diff --git a/CHANGELOG.md b/CHANGELOG.md index ab7dcd3b05..048b8016ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # TelegramBotAPI changelog +## 4.2.3 + +* `Versions`: + * `MicroUtils`: `0.16.2` -> `0.16.4` +* `Core`: + * Simplify default `RequestsLimiter` (`ExceptionsOnlyLimiter`) (thanks to [@y9san9](https://github.com/y9san9) for help) + ## 4.2.2 * `Versions`: diff --git a/gradle.properties b/gradle.properties index d65eeb7079..00e0ade84e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ kotlin.incremental=true kotlin.incremental.js=true library_group=dev.inmo -library_version=4.2.2 +library_version=4.2.3 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 98d24fa96a..2e7f91af54 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ ktor = "2.2.1" ksp = "1.7.22-1.0.8" kotlin-poet = "1.12.0" -microutils = "0.16.2" +microutils = "0.16.4" github-release-plugin = "2.4.1" dokka = "1.7.20" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorRequestsExecutor.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorRequestsExecutor.kt index c9a3663fe5..88990f0996 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorRequestsExecutor.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/KtorRequestsExecutor.kt @@ -30,7 +30,7 @@ class KtorRequestsExecutor( client: HttpClient = HttpClient(), callsFactories: List = emptyList(), excludeDefaultFactories: Boolean = false, - private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(), + private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter, private val jsonFormatter: Json = nonstrictJsonFormat, private val pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder ) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { @@ -51,7 +51,7 @@ class KtorRequestsExecutor( override suspend fun execute(request: Request): T { return runCatchingSafely { pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories) - requestsLimiter.limit { + requestsLimiter.limit(request) { var result: T? = null lateinit var factoryHandledRequest: KtorCallFactory for (potentialFactory in callsFactories) { @@ -111,7 +111,7 @@ class KtorRequestsExecutorBuilder( var client: HttpClient = HttpClient() var callsFactories: List = emptyList() var excludeDefaultFactories: Boolean = false - var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter() + var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter var jsonFormatter: Json = nonstrictJsonFormat fun build() = KtorRequestsExecutor(telegramAPIUrlsKeeper, client, callsFactories, excludeDefaultFactories, requestsLimiter, jsonFormatter) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt index 723e88fd2e..41b7b002b6 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt @@ -1,66 +1,18 @@ package dev.inmo.tgbotapi.bot.settings.limiters -import dev.inmo.micro_utils.coroutines.safely import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException -import dev.inmo.tgbotapi.types.MilliSeconds -import dev.inmo.tgbotapi.types.RetryAfterError -import io.ktor.client.plugins.ClientRequestException -import io.ktor.http.HttpStatusCode import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.first /** - * This limiter will limit requests only after getting a [RetryAfterError] or [ClientRequestException] with - * [HttpStatusCode.TooManyRequests] status code. Important thing is that in case if some of block has been blocked, all - * the others will wait until it will be possible to be called - * - * @param defaultTooManyRequestsDelay This parameter will be used in case of getting [ClientRequestException] with - * [HttpStatusCode.TooManyRequests] as a parameter for delay like it would be [TooMuchRequestsException]. The reason of - * it is that in [ClientRequestException] there is no information about required delay between requests + * Simple limiter which will lock any request when [TooMuchRequestsExceptions] is thrown and rerun request after lock time */ -class ExceptionsOnlyLimiter( - private val defaultTooManyRequestsDelay: MilliSeconds = 1000L -) : RequestLimiter { - private val lockState = MutableStateFlow(false) - private suspend fun lock(timeMillis: MilliSeconds) { - try { - safely { - lockState.emit(true) - delay(timeMillis) - } - } finally { - lockState.emit(false) - } - } - +object ExceptionsOnlyLimiter : RequestLimiter { override suspend fun limit(block: suspend () -> T): T { - while (true) { - lockState.first { !it } - var throwable: Throwable? = null - val result = safely({ - throwable = when (it) { - is TooMuchRequestsException -> { - lock(it.retryAfter.leftToRetry) - it - } - is ClientRequestException -> { - if (it.response.status == HttpStatusCode.TooManyRequests) { - lock(defaultTooManyRequestsDelay) - } else { - throw it - } - it - } - else -> throw it - } - null - }) { - block() - } - if (throwable == null) { - return result!! - } + return try { + block() + } catch (e: TooMuchRequestsException) { + delay(e.retryAfter.leftToRetry) + limit(block) } } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/NoLimitsLimiter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/NoLimitsLimiter.kt new file mode 100644 index 0000000000..09dfda571b --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/NoLimitsLimiter.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.bot.settings.limiters + +object NoLimitsLimiter : RequestLimiter { + override suspend fun limit(block: suspend () -> T): T = block() +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/RequestLimiter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/RequestLimiter.kt index a23ed0b97c..dd08878577 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/RequestLimiter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/RequestLimiter.kt @@ -1,8 +1,12 @@ package dev.inmo.tgbotapi.bot.settings.limiters +import dev.inmo.tgbotapi.requests.abstracts.Request + interface RequestLimiter { /** * Use limit for working of block (like delay between or after, for example) */ suspend fun limit(block: suspend () -> T): T + + suspend fun limit(request: Request, block: suspend () -> T) = limit(block) }