1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-10-25 17:20:07 +00:00

small hotfix

This commit is contained in:
2025-10-22 01:51:20 +06:00
parent 68897c89c3
commit f8ceab7640
13 changed files with 131 additions and 40 deletions

View File

@@ -2,6 +2,12 @@
## 30.0.1
* `Core`:
* Potential fix of [#989](https://github.com/InsanusMokrassar/ktgbotapi/issues/989) by:
* In long polling have been added check for causing by unresolved address exception
* Add `TelegramBotPipelinesHandler.onRequestExceptionInLimiter` which will be triggered in ANY exception during
request execution
## 30.0.0
**THIS UPDATE MAY CONTAINS BREAKING CHANGES**

View File

@@ -9,4 +9,4 @@ kotlin.incremental.js=true
ksp.useKSP2=false
library_group=dev.inmo
library_version=30.0.1
library_version=30.0.1-rc3

View File

@@ -397,6 +397,7 @@ public abstract interface class dev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesH
public fun onBeforeCallFactoryMakeCall (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onBeforeSearchCallFactory (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestException (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestExceptionInLimiter (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultAbsent (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultPresented (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestReturnResult-3t6e044 (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -407,6 +408,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler$Compan
public fun onBeforeCallFactoryMakeCall (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onBeforeSearchCallFactory (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestException (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestExceptionInLimiter (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultAbsent (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultPresented (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestReturnResult-3t6e044 (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -417,6 +419,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler$Defaul
public static fun onBeforeCallFactoryMakeCall (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun onBeforeSearchCallFactory (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun onRequestException (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun onRequestExceptionInLimiter (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun onRequestResultAbsent (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun onRequestResultPresented (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun onRequestReturnResult-3t6e044 (Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -475,13 +478,14 @@ public final class dev/inmo/tgbotapi/bot/ktor/base/SimpleRequestCallFactory : de
public class dev/inmo/tgbotapi/bot/ktor/middlewares/TelegramBotMiddleware : dev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler {
public static final field Companion Ldev/inmo/tgbotapi/bot/ktor/middlewares/TelegramBotMiddleware$Companion;
public fun <init> ()V
public fun <init> (Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Ljava/lang/String;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;Ljava/lang/String;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getId ()Ljava/lang/String;
public fun onAfterCallFactoryMakeCall (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onBeforeCallFactoryMakeCall (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onBeforeSearchCallFactory (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestException (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestExceptionInLimiter (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultAbsent (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultPresented (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestReturnResult-3t6e044 (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -503,6 +507,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/middlewares/TelegramBotMiddlewareB
public final fun doOnBeforeCallFactoryMakeCall (Lkotlin/jvm/functions/Function3;)V
public final fun doOnBeforeSearchCallFactory (Lkotlin/jvm/functions/Function3;)V
public final fun doOnRequestException (Lkotlin/jvm/functions/Function3;)V
public final fun doOnRequestExceptionInLimiter (Lkotlin/jvm/functions/Function3;)V
public final fun doOnRequestResultAbsent (Lkotlin/jvm/functions/Function3;)V
public final fun doOnRequestResultPresented (Lkotlin/jvm/functions/Function5;)V
public final fun doOnRequestReturnResult (Lkotlin/jvm/functions/Function4;)V
@@ -511,6 +516,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/middlewares/TelegramBotMiddlewareB
public final fun getOnBeforeCallFactoryMakeCall ()Lkotlin/jvm/functions/Function3;
public final fun getOnBeforeSearchCallFactory ()Lkotlin/jvm/functions/Function3;
public final fun getOnRequestException ()Lkotlin/jvm/functions/Function3;
public final fun getOnRequestExceptionInLimiter ()Lkotlin/jvm/functions/Function3;
public final fun getOnRequestResultAbsent ()Lkotlin/jvm/functions/Function3;
public final fun getOnRequestResultPresented ()Lkotlin/jvm/functions/Function5;
public final fun getOnRequestReturnResult ()Lkotlin/jvm/functions/Function4;
@@ -519,6 +525,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/middlewares/TelegramBotMiddlewareB
public final fun setOnBeforeCallFactoryMakeCall (Lkotlin/jvm/functions/Function3;)V
public final fun setOnBeforeSearchCallFactory (Lkotlin/jvm/functions/Function3;)V
public final fun setOnRequestException (Lkotlin/jvm/functions/Function3;)V
public final fun setOnRequestExceptionInLimiter (Lkotlin/jvm/functions/Function3;)V
public final fun setOnRequestResultAbsent (Lkotlin/jvm/functions/Function3;)V
public final fun setOnRequestResultPresented (Lkotlin/jvm/functions/Function5;)V
public final fun setOnRequestReturnResult (Lkotlin/jvm/functions/Function4;)V
@@ -537,6 +544,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/middlewares/TelegramBotMiddlewares
public fun onBeforeCallFactoryMakeCall (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onBeforeSearchCallFactory (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestException (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestExceptionInLimiter (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultAbsent (Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestResultPresented (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ldev/inmo/tgbotapi/bot/ktor/KtorCallFactory;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun onRequestReturnResult-3t6e044 (Ljava/lang/Object;Ldev/inmo/tgbotapi/requests/abstracts/Request;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -31903,6 +31911,16 @@ public final class dev/inmo/tgbotapi/utils/CausedByCancellationKt {
public static final fun isCausedByCancellation (Ljava/lang/Throwable;)Z
}
public final class dev/inmo/tgbotapi/utils/CausedByKt {
public static final fun causedBy (Ljava/lang/Throwable;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)Ljava/lang/Throwable;
public static synthetic fun causedBy$default (Ljava/lang/Throwable;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Throwable;
}
public final class dev/inmo/tgbotapi/utils/CausedByUnresolvedAddressExceptionKt {
public static final fun causedUnresolvedAddressException (Ljava/lang/Throwable;)Ljava/nio/channels/UnresolvedAddressException;
public static final fun isCausedUnresolvedAddressException (Ljava/lang/Throwable;)Z
}
public final class dev/inmo/tgbotapi/utils/DefaultKSLogKt {
public static final fun SetDefaultKTgBotAPIKSLog (ZLkotlin/jvm/functions/Function1;)V
public static synthetic fun SetDefaultKTgBotAPIKSLog$default (ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V

View File

@@ -3,9 +3,24 @@ package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.requests.abstracts.Request
interface TelegramBotPipelinesHandler {
/**
* Will be called when any exception will happen due to the [request] handling inside of limiter block. This method
* will be called for each exception happened during call factory call
*/
suspend fun <T: Any> onRequestExceptionInLimiter(
request: Request<T>,
t: Throwable
): T? = null
/**
* Will be called when any exception will happen due to the [request] handling. If returns value - that value
* will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead
* will be returned from [dev.inmo.tgbotapi.bot.RequestsExecutor.execute] instead. In difference with
* [onRequestExceptionInLimiter], this method will be called only AFTER
* [dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter] will pass result of call factory execution outside of
* its [dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter.limit] function
*
* @see dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor
* @see dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
*/
suspend fun <T: Any> onRequestException(
request: Request<T>,

View File

@@ -53,29 +53,33 @@ class DefaultKtorRequestsExecutor internal constructor(
logger.v { "Start request $request" }
pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories)
requestsLimiter.limit(request) {
var result: T? = null
lateinit var factoryHandledRequest: KtorCallFactory
for (potentialFactory in callsFactories) {
pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory)
logger.v { "Trying factory $potentialFactory for $request" }
val resultFromFactory = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
logger.v { "Result of factory $potentialFactory handling $request: $resultFromFactory" }
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(resultFromFactory, request, potentialFactory)
logger.v { "Result of pipeline $pipelineStepsHolder handling $resultFromFactory: $result" }
if (result != null) {
factoryHandledRequest = potentialFactory
break
runCatching {
var result: T? = null
lateinit var factoryHandledRequest: KtorCallFactory
for (potentialFactory in callsFactories) {
pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory)
logger.v { "Trying factory $potentialFactory for $request" }
val resultFromFactory = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
logger.v { "Result of factory $potentialFactory handling $request: $resultFromFactory" }
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(resultFromFactory, request, potentialFactory)
logger.v { "Result of pipeline $pipelineStepsHolder handling $resultFromFactory: $result" }
if (result != null) {
factoryHandledRequest = potentialFactory
break
}
}
}
result ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
result ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
}.onFailure { e ->
pipelineStepsHolder.onRequestExceptionInLimiter(request, e) ?.let { return@let it } ?: throw e
}.getOrThrow()
}
}.let {
val result = it.exceptionOrNull() ?.let { e ->

View File

@@ -31,9 +31,16 @@ open class TelegramBotMiddleware(
internal val onRequestResultPresented: (suspend (result: Any, request: Request<*>, resultCallFactory: KtorCallFactory, callsFactories: List<KtorCallFactory>) -> Any?)? = null,
internal val onRequestResultAbsent: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Any?)? = null,
internal val onRequestReturnResult: (suspend (result: Result<*>, request: Request<*>, callsFactories: List<KtorCallFactory>) -> Result<Any?>?)? = null,
internal val onRequestExceptionInLimiter: (suspend (request: Request<*>, t: Throwable?) -> Any?)? = null,
val id: String = uuid4().toString()
) : TelegramBotPipelinesHandler {
object ResultAbsence : Throwable()
override suspend fun <T : Any> onRequestExceptionInLimiter(request: Request<T>, t: Throwable): T? {
@Suppress("UNCHECKED_CAST")
return onRequestExceptionInLimiter ?.invoke(request, t) as? T
}
override suspend fun <T : Any> onRequestException(request: Request<T>, t: Throwable): T? {
@Suppress("UNCHECKED_CAST")
return onRequestException ?.invoke(request, t) as? T

View File

@@ -8,6 +8,7 @@ import dev.inmo.tgbotapi.requests.abstracts.Request
@Warning("This API is experimental and subject of changes")
class TelegramBotMiddlewareBuilder {
var onRequestExceptionInLimiter: (suspend (request: Request<*>, t: Throwable?) -> Any?)? = null
var onRequestException: (suspend (request: Request<*>, t: Throwable?) -> Any?)? = null
var onBeforeSearchCallFactory: (suspend (request: Request<*>, callsFactories: List<KtorCallFactory>) -> Unit)? = null
var onBeforeCallFactoryMakeCall: (suspend (request: Request<*>, potentialFactory: KtorCallFactory) -> Unit)? = null
@@ -17,6 +18,12 @@ class TelegramBotMiddlewareBuilder {
var onRequestReturnResult: (suspend (result: Result<*>, request: Request<*>, callsFactories: List<KtorCallFactory>) -> Result<Any?>?)? = null
var id: String = uuid4().toString()
/**
* Useful way to set [onRequestException]
*/
fun doOnRequestExceptionInLimiter(block: suspend (request: Request<*>, t: Throwable?) -> Any?) {
onRequestExceptionInLimiter = block
}
/**
* Useful way to set [onRequestException]
*/
@@ -63,6 +70,7 @@ class TelegramBotMiddlewareBuilder {
@Warning("This API is experimental and subject of changes")
fun build(): TelegramBotMiddleware {
return TelegramBotMiddleware(
onRequestExceptionInLimiter = onRequestExceptionInLimiter,
onRequestException = onRequestException,
onBeforeSearchCallFactory = onBeforeSearchCallFactory,
onBeforeCallFactoryMakeCall = onBeforeCallFactoryMakeCall,
@@ -78,6 +86,7 @@ class TelegramBotMiddlewareBuilder {
@Warning("This API is experimental and subject of changes")
fun from(middleware: TelegramBotMiddleware, additionalSetup: TelegramBotMiddlewareBuilder.() -> Unit): TelegramBotMiddleware {
return TelegramBotMiddlewareBuilder().apply {
onRequestExceptionInLimiter = middleware.onRequestExceptionInLimiter
onRequestException = middleware.onRequestException
onBeforeSearchCallFactory = middleware.onBeforeSearchCallFactory
onBeforeCallFactoryMakeCall = middleware.onBeforeCallFactoryMakeCall

View File

@@ -10,6 +10,12 @@ import dev.inmo.tgbotapi.requests.abstracts.Request
class TelegramBotMiddlewaresPipelinesHandler(
private val middlewares: List<TelegramBotMiddleware> = emptyList()
) : TelegramBotPipelinesHandler {
override suspend fun <T : Any> onRequestExceptionInLimiter(request: Request<T>, t: Throwable): T? {
return middlewares.firstNotNullOfOrNull {
it.onRequestExceptionInLimiter(request, t)
} ?: super.onRequestExceptionInLimiter(request, t)
}
override suspend fun <T : Any> onRequestException(request: Request<T>, t: Throwable): T? {
return middlewares.firstNotNullOfOrNull {
it.onRequestException(request, t)

View File

@@ -1,6 +1,8 @@
package dev.inmo.tgbotapi.bot.settings.limiters
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
import dev.inmo.tgbotapi.utils.isCausedUnresolvedAddressException
import io.ktor.util.network.UnresolvedAddressException
import kotlinx.coroutines.delay
/**
@@ -13,10 +15,10 @@ object ExceptionsOnlyLimiter : RequestLimiter {
result = runCatching {
block()
}.onFailure {
if (it is TooMuchRequestsException) {
delay(it.retryAfter.leftToRetry)
} else {
throw it
when {
it.isCausedUnresolvedAddressException() -> delay(1000L)
it is TooMuchRequestsException -> delay(it.retryAfter.leftToRetry)
else -> throw it
}
}
}

View File

@@ -0,0 +1,15 @@
package dev.inmo.tgbotapi.utils
import kotlin.reflect.KClass
fun <T : Throwable> Throwable.causedBy(kclass: KClass<T>, additionalFilterOnHappened: (T) -> T? = { it }): T? {
var current = this
while (kclass.isInstance(current) == false) {
when {
kclass.isInstance(current) -> return additionalFilterOnHappened(current as T)
else -> current = current.cause ?: return null
}
}
return current as T
}

View File

@@ -14,16 +14,9 @@ import kotlinx.coroutines.CancellationException
* @return the first [CancellationException] found in the cause chain, or `null` if none present
*/
fun Throwable.causedCancellationException(): CancellationException? {
var current = this
while (current !is CancellationException) {
when {
// It is possible, that API will be changed and cancellation will be caused by something else
current is CancellationException && current.cause == null -> return current
else -> current = current.cause ?: return null
}
return causedBy(CancellationException::class) {
it.takeIf { it.cause == null }
}
return current
}
/**

View File

@@ -0,0 +1,9 @@
package dev.inmo.tgbotapi.utils
import io.ktor.util.network.UnresolvedAddressException
fun Throwable.causedUnresolvedAddressException(): UnresolvedAddressException? {
return causedBy(UnresolvedAddressException::class)
}
fun Throwable.isCausedUnresolvedAddressException(): Boolean = causedUnresolvedAddressException() != null

View File

@@ -18,8 +18,11 @@ import dev.inmo.tgbotapi.updateshandlers.*
import dev.inmo.tgbotapi.utils.DefaultKTgBotAPIKSLog
import dev.inmo.tgbotapi.utils.causedCancellationException
import dev.inmo.tgbotapi.utils.isCausedByCancellation
import dev.inmo.tgbotapi.utils.isCausedUnresolvedAddressException
import dev.inmo.tgbotapi.utils.subscribeWithBotLogger
import io.ktor.client.network.sockets.ConnectTimeoutException
import io.ktor.client.plugins.HttpRequestTimeoutException
import io.ktor.util.network.UnresolvedAddressException
import io.ktor.utils.io.CancellationException
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
@@ -127,12 +130,16 @@ fun TelegramBot.longPollingFlow(
}.onFailure { e ->
runCatchingLogging(logger = Log) {
val isHttpRequestTimeoutException =
e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException)
e is ConnectTimeoutException || e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException)
if (isHttpRequestTimeoutException && autoSkipTimeoutExceptions) {
return@onFailure
}
exceptionsHandler?.invoke(e)
if (e is RequestException) {
// It seems some problems with internet connection. See https://github.com/InsanusMokrassar/ktgbotapi/issues/989
val isUnresolvedAddressException = e.isCausedUnresolvedAddressException()
if (e is RequestException || isUnresolvedAddressException) {
delay(1000L)
}
}