Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions src/main/kotlin/app/api/Api.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import app.model.Repo
import app.model.User

interface Api {
fun authorize()
fun getUser(): User
fun getRepo(repoRehash: String): Repo
fun postRepo(repo: Repo)
fun postCommits(commitsList: List<Commit>)
fun deleteCommits(commitsList: List<Commit>)
fun postFacts(factsList: List<Fact>)
companion object {
val OUT_OF_DATE = 1
}

fun authorize(): Result<Unit>
fun getUser(): Result<User>
fun getRepo(repoRehash: String): Result<Repo>
fun postRepo(repo: Repo): Result<Unit>
fun postCommits(commitsList: List<Commit>): Result<Unit>
fun deleteCommits(commitsList: List<Commit>): Result<Unit>
fun postFacts(factsList: List<Fact>): Result<Unit>
}
75 changes: 75 additions & 0 deletions src/main/kotlin/app/api/ApiError.kt
Original file line number Diff line number Diff line change
@@ -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<Error>()

// 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
}
23 changes: 14 additions & 9 deletions src/main/kotlin/app/api/MockApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,45 @@ class MockApi( // GET requests.
// DELETE requests.
var receivedDeletedCommits: MutableList<Commit> = mutableListOf()

override fun authorize() {
override fun authorize(): Result<Unit> {
Logger.debug { "MockApi: authorize request" }
return Result()
}

override fun getUser(): User {
override fun getUser(): Result<User> {
Logger.debug { "MockApi: getUser request" }
return mockUser
return Result(mockUser)
}

override fun getRepo(repoRehash: String): Repo {
override fun getRepo(repoRehash: String): Result<Repo> {
Logger.debug { "MockApi: getRepo request" }
return mockRepo
return Result(mockRepo)
}

override fun postRepo(repo: Repo) {
override fun postRepo(repo: Repo): Result<Unit> {
Logger.debug { "MockApi: postRepo request ($repo)" }
receivedRepos.add(repo)
return Result()
}

override fun postCommits(commitsList: List<Commit>) {
override fun postCommits(commitsList: List<Commit>): Result<Unit> {
Logger.debug {
"MockApi: postCommits request (${commitsList.size} commits)"
}
receivedAddedCommits.addAll(commitsList)
return Result()
}

override fun deleteCommits(commitsList: List<Commit>) {
override fun deleteCommits(commitsList: List<Commit>): Result<Unit> {
Logger.debug {
"MockApi: deleteCommits request (${commitsList.size} commits)" }
receivedDeletedCommits.addAll(commitsList)
return Result()
}

override fun postFacts(factsList: List<Fact>) {
override fun postFacts(factsList: List<Fact>): Result<Unit> {
Logger.debug { "MockApi: postStats request (${factsList.size} stats)" }
receivedFacts.addAll(factsList)
return Result()
}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/app/api/Result.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2017 Sourcerer Inc. All Rights Reserved.
// Author: Anatoly Kislov (anatoly@sourcerer.io)

package app.api

data class Result<out T> (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
}
}
}
44 changes: 24 additions & 20 deletions src/main/kotlin/app/api/ServerApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import app.model.Fact
import app.model.FactGroup
import app.model.Repo
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
Expand Down Expand Up @@ -108,22 +107,27 @@ class ServerApi (private val configurator: Configurator) : Api {

private fun <T> makeRequest(request: Request,
requestName: String,
parser: (ByteArray) -> T): T {
parser: (ByteArray) -> T): Result<T> {
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<String, String> {
Expand All @@ -134,16 +138,16 @@ class ServerApi (private val configurator: Configurator) : Api {
return Pair(HEADER_CONTENT_TYPE, HEADER_CONTENT_TYPE_PROTO)
}

override fun authorize() {
override fun authorize(): Result<Unit> {
return makeRequest(createRequestGetToken(), "getToken", {})
}

override fun getUser(): User {
override fun getUser(): Result<User> {
return makeRequest(createRequestGetUser(), "getUser",
{ body -> User(body) })
}

override fun getRepo(repoRehash: String): Repo {
override fun getRepo(repoRehash: String): Result<Repo> {
if (repoRehash.isBlank()) {
throw IllegalArgumentException()
}
Expand All @@ -152,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<Unit> {
return makeRequest(createRequestPostRepo(repo),
"postRepo", {})
}

override fun postCommits(commitsList: List<Commit>) {
override fun postCommits(commitsList: List<Commit>): Result<Unit> {
val commits = CommitGroup(commitsList)
makeRequest(createRequestPostCommits(commits),
"postCommits", {})
return makeRequest(createRequestPostCommits(commits),
"postCommits", {})
}

override fun deleteCommits(commitsList: List<Commit>) {
override fun deleteCommits(commitsList: List<Commit>): Result<Unit> {
val commits = CommitGroup(commitsList)
makeRequest(createRequestDeleteCommits(commits),
"deleteCommits", {})
return makeRequest(createRequestDeleteCommits(commits),
"deleteCommits", {})
}

override fun postFacts(factsList: List<Fact>) {
override fun postFacts(factsList: List<Fact>): Result<Unit> {
val facts = FactGroup(factsList)
makeRequest(createRequestPostFacts(facts), "postFacts", {})
return makeRequest(createRequestPostFacts(facts), "postFacts", {})
}
}
3 changes: 1 addition & 2 deletions src/main/kotlin/app/hashers/CodeLongevity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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" }
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/main/kotlin/app/hashers/CommitHasher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -70,14 +73,14 @@ class CommitHasher(private val serverRepo: Repo = Repo(),

private fun postCommitsToServer(commits: List<Commit>) {
if (commits.isNotEmpty()) {
api.postCommits(commits)
api.postCommits(commits).onErrorThrow()
Logger.info { "Sent ${commits.size} added commits to server" }
}
}

private fun deleteCommitsOnServer(commits: List<Commit>) {
if (commits.isNotEmpty()) {
api.deleteCommits(commits)
api.deleteCommits(commits).onErrorThrow()
Logger.info { "Sent ${commits.size} deleted commits to server" }
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/app/hashers/FactHasher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class FactHasher(private val serverRepo: Repo = Repo(),
fsRepoDateStart[email] = timestamp

// RepoDateEnd.
if ((fsRepoDateEnd[email] ?: -1) == -1L) {
if (fsRepoDateEnd[email]!! == -1L) {
fsRepoDateEnd[email] = timestamp
}

Expand Down Expand Up @@ -137,7 +137,7 @@ class FactHasher(private val serverRepo: Repo = Repo(),

private fun postFactsToServer(facts: List<Fact>) {
if (facts.isNotEmpty()) {
api.postFacts(facts)
api.postFacts(facts).onErrorThrow()
Logger.info { "Sent ${facts.size} facts to server" }
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/app/hashers/RepoHasher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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"
Expand All @@ -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() }
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/app/model/DiffContent.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright 2017 Sourcerer Inc. All Rights Reserved.
// Author: Anatoly Kislov (anatoly@sourcerer.io)

package app.model

class DiffContent(
Expand Down
Loading