Migrate extension list fetch to coroutine

This commit is contained in:
arkon 2020-02-02 22:57:15 -05:00 committed by Jay
parent 3bb1c9efa7
commit dc9545570d
4 changed files with 50 additions and 29 deletions

View File

@ -17,9 +17,7 @@ import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
class UpdaterService : IntentService(UpdaterService::class.java.name) { class UpdaterService : IntentService(UpdaterService::class.java.name) {
/**
* Network helper
*/
private val network: NetworkHelper by injectLazy() private val network: NetworkHelper by injectLazy()
/** /**

View File

@ -15,8 +15,6 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.util.system.launchNow import eu.kanade.tachiyomi.util.system.launchNow
import kotlinx.coroutines.async import kotlinx.coroutines.async
import rx.Observable import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -146,11 +144,13 @@ class ExtensionManager(
* Finds the available extensions in the [api] and updates [availableExtensions]. * Finds the available extensions in the [api] and updates [availableExtensions].
*/ */
fun findAvailableExtensions() { fun findAvailableExtensions() {
api.findExtensions() launchNow {
.onErrorReturn { emptyList() } availableExtensions = try {
.subscribeOn(Schedulers.io()) api.findExtensions()
.observeOn(AndroidSchedulers.mainThread()) } catch (e: Exception) {
.subscribe { availableExtensions = it } emptyList()
}
}
} }
/** /**

View File

@ -13,12 +13,10 @@ import eu.kanade.tachiyomi.extension.model.LoadResult
import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.extension.util.ExtensionLoader
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.asObservableSuccess
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import eu.kanade.tachiyomi.network.await
import okhttp3.Response import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.lang.Exception import java.lang.Exception
@ -26,23 +24,18 @@ internal class ExtensionGithubApi {
private val network: NetworkHelper by injectLazy() private val network: NetworkHelper by injectLazy()
private val client get() = network.client
private val gson: Gson by injectLazy() private val gson: Gson by injectLazy()
private val repoUrl = "https://raw.githubusercontent.com/inorichi/tachiyomi-extensions/repo" suspend fun findExtensions(): List<Extension.Available> {
val call = GET("$REPO_URL/index.json")
fun findExtensions(): Observable<List<Extension.Available>> { return parseResponse(network.client.newCall(call).await())
val call = GET("$repoUrl/index.json")
return client.newCall(call).asObservableSuccess()
.map(::parseResponse)
} }
suspend fun checkforUpdates(context: Context): List<Extension.Installed> { suspend fun checkforUpdates(context: Context): List<Extension.Installed> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val call = GET("$repoUrl/index.json") val call = GET("$REPO_URL/index.json")
val response = client.newCall(call).execute() val response = network.client.newCall(call).await()
if (response.isSuccessful) { if (response.isSuccessful) {
val extensions = parseResponse(response) val extensions = parseResponse(response)
@ -80,13 +73,17 @@ internal class ExtensionGithubApi {
val versionName = element["version"].string val versionName = element["version"].string
val versionCode = element["code"].int val versionCode = element["code"].int
val lang = element["lang"].string 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) Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon)
} }
} }
fun getApkUrl(extension: Extension.Available): String { 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"
} }
} }

View File

@ -1,13 +1,14 @@
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
import okhttp3.Call import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.OkHttpClient import okhttp3.*
import okhttp3.Request
import okhttp3.Response
import rx.Observable import rx.Observable
import rx.Producer import rx.Producer
import rx.Subscription import rx.Subscription
import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
fun Call.asObservable(): Observable<Response> { fun Call.asObservable(): Observable<Response> {
return Observable.unsafeCreate { subscriber -> return Observable.unsafeCreate { subscriber ->
@ -46,6 +47,31 @@ fun Call.asObservable(): Observable<Response> {
} }
} }
// 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<Response> { fun Call.asObservableSuccess(): Observable<Response> {
return asObservable().doOnNext { response -> return asObservable().doOnNext { response ->
if (!response.isSuccessful) { if (!response.isSuccessful) {