From c6da312550daa8e78e2ae8c1e89a2d3d16516121 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Thu, 9 Nov 2017 00:31:25 +0300 Subject: [PATCH 1/7] wip: add result message, edit logging --- src/main/kotlin/app/api/ResultCodes.kt | 4 ++++ src/main/kotlin/app/hashers/RepoHasher.kt | 4 ++-- src/main/kotlin/app/model/Result.kt | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/app/api/ResultCodes.kt create mode 100644 src/main/kotlin/app/model/Result.kt diff --git a/src/main/kotlin/app/api/ResultCodes.kt b/src/main/kotlin/app/api/ResultCodes.kt new file mode 100644 index 00000000..1e847b09 --- /dev/null +++ b/src/main/kotlin/app/api/ResultCodes.kt @@ -0,0 +1,4 @@ +package app.api; + +public class ResultCodes { +} diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index 7197e297..becbd555 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -88,9 +88,9 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, throw HashingException(errors) } - println("Hashing $localRepo successfully finished.") + println("Hashing $localRepo complete finished.") Logger.info(Logger.Events.HASHING_REPO_SUCCESS) - { "Hashing repo succesfully" } + { "Hashing repo completed" } } finally { closeGit(git) diff --git a/src/main/kotlin/app/model/Result.kt b/src/main/kotlin/app/model/Result.kt new file mode 100644 index 00000000..d4037fd2 --- /dev/null +++ b/src/main/kotlin/app/model/Result.kt @@ -0,0 +1,2 @@ +package app.model + From 3a0e8c5ed170e71e5c142c26564450596def2cc4 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Thu, 9 Nov 2017 00:32:07 +0300 Subject: [PATCH 2/7] feat: limit max num of commits sent in one request --- src/main/kotlin/app/hashers/CommitHasher.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/app/hashers/CommitHasher.kt b/src/main/kotlin/app/hashers/CommitHasher.kt index dd40535b..ed92d1c5 100644 --- a/src/main/kotlin/app/hashers/CommitHasher.kt +++ b/src/main/kotlin/app/hashers/CommitHasher.kt @@ -53,7 +53,10 @@ class CommitHasher(private val serverRepo: Repo = Repo(), commit } - .buffer(20, TimeUnit.SECONDS) // Group ready commits by time. + // Group ready commits by time and count. Max payload 10 mb, + // one commit with stats takes around 1 kb, so pack by max 1000 + // with 10x margin of safety. + .buffer(20, TimeUnit.SECONDS, 1000) .subscribe({ commitsBundle -> // OnNext. postCommitsToServer(commitsBundle) // Send ready commits. }, onError) From 1bcff3ba0b95c73acdf059e1e1b215f378743a8d Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Thu, 9 Nov 2017 00:38:08 +0300 Subject: [PATCH 3/7] chore: fix if --- src/main/kotlin/app/hashers/FactHasher.kt | 2 +- src/main/kotlin/app/model/DiffContent.kt | 3 +++ src/main/kotlin/app/model/Fact.kt | 3 +++ src/main/kotlin/app/model/FactGroup.kt | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/app/hashers/FactHasher.kt b/src/main/kotlin/app/hashers/FactHasher.kt index 4d9a3c58..f8fb1584 100644 --- a/src/main/kotlin/app/hashers/FactHasher.kt +++ b/src/main/kotlin/app/hashers/FactHasher.kt @@ -82,7 +82,7 @@ class FactHasher(private val serverRepo: Repo = Repo(), fsRepoDateStart[email] = timestamp // RepoDateEnd. - if ((fsRepoDateEnd[email] ?: -1) == -1L) { + if (fsRepoDateEnd[email] == null) { fsRepoDateEnd[email] = timestamp } diff --git a/src/main/kotlin/app/model/DiffContent.kt b/src/main/kotlin/app/model/DiffContent.kt index 82cb7d1e..212eb978 100644 --- a/src/main/kotlin/app/model/DiffContent.kt +++ b/src/main/kotlin/app/model/DiffContent.kt @@ -1,3 +1,6 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + package app.model class DiffContent( diff --git a/src/main/kotlin/app/model/Fact.kt b/src/main/kotlin/app/model/Fact.kt index 91daf5a8..e137f1d9 100644 --- a/src/main/kotlin/app/model/Fact.kt +++ b/src/main/kotlin/app/model/Fact.kt @@ -1,3 +1,6 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + package app.model import app.Protos diff --git a/src/main/kotlin/app/model/FactGroup.kt b/src/main/kotlin/app/model/FactGroup.kt index 9c00871f..681196d1 100644 --- a/src/main/kotlin/app/model/FactGroup.kt +++ b/src/main/kotlin/app/model/FactGroup.kt @@ -1,3 +1,6 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + package app.model import app.Protos From d238bbbd78a1b2eab5e5c20ee54ef45e27836dc4 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Thu, 9 Nov 2017 00:38:20 +0300 Subject: [PATCH 4/7] wip: result message --- src/main/kotlin/app/api/ResultCodes.kt | 9 +++++-- src/main/kotlin/app/model/Result.kt | 35 +++++++++++++++++++++++++- src/main/proto/sourcerer.proto | 6 +++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/app/api/ResultCodes.kt b/src/main/kotlin/app/api/ResultCodes.kt index 1e847b09..0eff37b4 100644 --- a/src/main/kotlin/app/api/ResultCodes.kt +++ b/src/main/kotlin/app/api/ResultCodes.kt @@ -1,4 +1,9 @@ -package app.api; +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) -public class ResultCodes { +package app.api + +object ResultCodes { + //ok + //old version } diff --git a/src/main/kotlin/app/model/Result.kt b/src/main/kotlin/app/model/Result.kt index d4037fd2..fb1b7f76 100644 --- a/src/main/kotlin/app/model/Result.kt +++ b/src/main/kotlin/app/model/Result.kt @@ -1,2 +1,35 @@ -package app.model +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) +package app.model + +import app.Protos +import com.google.protobuf.InvalidProtocolBufferException +import java.security.InvalidParameterException + +data class Result( + var code: Int = 0, + var message: String = "" +) { + @Throws(InvalidParameterException::class) + constructor(proto: Protos.Result) : this() { + code = proto.code + message = proto.message + } + + @Throws(InvalidProtocolBufferException::class) + constructor(bytes: ByteArray) : this(Protos.Result.parseFrom(bytes)) + + constructor(serialized: String) : this(serialized.toByteArray()) + + fun getProto(): Protos.Result { + return Protos.Result.newBuilder() + .setCode(code) + .setMessage(message) + .build() + } + + fun serialize(): ByteArray { + return getProto().toByteArray() + } +} diff --git a/src/main/proto/sourcerer.proto b/src/main/proto/sourcerer.proto index efa1ca90..4015b41c 100644 --- a/src/main/proto/sourcerer.proto +++ b/src/main/proto/sourcerer.proto @@ -98,3 +98,9 @@ message Repo { // starts after last commit from the overlap. repeated Commit commits = 5; } + +// Results from server. +message Result { + uint32 code = 1; + string message = 2; +} From 7c0549df7de56276a61948900c3b1d80ce6cf396 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Thu, 9 Nov 2017 01:08:14 +0300 Subject: [PATCH 5/7] feat: restrict out-dated versions --- src/main/kotlin/app/api/Api.kt | 7 ++++++- src/main/kotlin/app/api/MockApi.kt | 5 ++++- src/main/kotlin/app/api/ResultCodes.kt | 9 --------- src/main/kotlin/app/api/ServerApi.kt | 6 ++++-- src/main/kotlin/app/ui/AuthState.kt | 17 +++++++++++------ 5 files changed, 25 insertions(+), 19 deletions(-) delete mode 100644 src/main/kotlin/app/api/ResultCodes.kt diff --git a/src/main/kotlin/app/api/Api.kt b/src/main/kotlin/app/api/Api.kt index 5b58a2e5..8794eb52 100644 --- a/src/main/kotlin/app/api/Api.kt +++ b/src/main/kotlin/app/api/Api.kt @@ -6,10 +6,15 @@ package app.api import app.model.Commit import app.model.Fact import app.model.Repo +import app.model.Result import app.model.User interface Api { - fun authorize() + companion object { + val OK = 0 + val OUT_OF_DATE = 1 + } + fun authorize(): Result fun getUser(): User fun getRepo(repoRehash: String): Repo fun postRepo(repo: Repo) diff --git a/src/main/kotlin/app/api/MockApi.kt b/src/main/kotlin/app/api/MockApi.kt index fd4bb8cb..5cf0697b 100644 --- a/src/main/kotlin/app/api/MockApi.kt +++ b/src/main/kotlin/app/api/MockApi.kt @@ -7,9 +7,11 @@ import app.Logger import app.model.Commit import app.model.Repo import app.model.Fact +import app.model.Result import app.model.User class MockApi( // GET requests. + var mockAuthResult: Result = Result(), var mockUser: User = User(), var mockRepo: Repo = Repo()) : Api { // POST requests. @@ -21,8 +23,9 @@ class MockApi( // GET requests. // DELETE requests. var receivedDeletedCommits: MutableList = mutableListOf() - override fun authorize() { + override fun authorize(): Result { Logger.debug { "MockApi: authorize request" } + return mockAuthResult } override fun getUser(): User { diff --git a/src/main/kotlin/app/api/ResultCodes.kt b/src/main/kotlin/app/api/ResultCodes.kt deleted file mode 100644 index 0eff37b4..00000000 --- a/src/main/kotlin/app/api/ResultCodes.kt +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2017 Sourcerer Inc. All Rights Reserved. -// Author: Anatoly Kislov (anatoly@sourcerer.io) - -package app.api - -object ResultCodes { - //ok - //old version -} diff --git a/src/main/kotlin/app/api/ServerApi.kt b/src/main/kotlin/app/api/ServerApi.kt index 7053d3b3..a3ad565d 100644 --- a/src/main/kotlin/app/api/ServerApi.kt +++ b/src/main/kotlin/app/api/ServerApi.kt @@ -11,6 +11,7 @@ import app.model.CommitGroup import app.model.Fact import app.model.FactGroup import app.model.Repo +import app.model.Result import app.model.User import app.utils.RequestException import com.github.kittinunf.fuel.core.FuelManager @@ -134,8 +135,9 @@ class ServerApi (private val configurator: Configurator) : Api { return Pair(HEADER_CONTENT_TYPE, HEADER_CONTENT_TYPE_PROTO) } - override fun authorize() { - return makeRequest(createRequestGetToken(), "getToken", {}) + override fun authorize(): Result { + return makeRequest(createRequestGetToken(), "getToken", + { body -> Result(body) }) } override fun getUser(): User { diff --git a/src/main/kotlin/app/ui/AuthState.kt b/src/main/kotlin/app/ui/AuthState.kt index 11446e6e..67cd9019 100644 --- a/src/main/kotlin/app/ui/AuthState.kt +++ b/src/main/kotlin/app/ui/AuthState.kt @@ -3,7 +3,6 @@ package app.ui -import app.Analytics import app.BuildConfig import app.Logger import app.api.Api @@ -20,7 +19,7 @@ class AuthState constructor(private val context: Context, : ConsoleState { var username = "" var password = "" - var connectionError = false + var retry = true override fun doAction() { if (!configurator.isValidCredentials()) { @@ -28,13 +27,13 @@ class AuthState constructor(private val context: Context, getPassword() } - while (!tryAuth() && !connectionError) { + while (!tryAuth() && retry) { getPassword() } } override fun next() { - if (!connectionError) { + if (!retry) { context.changeState(ListRepoState(context, api, configurator)) } else { context.changeState(CloseState()) @@ -68,7 +67,13 @@ class AuthState constructor(private val context: Context, fun tryAuth(): Boolean { try { println("Authenticating...") - api.authorize() + val result = api.authorize() + if (result.code == Api.OUT_OF_DATE) { + println("App is out of date. Please get new version at " + + "https://sourcerer.io") + retry = false + return false + } val user = api.getUser() configurator.setRepos(user.repos) @@ -89,8 +94,8 @@ class AuthState constructor(private val context: Context, println("Authentication error. Try again.") } } else { - connectionError = true println("Connection problems. Try again later.") + retry = false } } return false From 41e32e2a1c6ce0c720dfcf8da2455242c86d9196 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Fri, 10 Nov 2017 03:47:16 +0300 Subject: [PATCH 6/7] feat: add result to api, check app version on server --- src/main/kotlin/app/api/Api.kt | 17 ++--- src/main/kotlin/app/api/ApiError.kt | 75 +++++++++++++++++++ src/main/kotlin/app/api/MockApi.kt | 26 ++++--- src/main/kotlin/app/api/Result.kt | 19 +++++ src/main/kotlin/app/api/ServerApi.kt | 48 ++++++------ src/main/kotlin/app/hashers/CodeLongevity.kt | 3 +- src/main/kotlin/app/hashers/CommitHasher.kt | 4 +- src/main/kotlin/app/hashers/FactHasher.kt | 4 +- src/main/kotlin/app/hashers/RepoHasher.kt | 4 +- .../kotlin/app/model/{Result.kt => Error.kt} | 10 +-- src/main/kotlin/app/model/Errors.kt | 32 ++++++++ src/main/kotlin/app/ui/AuthState.kt | 22 ++++-- src/main/proto/sourcerer.proto | 8 +- .../test/tests/hashers/FactHasherTest.kt | 1 - 14 files changed, 206 insertions(+), 67 deletions(-) create mode 100644 src/main/kotlin/app/api/ApiError.kt create mode 100644 src/main/kotlin/app/api/Result.kt rename src/main/kotlin/app/model/{Result.kt => Error.kt} (76%) create mode 100644 src/main/kotlin/app/model/Errors.kt diff --git a/src/main/kotlin/app/api/Api.kt b/src/main/kotlin/app/api/Api.kt index 8794eb52..a2a5658e 100644 --- a/src/main/kotlin/app/api/Api.kt +++ b/src/main/kotlin/app/api/Api.kt @@ -6,19 +6,18 @@ package app.api import app.model.Commit import app.model.Fact import app.model.Repo -import app.model.Result import app.model.User interface Api { companion object { - val OK = 0 val OUT_OF_DATE = 1 } - fun authorize(): Result - fun getUser(): User - fun getRepo(repoRehash: String): Repo - fun postRepo(repo: Repo) - fun postCommits(commitsList: List) - fun deleteCommits(commitsList: List) - fun postFacts(factsList: List) + + fun authorize(): Result + fun getUser(): Result + fun getRepo(repoRehash: String): Result + fun postRepo(repo: Repo): Result + fun postCommits(commitsList: List): Result + fun deleteCommits(commitsList: List): Result + fun postFacts(factsList: List): Result } diff --git a/src/main/kotlin/app/api/ApiError.kt b/src/main/kotlin/app/api/ApiError.kt new file mode 100644 index 00000000..981f1d5b --- /dev/null +++ b/src/main/kotlin/app/api/ApiError.kt @@ -0,0 +1,75 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + +package app.api + +import app.Logger +import app.model.Error +import app.model.Errors +import com.github.kittinunf.fuel.core.FuelError +import com.google.protobuf.InvalidProtocolBufferException +import java.nio.charset.Charset +import java.security.InvalidParameterException + +class ApiError(exception: Exception) : Exception(exception.message) { + companion object { + private val AUTH_ERROR_CODES = listOf(401, 403) + } + + // Response content. + var httpStatusCode: Int = 0 + var httpResponseMessage: String = "" + var httpBodyMessage: String = "" + + // Server errors from response. + var serverErrors = listOf() + + // Type of errors. + var isParseError = false + var isAuthError: Boolean = false + get() = AUTH_ERROR_CODES.contains(httpStatusCode) + + constructor(fuelError: FuelError) : this(fuelError as Exception) { + httpStatusCode = fuelError.response.httpStatusCode + httpResponseMessage = fuelError.response.httpResponseMessage + if (fuelError.response.httpResponseHeaders["Content-Type"] + ?.contains("application/octet-stream") == true) { + try { + serverErrors = Errors(fuelError.response.data).errors + } catch (e: Exception) { + Logger.error(e, "Error while parsing errors from server") + } + } else { + httpBodyMessage = fuelError.response.data + .toString(Charset.defaultCharset()) + } + } + + constructor(parseException: InvalidProtocolBufferException) : + this(parseException as Exception) { + isParseError = true + } + + constructor(parseException: InvalidParameterException) : + this(parseException as Exception) { + isParseError = true + } + + fun isWithServerCode(serverErrorCode: Int): Boolean { + return serverErrors.find { error -> + error.code == serverErrorCode } != null + } +} + +fun ApiError?.ifNotNullThrow() { + if (this != null) { + throw this + } +} + +fun ApiError?.isWithServerCode(serverErrorCode: Int): Boolean { + if (this != null) { + return this.isWithServerCode(serverErrorCode) + } + return false +} diff --git a/src/main/kotlin/app/api/MockApi.kt b/src/main/kotlin/app/api/MockApi.kt index 5cf0697b..c08688ec 100644 --- a/src/main/kotlin/app/api/MockApi.kt +++ b/src/main/kotlin/app/api/MockApi.kt @@ -7,11 +7,9 @@ import app.Logger import app.model.Commit import app.model.Repo import app.model.Fact -import app.model.Result import app.model.User class MockApi( // GET requests. - var mockAuthResult: Result = Result(), var mockUser: User = User(), var mockRepo: Repo = Repo()) : Api { // POST requests. @@ -23,41 +21,45 @@ class MockApi( // GET requests. // DELETE requests. var receivedDeletedCommits: MutableList = mutableListOf() - override fun authorize(): Result { + override fun authorize(): Result { Logger.debug { "MockApi: authorize request" } - return mockAuthResult + return Result() } - override fun getUser(): User { + override fun getUser(): Result { Logger.debug { "MockApi: getUser request" } - return mockUser + return Result(mockUser) } - override fun getRepo(repoRehash: String): Repo { + override fun getRepo(repoRehash: String): Result { Logger.debug { "MockApi: getRepo request" } - return mockRepo + return Result(mockRepo) } - override fun postRepo(repo: Repo) { + override fun postRepo(repo: Repo): Result { Logger.debug { "MockApi: postRepo request ($repo)" } receivedRepos.add(repo) + return Result() } - override fun postCommits(commitsList: List) { + override fun postCommits(commitsList: List): Result { Logger.debug { "MockApi: postCommits request (${commitsList.size} commits)" } receivedAddedCommits.addAll(commitsList) + return Result() } - override fun deleteCommits(commitsList: List) { + override fun deleteCommits(commitsList: List): Result { Logger.debug { "MockApi: deleteCommits request (${commitsList.size} commits)" } receivedDeletedCommits.addAll(commitsList) + return Result() } - override fun postFacts(factsList: List) { + override fun postFacts(factsList: List): Result { Logger.debug { "MockApi: postStats request (${factsList.size} stats)" } receivedFacts.addAll(factsList) + return Result() } } diff --git a/src/main/kotlin/app/api/Result.kt b/src/main/kotlin/app/api/Result.kt new file mode 100644 index 00000000..9a56a26a --- /dev/null +++ b/src/main/kotlin/app/api/Result.kt @@ -0,0 +1,19 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + +package app.api + +data class Result (val data: T? = null, val error: ApiError? = null) { + fun getOrThrow(): T { + if (error == null) { + return data!! + } + throw error + } + + fun onErrorThrow() { + if (error != null) { + throw error + } + } +} diff --git a/src/main/kotlin/app/api/ServerApi.kt b/src/main/kotlin/app/api/ServerApi.kt index a3ad565d..f475c6a4 100644 --- a/src/main/kotlin/app/api/ServerApi.kt +++ b/src/main/kotlin/app/api/ServerApi.kt @@ -11,9 +11,7 @@ import app.model.CommitGroup import app.model.Fact import app.model.FactGroup import app.model.Repo -import app.model.Result import app.model.User -import app.utils.RequestException import com.github.kittinunf.fuel.core.FuelManager import com.github.kittinunf.fuel.core.Method import com.github.kittinunf.fuel.core.Request @@ -109,22 +107,27 @@ class ServerApi (private val configurator: Configurator) : Api { private fun makeRequest(request: Request, requestName: String, - parser: (ByteArray) -> T): T { + parser: (ByteArray) -> T): Result { + var error: ApiError? = null + var data: T? = null + try { Logger.debug { "Request $requestName initialized" } val (_, res, result) = request.responseString() val (_, e) = result if (e == null) { Logger.debug { "Request $requestName success" } - return parser(res.data) + data = parser(res.data) } else { - throw RequestException(e) + error = ApiError(e) } } catch (e: InvalidProtocolBufferException) { - throw RequestException(e) + error = ApiError(e) } catch (e: InvalidParameterException) { - throw RequestException(e) + error = ApiError(e) } + + return Result(data, error) } private fun getVersionCodeHeader(): Pair { @@ -135,17 +138,16 @@ class ServerApi (private val configurator: Configurator) : Api { return Pair(HEADER_CONTENT_TYPE, HEADER_CONTENT_TYPE_PROTO) } - override fun authorize(): Result { - return makeRequest(createRequestGetToken(), "getToken", - { body -> Result(body) }) + override fun authorize(): Result { + return makeRequest(createRequestGetToken(), "getToken", {}) } - override fun getUser(): User { + override fun getUser(): Result { return makeRequest(createRequestGetUser(), "getUser", { body -> User(body) }) } - override fun getRepo(repoRehash: String): Repo { + override fun getRepo(repoRehash: String): Result { if (repoRehash.isBlank()) { throw IllegalArgumentException() } @@ -154,25 +156,25 @@ class ServerApi (private val configurator: Configurator) : Api { { body -> Repo(body) }) } - override fun postRepo(repo: Repo) { - makeRequest(createRequestPostRepo(repo), - "postRepo", {}) + override fun postRepo(repo: Repo): Result { + return makeRequest(createRequestPostRepo(repo), + "postRepo", {}) } - override fun postCommits(commitsList: List) { + override fun postCommits(commitsList: List): Result { val commits = CommitGroup(commitsList) - makeRequest(createRequestPostCommits(commits), - "postCommits", {}) + return makeRequest(createRequestPostCommits(commits), + "postCommits", {}) } - override fun deleteCommits(commitsList: List) { + override fun deleteCommits(commitsList: List): Result { val commits = CommitGroup(commitsList) - makeRequest(createRequestDeleteCommits(commits), - "deleteCommits", {}) + return makeRequest(createRequestDeleteCommits(commits), + "deleteCommits", {}) } - override fun postFacts(factsList: List) { + override fun postFacts(factsList: List): Result { val facts = FactGroup(factsList) - makeRequest(createRequestPostFacts(facts), "postFacts", {}) + return makeRequest(createRequestPostFacts(facts), "postFacts", {}) } } diff --git a/src/main/kotlin/app/hashers/CodeLongevity.kt b/src/main/kotlin/app/hashers/CodeLongevity.kt index bddfe087..e28c7166 100644 --- a/src/main/kotlin/app/hashers/CodeLongevity.kt +++ b/src/main/kotlin/app/hashers/CodeLongevity.kt @@ -22,7 +22,6 @@ import org.eclipse.jgit.revwalk.RevWalk import org.eclipse.jgit.treewalk.TreeWalk import org.eclipse.jgit.util.io.DisabledOutputStream -import java.io.InputStream import java.io.File import java.io.FileInputStream import java.io.FileNotFoundException @@ -211,7 +210,7 @@ class CodeLongevity(private val serverRepo: Repo, } if (stats.size > 0) { - api.postFacts(stats) + api.postFacts(stats).onErrorThrow() Logger.info { "Sent ${stats.size} facts to server" } } } diff --git a/src/main/kotlin/app/hashers/CommitHasher.kt b/src/main/kotlin/app/hashers/CommitHasher.kt index ed92d1c5..aae20917 100644 --- a/src/main/kotlin/app/hashers/CommitHasher.kt +++ b/src/main/kotlin/app/hashers/CommitHasher.kt @@ -73,14 +73,14 @@ class CommitHasher(private val serverRepo: Repo = Repo(), private fun postCommitsToServer(commits: List) { if (commits.isNotEmpty()) { - api.postCommits(commits) + api.postCommits(commits).onErrorThrow() Logger.info { "Sent ${commits.size} added commits to server" } } } private fun deleteCommitsOnServer(commits: List) { if (commits.isNotEmpty()) { - api.deleteCommits(commits) + api.deleteCommits(commits).onErrorThrow() Logger.info { "Sent ${commits.size} deleted commits to server" } } } diff --git a/src/main/kotlin/app/hashers/FactHasher.kt b/src/main/kotlin/app/hashers/FactHasher.kt index f8fb1584..41332ac0 100644 --- a/src/main/kotlin/app/hashers/FactHasher.kt +++ b/src/main/kotlin/app/hashers/FactHasher.kt @@ -82,7 +82,7 @@ class FactHasher(private val serverRepo: Repo = Repo(), fsRepoDateStart[email] = timestamp // RepoDateEnd. - if (fsRepoDateEnd[email] == null) { + if (fsRepoDateEnd[email]!! == -1L) { fsRepoDateEnd[email] = timestamp } @@ -137,7 +137,7 @@ class FactHasher(private val serverRepo: Repo = Repo(), private fun postFactsToServer(facts: List) { if (facts.isNotEmpty()) { - api.postFacts(facts) + api.postFacts(facts).onErrorThrow() Logger.info { "Sent ${facts.size} facts to server" } } } diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index becbd555..069a6aa1 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -116,7 +116,7 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, } private fun getRepoFromServer() { - val repo = api.getRepo(serverRepo.rehash) + val repo = api.getRepo(serverRepo.rehash).getOrThrow() serverRepo.commits = repo.commits Logger.info{ "Received repo from server with ${serverRepo.commits.size} commits" @@ -126,7 +126,7 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, private fun postRepoToServer() { serverRepo.commits = listOf() - api.postRepo(serverRepo) + api.postRepo(serverRepo).onErrorThrow() Logger.debug { serverRepo.toString() } } diff --git a/src/main/kotlin/app/model/Result.kt b/src/main/kotlin/app/model/Error.kt similarity index 76% rename from src/main/kotlin/app/model/Result.kt rename to src/main/kotlin/app/model/Error.kt index fb1b7f76..0baf8997 100644 --- a/src/main/kotlin/app/model/Result.kt +++ b/src/main/kotlin/app/model/Error.kt @@ -7,23 +7,23 @@ import app.Protos import com.google.protobuf.InvalidProtocolBufferException import java.security.InvalidParameterException -data class Result( +data class Error( var code: Int = 0, var message: String = "" ) { @Throws(InvalidParameterException::class) - constructor(proto: Protos.Result) : this() { + constructor(proto: Protos.Error) : this() { code = proto.code message = proto.message } @Throws(InvalidProtocolBufferException::class) - constructor(bytes: ByteArray) : this(Protos.Result.parseFrom(bytes)) + constructor(bytes: ByteArray) : this(Protos.Error.parseFrom(bytes)) constructor(serialized: String) : this(serialized.toByteArray()) - fun getProto(): Protos.Result { - return Protos.Result.newBuilder() + fun getProto(): Protos.Error { + return Protos.Error.newBuilder() .setCode(code) .setMessage(message) .build() diff --git a/src/main/kotlin/app/model/Errors.kt b/src/main/kotlin/app/model/Errors.kt new file mode 100644 index 00000000..59b9625a --- /dev/null +++ b/src/main/kotlin/app/model/Errors.kt @@ -0,0 +1,32 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + +package app.model + +import app.Protos +import com.google.protobuf.InvalidProtocolBufferException +import java.security.InvalidParameterException + +data class Errors ( + var errors: List = listOf() +) { + @Throws(InvalidParameterException::class) + constructor(proto: Protos.Errors) : this() { + errors = proto.errorsList.map { error -> Error(error) } + } + + @Throws(InvalidProtocolBufferException::class) + constructor(bytes: ByteArray) : this(Protos.Errors.parseFrom(bytes)) + + constructor(serialized: String) : this(serialized.toByteArray()) + + fun getProto(): Protos.Errors { + return Protos.Errors.newBuilder() + .addAllErrors(errors.map { error -> error.getProto() }) + .build() + } + + fun serialize(): ByteArray { + return getProto().toByteArray() + } +} diff --git a/src/main/kotlin/app/ui/AuthState.kt b/src/main/kotlin/app/ui/AuthState.kt index 67cd9019..43d8f216 100644 --- a/src/main/kotlin/app/ui/AuthState.kt +++ b/src/main/kotlin/app/ui/AuthState.kt @@ -8,7 +8,9 @@ import app.Logger import app.api.Api import app.config.Configurator import app.utils.PasswordHelper -import app.utils.RequestException +import app.api.ApiError +import app.api.ifNotNullThrow +import app.api.isWithServerCode /** * Authorization console UI state. @@ -20,6 +22,7 @@ class AuthState constructor(private val context: Context, var username = "" var password = "" var retry = true + var authorised = false override fun doAction() { if (!configurator.isValidCredentials()) { @@ -27,13 +30,15 @@ class AuthState constructor(private val context: Context, getPassword() } - while (!tryAuth() && retry) { + authorised = tryAuth() + while (!authorised && retry) { getPassword() + authorised = tryAuth() } } override fun next() { - if (!retry) { + if (authorised) { context.changeState(ListRepoState(context, api, configurator)) } else { context.changeState(CloseState()) @@ -67,15 +72,17 @@ class AuthState constructor(private val context: Context, fun tryAuth(): Boolean { try { println("Authenticating...") - val result = api.authorize() - if (result.code == Api.OUT_OF_DATE) { + val (_, error) = api.authorize() + if (error.isWithServerCode(Api.OUT_OF_DATE)) { println("App is out of date. Please get new version at " + "https://sourcerer.io") retry = false return false } + // Other request errors should be processed by try/catch. + error.ifNotNullThrow() - val user = api.getUser() + val user = api.getUser().getOrThrow() configurator.setRepos(user.repos) println("You are successfully authenticated. Your profile page is " @@ -86,7 +93,7 @@ class AuthState constructor(private val context: Context, Logger.info(Logger.Events.AUTH) { "Auth success" } return true - } catch (e: RequestException) { + } catch (e: ApiError) { if (e.isAuthError) { if(e.httpBodyMessage.isNotBlank()) { println(e.httpBodyMessage) @@ -98,6 +105,7 @@ class AuthState constructor(private val context: Context, retry = false } } + return false } } diff --git a/src/main/proto/sourcerer.proto b/src/main/proto/sourcerer.proto index 4015b41c..f30a9c9a 100644 --- a/src/main/proto/sourcerer.proto +++ b/src/main/proto/sourcerer.proto @@ -99,8 +99,12 @@ message Repo { repeated Commit commits = 5; } -// Results from server. -message Result { +// Errors from server. +message Error { uint32 code = 1; string message = 2; } + +message Errors { + repeated Error errors = 1; +} diff --git a/src/test/kotlin/test/tests/hashers/FactHasherTest.kt b/src/test/kotlin/test/tests/hashers/FactHasherTest.kt index 33f51e42..f6302188 100644 --- a/src/test/kotlin/test/tests/hashers/FactHasherTest.kt +++ b/src/test/kotlin/test/tests/hashers/FactHasherTest.kt @@ -193,7 +193,6 @@ class FactHasherTest : Spek({ "2"))) } - afterGroup { testRepo.destroy() } From d192d5c2724d36b7caedfe38fb89ad0a9235a82a Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Fri, 10 Nov 2017 15:32:19 +0300 Subject: [PATCH 7/7] chore: fix typo --- src/main/kotlin/app/ui/AuthState.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/app/ui/AuthState.kt b/src/main/kotlin/app/ui/AuthState.kt index 43d8f216..66948e9b 100644 --- a/src/main/kotlin/app/ui/AuthState.kt +++ b/src/main/kotlin/app/ui/AuthState.kt @@ -22,7 +22,7 @@ class AuthState constructor(private val context: Context, var username = "" var password = "" var retry = true - var authorised = false + var authorized = false override fun doAction() { if (!configurator.isValidCredentials()) { @@ -30,15 +30,15 @@ class AuthState constructor(private val context: Context, getPassword() } - authorised = tryAuth() - while (!authorised && retry) { + authorized = tryAuth() + while (!authorized && retry) { getPassword() - authorised = tryAuth() + authorized = tryAuth() } } override fun next() { - if (authorised) { + if (authorized) { context.changeState(ListRepoState(context, api, configurator)) } else { context.changeState(CloseState())