diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8080d0f7..4d9052292c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * `MicroUtils`: `0.12.1` -> `0.12.4` * `Core`: * `SetWebhook#allowedUpdates` now is `ALL_UPDATES_LIST` by default instead of `null` + * `KtorRequestsExecutor#execute` now will __always__ throw `BotException` if something went wrong inside * `API`: * Extension `TelegramBot#setWebhook` parameter `allowedUpdates` now is `ALL_UPDATES_LIST` by default instead of `null` * `Utils`: diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/exceptions/RequestException.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/exceptions/RequestException.kt index 3ed3242660..7448d2e901 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/exceptions/RequestException.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/exceptions/RequestException.kt @@ -35,13 +35,18 @@ fun newRequestException( } } ?: CommonRequestException(response, plainAnswer, message, cause) +sealed class BotException(message: String = "Something went wrong", cause: Throwable? = null) : IOException(message, cause) + +class CommonBotException(message: String = "Something went wrong", cause: Throwable? = null) : BotException(message, cause) + sealed class RequestException constructor( val response: Response, val plainAnswer: String, message: String? = null, - override val cause: Throwable? = null -) : IOException( - message ?: "Something went wrong" + cause: Throwable? = null +) : BotException( + message ?: "Something went wrong", + cause ) class CommonRequestException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) : 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 45ed64fc02..730924daa2 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 @@ -1,9 +1,10 @@ package dev.inmo.tgbotapi.bot.ktor +import dev.inmo.micro_utils.coroutines.runCatchingSafely import dev.inmo.micro_utils.coroutines.safely import dev.inmo.tgbotapi.bot.BaseRequestsExecutor import dev.inmo.tgbotapi.bot.TelegramBot -import dev.inmo.tgbotapi.bot.exceptions.newRequestException +import dev.inmo.tgbotapi.bot.exceptions.* import dev.inmo.tgbotapi.bot.ktor.base.* import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter @@ -48,51 +49,47 @@ class KtorRequestsExecutor( } override suspend fun execute(request: Request): T { - return runCatching { - safely( - { e -> - pipelineStepsHolder.onRequestException(request, e) ?.let { return@safely it } - - throw if (e is ClientRequestException) { - val content = e.response.bodyAsText() - val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) - newRequestException( - responseObject, - content, - "Can't get result object from $content" - ) - } else { - e + return runCatchingSafely { + pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories) + requestsLimiter.limit { + var result: T? = null + lateinit var factoryHandledRequest: KtorCallFactory + for (potentialFactory in callsFactories) { + pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory) + result = potentialFactory.makeCall( + client, + telegramAPIUrlsKeeper, + request, + jsonFormatter + ) + result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory) + if (result != null) { + factoryHandledRequest = potentialFactory + break } - } - ) { - pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories) - requestsLimiter.limit { - var result: T? = null - lateinit var factoryHandledRequest: KtorCallFactory - for (potentialFactory in callsFactories) { - pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory) - result = potentialFactory.makeCall( - client, - telegramAPIUrlsKeeper, - request, - jsonFormatter - ) - result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory) - 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") } }.let { - pipelineStepsHolder.onRequestReturnResult(it, request, callsFactories) + val result = it.exceptionOrNull() ?.let { e -> + pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it } + + if (e is ClientRequestException) { + val content = e.response.bodyAsText() + val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) + newRequestException( + responseObject, + content, + "Can't get result object from $content" + ) + } else { + CommonBotException(cause = e) + } + } ?.let { Result.failure(it) } ?: it + pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories) } }