package com.example.modifier.http import com.example.modifier.http.response.ErrorResponse import com.example.modifier.repo.AppPrefsRepo import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.engine.okhttp.OkHttp import io.ktor.client.network.sockets.ConnectTimeoutException import io.ktor.client.network.sockets.SocketTimeoutException import io.ktor.client.plugins.ClientRequestException import io.ktor.client.plugins.HttpRequestRetry import io.ktor.client.plugins.HttpRequestTimeoutException import io.ktor.client.plugins.HttpResponseValidator import io.ktor.client.plugins.HttpSend import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.defaultRequest import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logging import io.ktor.client.plugins.resources.Resources import io.ktor.client.utils.unwrapCancellationException import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.CancellationException import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json private fun Throwable.isTimeoutException(): Boolean { val exception = unwrapCancellationException() return exception is HttpRequestTimeoutException || exception is ConnectTimeoutException || exception is SocketTimeoutException } @OptIn(ExperimentalSerializationApi::class) var ktorClient = HttpClient(OkHttp) { defaultRequest { val server = AppPrefsRepo.instance.appPrefs.value.server url(server.endsWith("/").let { if (it) server else "$server/" }) } install(HttpSend) { maxSendCount = 200 } install(Logging) { level = LogLevel.INFO } install(HttpRequestRetry) { maxRetries = 3 retryOnExceptionIf { _, cause -> when { cause.isTimeoutException() -> true cause is CancellationException -> false else -> true } } retryIf { _, response -> response.status.value.let { when (it) { 425, 429, 502, 503, 504 -> true else -> false } } } delayMillis { 1000 } } install(HttpTimeout) { requestTimeoutMillis = 30 * 1000 socketTimeoutMillis = 30 * 1000 } install(Resources) install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true explicitNulls = false }) } HttpResponseValidator { validateResponse { response -> if (response.status.value !in 200..299) { val error = response.body() throw ClientRequestException(response, error.message ?: "Unknown error") } } } }