From dc9545570dc8ba0645dd6bf1d37ae13a4eb763ac Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 2 Feb 2020 22:57:15 -0500 Subject: [PATCH] Migrate extension list fetch to coroutine --- .../tachiyomi/data/updater/UpdaterService.kt | 4 +-- .../tachiyomi/extension/ExtensionManager.kt | 14 ++++---- .../extension/api/ExtensionGithubApi.kt | 27 +++++++-------- .../tachiyomi/network/OkHttpExtensions.kt | 34 ++++++++++++++++--- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterService.kt index 7de94fd306..ddce70db74 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterService.kt @@ -17,9 +17,7 @@ import uy.kohesive.injekt.injectLazy import java.io.File class UpdaterService : IntentService(UpdaterService::class.java.name) { - /** - * Network helper - */ + private val network: NetworkHelper by injectLazy() /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 6d6f671fb7..ea12b35d52 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -15,8 +15,6 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.util.system.launchNow import kotlinx.coroutines.async import rx.Observable -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -146,11 +144,13 @@ class ExtensionManager( * Finds the available extensions in the [api] and updates [availableExtensions]. */ fun findAvailableExtensions() { - api.findExtensions() - .onErrorReturn { emptyList() } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { availableExtensions = it } + launchNow { + availableExtensions = try { + api.findExtensions() + } catch (e: Exception) { + emptyList() + } + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index ec8201d6eb..8bf34cb960 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -13,12 +13,10 @@ import eu.kanade.tachiyomi.extension.model.LoadResult import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.network.asObservableSuccess import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.withContext +import eu.kanade.tachiyomi.network.await import okhttp3.Response -import rx.Observable import uy.kohesive.injekt.injectLazy import java.lang.Exception @@ -26,23 +24,18 @@ internal class ExtensionGithubApi { private val network: NetworkHelper by injectLazy() - private val client get() = network.client - private val gson: Gson by injectLazy() - private val repoUrl = "https://raw.githubusercontent.com/inorichi/tachiyomi-extensions/repo" + suspend fun findExtensions(): List { + val call = GET("$REPO_URL/index.json") - fun findExtensions(): Observable> { - val call = GET("$repoUrl/index.json") - - return client.newCall(call).asObservableSuccess() - .map(::parseResponse) + return parseResponse(network.client.newCall(call).await()) } suspend fun checkforUpdates(context: Context): List { return withContext(Dispatchers.IO) { - val call = GET("$repoUrl/index.json") - val response = client.newCall(call).execute() + val call = GET("$REPO_URL/index.json") + val response = network.client.newCall(call).await() if (response.isSuccessful) { val extensions = parseResponse(response) @@ -80,13 +73,17 @@ internal class ExtensionGithubApi { val versionName = element["version"].string val versionCode = element["code"].int val lang = element["lang"].string - val icon = "$repoUrl/icon/${apkName.replace(".apk", ".png")}" + val icon = "$REPO_URL/icon/${apkName.replace(".apk", ".png")}" Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon) } } fun getApkUrl(extension: Extension.Available): String { - return "$repoUrl/apk/${extension.apkName}" + return "$REPO_URL/apk/${extension.apkName}" + } + + companion object { + private const val REPO_URL = "https://raw.githubusercontent.com/inorichi/tachiyomi-extensions/repo" } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index 6f0bb5f08c..dc76ff0e7a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -1,13 +1,14 @@ package eu.kanade.tachiyomi.network -import okhttp3.Call -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response +import kotlinx.coroutines.suspendCancellableCoroutine +import okhttp3.* import rx.Observable import rx.Producer import rx.Subscription +import java.io.IOException import java.util.concurrent.atomic.AtomicBoolean +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException fun Call.asObservable(): Observable { return Observable.unsafeCreate { subscriber -> @@ -46,6 +47,31 @@ fun Call.asObservable(): Observable { } } +// Based on https://github.com/gildor/kotlin-coroutines-okhttp +suspend fun Call.await(): Response { + return suspendCancellableCoroutine { continuation -> + enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + continuation.resume(response) + } + + override fun onFailure(call: Call, e: IOException) { + // Don't bother with resuming the continuation if it is already cancelled. + if (continuation.isCancelled) return + continuation.resumeWithException(e) + } + }) + + continuation.invokeOnCancellation { + try { + cancel() + } catch (ex: Throwable) { + // Ignore cancel exception + } + } + } +} + fun Call.asObservableSuccess(): Observable { return asObservable().doOnNext { response -> if (!response.isSuccessful) {