From 084883a308bfde2385cc7495da0968fe05142b9b Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:48:37 +0800 Subject: [PATCH] Decouple CronetEngine --- .../com/hippo/ehviewer/EhApplication.kt | 10 ++++++--- .../hippo/ehviewer/cronet/CronetExtensions.kt | 11 ---------- .../kotlin/com/hippo/ehviewer/ktor/Cronet.kt | 9 ++++++++ .../com/hippo/ehviewer/ktor/CronetConfig.kt | 13 ++++++++++++ .../com/hippo/ehviewer/ktor/CronetEngine.kt | 21 ++++++++++--------- 5 files changed, 40 insertions(+), 24 deletions(-) delete mode 100644 app/src/main/kotlin/com/hippo/ehviewer/cronet/CronetExtensions.kt create mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ktor/Cronet.kt create mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetConfig.kt diff --git a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt index 03bbe71fb..5e93b41f3 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt @@ -43,13 +43,14 @@ import com.hippo.ehviewer.coil.CropBorderInterceptor import com.hippo.ehviewer.coil.DownloadThumbInterceptor import com.hippo.ehviewer.coil.HardwareBitmapInterceptor import com.hippo.ehviewer.coil.MergeInterceptor +import com.hippo.ehviewer.cronet.cronetHttpClient import com.hippo.ehviewer.dailycheck.checkDawn import com.hippo.ehviewer.dao.SearchDatabase import com.hippo.ehviewer.download.DownloadManager import com.hippo.ehviewer.download.DownloadsFilterMode import com.hippo.ehviewer.ktbuilder.diskCache import com.hippo.ehviewer.ktbuilder.imageLoader -import com.hippo.ehviewer.ktor.CronetEngine +import com.hippo.ehviewer.ktor.Cronet import com.hippo.ehviewer.legacy.cleanObsoleteCache import com.hippo.ehviewer.ui.keepNoMediaFileStatus import com.hippo.ehviewer.ui.lockObserver @@ -197,7 +198,10 @@ class EhApplication : companion object { val ktorClient by lazy { - HttpClient(CronetEngine) { + HttpClient(Cronet) { + engine { + client = cronetHttpClient + } install(HttpCookies) { storage = EhCookieStore } @@ -205,7 +209,7 @@ class EhApplication : } val noRedirectKtorClient by lazy { - HttpClient(CronetEngine) { + HttpClient(ktorClient.engine) { followRedirects = false install(HttpCookies) { storage = EhCookieStore diff --git a/app/src/main/kotlin/com/hippo/ehviewer/cronet/CronetExtensions.kt b/app/src/main/kotlin/com/hippo/ehviewer/cronet/CronetExtensions.kt deleted file mode 100644 index 9a0866939..000000000 --- a/app/src/main/kotlin/com/hippo/ehviewer/cronet/CronetExtensions.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.hippo.ehviewer.cronet - -import io.ktor.utils.io.pool.DirectByteBufferPool -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.asExecutor - -val pool = DirectByteBufferPool(32) - -// Limit thread to 1 since we are async & non-blocking -val cronetDispatcher = Dispatchers.Default.limitedParallelism(1) -val cronetHttpClientExecutor = cronetDispatcher.asExecutor() diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ktor/Cronet.kt b/app/src/main/kotlin/com/hippo/ehviewer/ktor/Cronet.kt new file mode 100644 index 000000000..5291dead9 --- /dev/null +++ b/app/src/main/kotlin/com/hippo/ehviewer/ktor/Cronet.kt @@ -0,0 +1,9 @@ +package com.hippo.ehviewer.ktor + +import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.HttpClientEngineFactory + +object Cronet : HttpClientEngineFactory { + override fun create(block: CronetConfig.() -> Unit): HttpClientEngine = + CronetEngine(CronetConfig().apply(block)) +} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetConfig.kt b/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetConfig.kt new file mode 100644 index 000000000..b9f35892e --- /dev/null +++ b/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetConfig.kt @@ -0,0 +1,13 @@ +package com.hippo.ehviewer.ktor + +import android.content.Context +import io.ktor.client.engine.HttpClientEngineConfig +import org.chromium.net.CronetEngine + +class CronetConfig : HttpClientEngineConfig() { + var client: CronetEngine? = null + + fun config(context: Context, block: CronetEngine.Builder.() -> Unit) { + client = CronetEngine.Builder(context).apply(block).build() + } +} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetEngine.kt b/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetEngine.kt index 2217f4440..f72b9b043 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetEngine.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ktor/CronetEngine.kt @@ -1,11 +1,6 @@ package com.hippo.ehviewer.ktor -import com.hippo.ehviewer.cronet.cronetDispatcher -import com.hippo.ehviewer.cronet.cronetHttpClient -import com.hippo.ehviewer.cronet.cronetHttpClientExecutor -import com.hippo.ehviewer.cronet.pool import io.ktor.client.engine.HttpClientEngineBase -import io.ktor.client.engine.HttpClientEngineConfig import io.ktor.client.engine.callContext import io.ktor.client.request.HttpRequestData import io.ktor.client.request.HttpResponseData @@ -18,12 +13,15 @@ import io.ktor.util.date.GMTDate import io.ktor.util.flattenForEach import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.InternalAPI +import io.ktor.utils.io.pool.DirectByteBufferPool import io.ktor.utils.io.pool.useInstance import io.ktor.utils.io.writer import java.nio.ByteBuffer import kotlin.coroutines.CoroutineContext import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.job @@ -33,9 +31,12 @@ import org.chromium.net.UrlRequest import org.chromium.net.UrlResponseInfo import org.chromium.net.apihelpers.UploadDataProviders -object CronetEngine : HttpClientEngineBase("Cronet") { - override val config = HttpClientEngineConfig() - override val dispatcher = cronetDispatcher +class CronetEngine(override val config: CronetConfig) : HttpClientEngineBase("Cronet") { + // Limit thread to 1 since we are async & non-blocking + override val dispatcher = Dispatchers.Default.limitedParallelism(1) + private val executor = dispatcher.asExecutor() + private val pool = DirectByteBufferPool(32) + private val client = config.client ?: error("Cronet client is not configured") @InternalAPI override suspend fun execute(data: HttpRequestData) = executeHttpRequest(callContext(), data) @@ -94,12 +95,12 @@ object CronetEngine : HttpClientEngineBase("Cronet") { } } - cronetHttpClient.newUrlRequestBuilder(data.url.toString(), callback, cronetHttpClientExecutor).apply { + client.newUrlRequestBuilder(data.url.toString(), callback, executor).apply { setHttpMethod(data.method.value) data.headers.flattenForEach { key, value -> addHeader(key, value) } data.body.contentType?.let { addHeader(HttpHeaders.ContentType, it.toString()) } data.body.contentLength?.let { addHeader(HttpHeaders.ContentLength, it.toString()) } - data.body.toUploadDataProvider()?.let { setUploadDataProvider(it, cronetHttpClientExecutor) } + data.body.toUploadDataProvider()?.let { setUploadDataProvider(it, executor) } }.build().apply { start() callContext.job.invokeOnCompletion { cancel() }