diff --git a/src/contributors/Contributors.kt b/src/contributors/Contributors.kt index 4bea4c3..03637a9 100644 --- a/src/contributors/Contributors.kt +++ b/src/contributors/Contributors.kt @@ -20,7 +20,7 @@ enum class Variant { CHANNELS // Request7Channels } -interface Contributors: CoroutineScope { +interface Contributors : CoroutineScope { val job: Job @@ -58,6 +58,7 @@ interface Contributors: CoroutineScope { val users = loadContributorsBlocking(service, req) updateResults(users, startTime) } + BACKGROUND -> { // Blocking a background thread loadContributorsBackground(service, req) { users -> SwingUtilities.invokeLater { @@ -65,6 +66,7 @@ interface Contributors: CoroutineScope { } } } + CALLBACKS -> { // Using callbacks loadContributorsCallbacks(service, req) { users -> SwingUtilities.invokeLater { @@ -72,24 +74,30 @@ interface Contributors: CoroutineScope { } } } + SUSPEND -> { // Using coroutines launch { val users = loadContributorsSuspend(service, req) updateResults(users, startTime) }.setUpCancellation() } + CONCURRENT -> { // Performing requests concurrently - launch { + launch(Dispatchers.Default) { val users = loadContributorsConcurrent(service, req) - updateResults(users, startTime) + withContext(Dispatchers.Main) { + updateResults(users, startTime) + } }.setUpCancellation() } + NOT_CANCELLABLE -> { // Performing requests in a non-cancellable way launch { val users = loadContributorsNotCancellable(service, req) updateResults(users, startTime) }.setUpCancellation() } + PROGRESS -> { // Showing progress launch(Dispatchers.Default) { loadContributorsProgress(service, req) { users, completed -> @@ -99,6 +107,7 @@ interface Contributors: CoroutineScope { } }.setUpCancellation() } + CHANNELS -> { // Performing requests concurrently and showing progress launch(Dispatchers.Default) { loadContributorsChannels(service, req) { users, completed -> @@ -178,8 +187,7 @@ interface Contributors: CoroutineScope { val params = getParams() if (params.username.isEmpty() && params.password.isEmpty()) { removeStoredParams() - } - else { + } else { saveParams(params) } } diff --git a/src/contributors/GitHubService.kt b/src/contributors/GitHubService.kt index 3dc8b7c..f4956f7 100644 --- a/src/contributors/GitHubService.kt +++ b/src/contributors/GitHubService.kt @@ -6,25 +6,24 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient -import retrofit2.Call import retrofit2.Response import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.http.GET import retrofit2.http.Path -import java.util.Base64 +import java.util.* interface GitHubService { @GET("orgs/{org}/repos?per_page=100") - fun getOrgReposCall( + suspend fun getOrgReposCall( @Path("org") org: String - ): Call> + ): Response> @GET("repos/{owner}/{repo}/contributors?per_page=100") - fun getRepoContributorsCall( + suspend fun getRepoContributorsCall( @Path("owner") owner: String, @Path("repo") repo: String - ): Call> + ): Response> } @Serializable @@ -36,7 +35,7 @@ data class Repo( @Serializable data class User( val login: String, - val contributions: Int + var contributions: Int ) @Serializable diff --git a/src/tasks/Aggregation.kt b/src/tasks/Aggregation.kt index f2d6fa7..6af1afd 100644 --- a/src/tasks/Aggregation.kt +++ b/src/tasks/Aggregation.kt @@ -14,5 +14,10 @@ TODO: Write aggregation code. The corresponding test can be found in test/tasks/AggregationKtTest.kt. You can use 'Navigate | Test' menu action (note the shortcut) to navigate to the test. */ -fun List.aggregate(): List = - this \ No newline at end of file +fun List.aggregate(): List { + return this + .groupBy { user -> user.login } + .map { (_, users) -> + users.first().copy(contributions = users.sumOf { user -> user.contributions }) + }.sortedByDescending { user -> user.contributions } +} diff --git a/src/tasks/Request1Blocking.kt b/src/tasks/Request1Blocking.kt index 346c149..893bfcf 100644 --- a/src/tasks/Request1Blocking.kt +++ b/src/tasks/Request1Blocking.kt @@ -1,24 +1,27 @@ package tasks -import contributors.* +import contributors.GitHubService +import contributors.RequestData +import contributors.User import retrofit2.Response -fun loadContributorsBlocking(service: GitHubService, req: RequestData) : List { - val repos = service - .getOrgReposCall(req.org) - .execute() // Executes request and blocks the current thread - .also { logRepos(req, it) } - .body() ?: emptyList() - - return repos.flatMap { repo -> - service - .getRepoContributorsCall(req.org, repo.name) - .execute() // Executes request and blocks the current thread - .also { logUsers(repo, it) } - .bodyList() - }.aggregate() +fun loadContributorsBlocking(service: GitHubService, req: RequestData): List { +// val repos = service +// .getOrgReposCall(req.org) +// .execute() // Executes request and blocks the current thread +// .also { logRepos(req, it) } +// .bodyList() +// +// return repos.flatMap { repo -> +// service +// .getRepoContributorsCall(req.org, repo.name) +// .execute() // Executes request and blocks the current thread +// .also { logUsers(repo, it) } +// .bodyList() +// }.aggregate() + return emptyList() } fun Response>.bodyList(): List { return body() ?: emptyList() -} \ No newline at end of file +} diff --git a/src/tasks/Request2Background.kt b/src/tasks/Request2Background.kt index 0ccfaf4..b490780 100644 --- a/src/tasks/Request2Background.kt +++ b/src/tasks/Request2Background.kt @@ -7,6 +7,6 @@ import kotlin.concurrent.thread fun loadContributorsBackground(service: GitHubService, req: RequestData, updateResults: (List) -> Unit) { thread { - loadContributorsBlocking(service, req) + updateResults(loadContributorsBlocking(service, req)) } -} \ No newline at end of file +} diff --git a/src/tasks/Request3Callbacks.kt b/src/tasks/Request3Callbacks.kt index 392c57a..7988470 100644 --- a/src/tasks/Request3Callbacks.kt +++ b/src/tasks/Request3Callbacks.kt @@ -1,27 +1,30 @@ package tasks -import contributors.* +import contributors.GitHubService +import contributors.RequestData +import contributors.User +import contributors.log import retrofit2.Call import retrofit2.Callback import retrofit2.Response -import java.util.* -import java.util.concurrent.atomic.AtomicInteger fun loadContributorsCallbacks(service: GitHubService, req: RequestData, updateResults: (List) -> Unit) { - service.getOrgReposCall(req.org).onResponse { responseRepos -> - logRepos(req, responseRepos) - val repos = responseRepos.bodyList() - val allUsers = mutableListOf() - for (repo in repos) { - service.getRepoContributorsCall(req.org, repo.name).onResponse { responseUsers -> - logUsers(repo, responseUsers) - val users = responseUsers.bodyList() - allUsers += users - } - } - // TODO: Why this code doesn't work? How to fix that? - updateResults(allUsers.aggregate()) - } +// service.getOrgReposCall(req.org).onResponse { responseRepos -> +// logRepos(req, responseRepos) +// val repos = responseRepos.bodyList() +// val allUsers = Collections.synchronizedList(mutableListOf()) +// val countDownLatch = CountDownLatch(repos.size) +// for (repo in repos) { +// service.getRepoContributorsCall(req.org, repo.name).onResponse { responseUsers -> +// logUsers(repo, responseUsers) +// val users = responseUsers.bodyList() +// allUsers += users +// countDownLatch.countDown() +// } +// } +// countDownLatch.await() +// updateResults(allUsers.aggregate()) +// } } inline fun Call.onResponse(crossinline callback: (Response) -> Unit) { diff --git a/src/tasks/Request4Suspend.kt b/src/tasks/Request4Suspend.kt index 37949e7..4cd6ba0 100644 --- a/src/tasks/Request4Suspend.kt +++ b/src/tasks/Request4Suspend.kt @@ -3,5 +3,14 @@ package tasks import contributors.* suspend fun loadContributorsSuspend(service: GitHubService, req: RequestData): List { - TODO() -} \ No newline at end of file + val repos = service + .getOrgReposCall(req.org) + .also { logRepos(req, it) } + .bodyList() + + return repos.flatMap { repo -> + service.getRepoContributorsCall(req.org, repo.name) + .also { logUsers(repo, it) } + .bodyList() + }.aggregate() +} diff --git a/src/tasks/Request5Concurrent.kt b/src/tasks/Request5Concurrent.kt index 03ab317..bd3c889 100644 --- a/src/tasks/Request5Concurrent.kt +++ b/src/tasks/Request5Concurrent.kt @@ -1,8 +1,25 @@ package tasks import contributors.* -import kotlinx.coroutines.* +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope suspend fun loadContributorsConcurrent(service: GitHubService, req: RequestData): List = coroutineScope { - TODO() -} \ No newline at end of file + val repos = service + .getOrgReposCall(req.org) + .also { logRepos(req, it) } + .bodyList() + + val deferredListOfUsers = repos.map { repo -> + async { + log("starting loading for ${repo.name}") + service.getRepoContributorsCall(req.org, repo.name) + .also { logUsers(repo, it) } + .bodyList() + } + } + + val list = deferredListOfUsers.awaitAll() + list.flatten().aggregate() +}