Apply watchdog before send request (#2056)
* Apply watchdog before send request * Cleanup CronetEngine --------- Co-authored-by: Dude so hot <djohn@fbi.gov>
This commit is contained in:
1 parent
b7948f7965
commit
bfa91bf2fb
5 files changed
+36
-36
No files matched your search
@@ -1,11 +1,11 @@
|
||||
package com.hippo.ehviewer.ktor
|
||||
|
||||
import com.hippo.ehviewer.BuildConfig
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhCookieStore
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngineConfig
|
||||
import io.ktor.client.plugins.HttpTimeout
|
||||
import io.ktor.client.plugins.HttpTimeoutConfig
|
||||
import io.ktor.client.plugins.SaveBodyPlugin
|
||||
import io.ktor.client.plugins.UserAgent
|
||||
import io.ktor.client.plugins.cookies.HttpCookies
|
||||
@@ -22,7 +22,7 @@ fun <T : HttpClientEngineConfig> HttpClientConfig<T>.configureCommon(redirect: B
|
||||
storage = EhCookieStore
|
||||
}
|
||||
install(HttpTimeout) {
|
||||
connectTimeoutMillis = Settings.connTimeout * 1000L
|
||||
reset()
|
||||
requestTimeoutMillis = 10_000
|
||||
}
|
||||
install(UserAgent) {
|
||||
@@ -37,3 +37,9 @@ fun <T : HttpClientEngineConfig> HttpClientConfig<T>.configureCommon(redirect: B
|
||||
disabled = true
|
||||
}
|
||||
}
|
||||
|
||||
fun HttpTimeoutConfig.reset() = apply {
|
||||
requestTimeoutMillis = HttpTimeoutConfig.INFINITE_TIMEOUT_MS
|
||||
connectTimeoutMillis = HttpTimeoutConfig.INFINITE_TIMEOUT_MS
|
||||
socketTimeoutMillis = HttpTimeoutConfig.INFINITE_TIMEOUT_MS
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.util.restartApplication
|
||||
import io.ktor.client.engine.HttpClientEngineBase
|
||||
import io.ktor.client.engine.callContext
|
||||
import io.ktor.client.plugins.ConnectTimeoutException
|
||||
import io.ktor.client.plugins.HttpTimeoutCapability
|
||||
import io.ktor.client.request.HttpRequestData
|
||||
import io.ktor.client.request.HttpResponseData
|
||||
@@ -35,14 +34,12 @@ import java.nio.ByteBuffer
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.asExecutor
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.consumeEach
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import splitties.preferences.edit
|
||||
|
||||
class CronetEngine(override val config: CronetConfig) : HttpClientEngineBase("Cronet") {
|
||||
@@ -58,12 +55,7 @@ class CronetEngine(override val config: CronetConfig) : HttpClientEngineBase("Cr
|
||||
}
|
||||
|
||||
@InternalAPI
|
||||
override suspend fun execute(data: HttpRequestData) = data.getCapabilityOrNull(HttpTimeoutCapability)!!.let { cfg ->
|
||||
val connTimeout = cfg.connectTimeoutMillis!!
|
||||
withTimeoutOrNull(connTimeout.milliseconds) {
|
||||
executeHttpRequest(callContext(), data)
|
||||
} ?: throw ConnectTimeoutException(data)
|
||||
}
|
||||
override suspend fun execute(data: HttpRequestData) = executeHttpRequest(callContext(), data)
|
||||
|
||||
private suspend fun executeHttpRequest(
|
||||
callContext: CoroutineContext,
|
||||
|
||||
@@ -166,6 +166,7 @@ class SpiderDen(val info: GalleryInfo) {
|
||||
referer: String?,
|
||||
notifyProgress: (Long, Long, Int) -> Unit,
|
||||
) = timeoutBySpeed(
|
||||
url,
|
||||
{ ehRequest(url, referer, builder = it) },
|
||||
{ a, b, c -> notifyProgress(a, b, c) },
|
||||
{ resp -> check(saveFromHttpResponse(index, resp)) },
|
||||
|
||||
@@ -5,19 +5,19 @@ import androidx.collection.mutableObjectIntMapOf
|
||||
import arrow.fx.coroutines.fixedRate
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.executeSafely
|
||||
import com.hippo.ehviewer.ktor.reset
|
||||
import com.hippo.ehviewer.util.LowSpeedException
|
||||
import com.hippo.ehviewer.util.ensureSuccess
|
||||
import io.ktor.client.plugins.ConnectTimeoutException
|
||||
import io.ktor.client.plugins.onDownload
|
||||
import io.ktor.client.plugins.timeout
|
||||
import io.ktor.client.request.HttpRequestBuilder
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.statement.HttpStatement
|
||||
import io.ktor.client.statement.request
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.TimeSource
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -57,40 +57,40 @@ class SpeedTracker(val window: Duration = 1.seconds) {
|
||||
}
|
||||
|
||||
suspend inline fun <R> timeoutBySpeed(
|
||||
crossinline req: suspend (HttpRequestBuilder.() -> Unit) -> HttpStatement,
|
||||
url: String,
|
||||
crossinline request: suspend (HttpRequestBuilder.() -> Unit) -> HttpStatement,
|
||||
crossinline l: suspend (Long, Long, Int) -> Unit,
|
||||
crossinline f: suspend (HttpResponse) -> R,
|
||||
) = with(SpeedTracker(2.seconds)) {
|
||||
var prev = 0L
|
||||
req {
|
||||
) = coroutineScope {
|
||||
val watchdog = launch {
|
||||
delay(Settings.connTimeout.seconds)
|
||||
throw ConnectTimeoutException(url, Settings.connTimeout * 1000L)
|
||||
}
|
||||
val tracker = SpeedTracker(2.seconds)
|
||||
request {
|
||||
var prev = 0L
|
||||
onDownload { done, total ->
|
||||
val bytesRead = (done - prev).toInt()
|
||||
track(bytesRead)
|
||||
tracker.track(bytesRead)
|
||||
l(total!!, done, bytesRead)
|
||||
prev = done
|
||||
}
|
||||
timeout { connectTimeoutMillis = Settings.connTimeout * 1000L }
|
||||
timeout { reset() }
|
||||
}.executeSafely { resp ->
|
||||
watchdog.cancel()
|
||||
resp.status.ensureSuccess()
|
||||
val timeoutSpeed = Settings.timeoutSpeed * 1024.0
|
||||
coroutineScope {
|
||||
val work = async { f(resp) }
|
||||
val job = launch {
|
||||
delay(2.seconds) // Tolerant 4 secs for receiving
|
||||
speedFlow(1.seconds).collect { speed ->
|
||||
if (timeoutSpeed != 0.0 && speed < timeoutSpeed) {
|
||||
throw LowSpeedException(
|
||||
resp.request.url.toString(),
|
||||
speed.toLong(),
|
||||
)
|
||||
}
|
||||
val speedWatchdog = launch {
|
||||
val timeoutSpeed = Settings.timeoutSpeed * 1024.0
|
||||
tracker.speedFlow(1.seconds).collect { speed ->
|
||||
if (timeoutSpeed != 0.0 && speed < timeoutSpeed) {
|
||||
throw LowSpeedException(url, speed.toLong())
|
||||
}
|
||||
}
|
||||
try {
|
||||
work.await()
|
||||
} finally {
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
try {
|
||||
f(resp)
|
||||
} finally {
|
||||
speedWatchdog.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ object AppUpdater {
|
||||
}
|
||||
|
||||
suspend fun downloadUpdate(url: String, path: Path) = timeoutBySpeed(
|
||||
url,
|
||||
{ ghStatement(url, builder = it) },
|
||||
{ _, _, _ -> },
|
||||
{ response ->
|
||||
|
||||
Reference in new issue
Block a user