diff --git a/CHANGELOG.md b/CHANGELOG.md index 461914a76b..cb6715d91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * `Coroutines`: `1.10.1` -> `1.10.2` * `Ktor`: `3.1.1` -> `3.1.3` * `MicroUtils`: `0.25.3` -> `0.25.7` +* `Core`: + * `RequestsExecutor` got property `RequestsExecutor.Log: KSLog?` ## 25.0.1 diff --git a/tgbotapi.behaviour_builder.fsm/api/tgbotapi.behaviour_builder.fsm.api b/tgbotapi.behaviour_builder.fsm/api/tgbotapi.behaviour_builder.fsm.api index 9459fe19dc..8d19a0a864 100644 --- a/tgbotapi.behaviour_builder.fsm/api/tgbotapi.behaviour_builder.fsm.api +++ b/tgbotapi.behaviour_builder.fsm/api/tgbotapi.behaviour_builder.fsm.api @@ -102,6 +102,7 @@ public final class dev/inmo/tgbotapi/extensions/behaviour_builder/DefaultBehavio public fun getEditedMessagesFlow ()Lkotlinx/coroutines/flow/Flow; public fun getFlowsUpdatesFilter ()Ldev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter; public fun getInlineQueriesFlow ()Lkotlinx/coroutines/flow/Flow; + public fun getLog ()Ldev/inmo/kslog/common/KSLog; public fun getMessageMediaGroupsFlow ()Lkotlinx/coroutines/flow/Flow; public fun getMessagesFlow ()Lkotlinx/coroutines/flow/Flow; public fun getMyChatMemberUpdatesFlow ()Lkotlinx/coroutines/flow/Flow; diff --git a/tgbotapi.behaviour_builder/api/tgbotapi.behaviour_builder.api b/tgbotapi.behaviour_builder/api/tgbotapi.behaviour_builder.api index 2341f63931..bc6111191a 100644 --- a/tgbotapi.behaviour_builder/api/tgbotapi.behaviour_builder.api +++ b/tgbotapi.behaviour_builder/api/tgbotapi.behaviour_builder.api @@ -116,6 +116,7 @@ public final class dev/inmo/tgbotapi/extensions/behaviour_builder/DefaultBehavio public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; public fun getData ()Ldev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextData; public fun getFlowsUpdatesFilter ()Ldev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter; + public fun getLog ()Ldev/inmo/kslog/common/KSLog; public fun getScope ()Lkotlinx/coroutines/CoroutineScope; public fun getSubcontextInitialAction ()Lkotlin/jvm/functions/Function3; public fun getTriggersHolder ()Ldev/inmo/tgbotapi/extensions/behaviour_builder/utils/handlers_registrar/TriggersHolder; diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/CombinedSubcontextInitialAction.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/CombinedSubcontextInitialAction.kt index 80e8ba413d..5057b1d486 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/CombinedSubcontextInitialAction.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/CombinedSubcontextInitialAction.kt @@ -40,7 +40,7 @@ class CombinedSubcontextInitialAction( runCatching { invoke(update) }.onFailure { - logger.error(it) { + (Log ?: logger).error(it) { "Unable to execute $subaction for update $update. Will try on next round" } }.onSuccess { @@ -50,7 +50,7 @@ class CombinedSubcontextInitialAction( } leftSubActions.removeAll(successSubActions) if (successSubActions.isEmpty()) { - logger.error { + (Log ?: logger).error { "Some SubActions have been unable to complete successfully:${leftSubActions.joinToString("\n") { it.toString() }}" } break diff --git a/tgbotapi.core/api/tgbotapi.core.api b/tgbotapi.core/api/tgbotapi.core.api index 2b3453a8a8..3b9a5be67f 100644 --- a/tgbotapi.core/api/tgbotapi.core.api +++ b/tgbotapi.core/api/tgbotapi.core.api @@ -246,6 +246,7 @@ public abstract class dev/inmo/tgbotapi/bot/BaseRequestsExecutor : dev/inmo/tgbo public abstract interface class dev/inmo/tgbotapi/bot/RequestsExecutor : java/io/Closeable { public abstract fun execute (Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun getLog ()Ldev/inmo/kslog/common/KSLog; } public abstract class dev/inmo/tgbotapi/bot/exceptions/BotException : java/io/IOException, kotlinx/coroutines/CopyableThrowable { @@ -416,6 +417,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/base/AbstractRequestCallFactoryKt public final class dev/inmo/tgbotapi/bot/ktor/base/DefaultKtorRequestsExecutor : dev/inmo/tgbotapi/bot/BaseRequestsExecutor { public fun close ()V public fun execute (Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun getLog ()Ldev/inmo/kslog/common/KSLog; } public final class dev/inmo/tgbotapi/bot/ktor/base/DownloadFileChannelRequestCallFactory : dev/inmo/tgbotapi/bot/ktor/KtorCallFactory { @@ -439,6 +441,7 @@ public final class dev/inmo/tgbotapi/bot/ktor/base/MultipleClientKtorRequestsExe public fun (Ldev/inmo/tgbotapi/utils/TelegramAPIUrlsKeeper;Ljava/util/List;ZLdev/inmo/tgbotapi/bot/settings/limiters/RequestLimiter;Lkotlinx/serialization/json/Json;Ldev/inmo/tgbotapi/bot/ktor/TelegramBotPipelinesHandler;ILdev/inmo/kslog/common/KSLog;Lkotlin/jvm/functions/Function0;)V public fun close ()V public fun execute (Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun getLog ()Ldev/inmo/kslog/common/KSLog; } public final class dev/inmo/tgbotapi/bot/ktor/base/SimpleRequestCallFactory : dev/inmo/tgbotapi/bot/ktor/base/AbstractRequestCallFactory { @@ -541,6 +544,7 @@ public final class dev/inmo/tgbotapi/bot/multiserver/SimpleMultiServerRequestsEx public synthetic fun (Ljava/util/List;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun close ()V public fun execute (Ldev/inmo/tgbotapi/requests/abstracts/Request;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun getLog ()Ldev/inmo/kslog/common/KSLog; } public final class dev/inmo/tgbotapi/bot/multiserver/SimpleMultiServerRequestsExecutor$Companion { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/RequestsExecutor.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/RequestsExecutor.kt index bd56503202..3c3756f568 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/RequestsExecutor.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/RequestsExecutor.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.bot +import dev.inmo.kslog.common.KSLog import dev.inmo.tgbotapi.requests.abstracts.Request import io.ktor.utils.io.core.Closeable @@ -11,6 +12,8 @@ import io.ktor.utils.io.core.Closeable * @see dev.inmo.tgbotapi.bot.Ktor.KtorRequestsExecutor */ interface RequestsExecutor : Closeable { + val Log: KSLog? + get() = null /** * Unsafe execution of incoming [request]. Can throw almost any exception. So, it is better to use * something like [dev.inmo.tgbotapi.extensions.utils.shortcuts.executeAsync] or 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 c23d52d6af..cc9da7da74 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 @@ -29,6 +29,7 @@ expect class KtorRequestsExecutor internal constructor( logger: KSLog, diff: Unit // just a diff property to know where constructor and where calling function with defaults ) : BaseRequestsExecutor { + override val Log: KSLog? override suspend fun execute(request: Request): T override fun close() } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/DefaultKtorRequestsExecutor.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/DefaultKtorRequestsExecutor.kt index e08f2c3807..e0deb6f658 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/DefaultKtorRequestsExecutor.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/DefaultKtorRequestsExecutor.kt @@ -30,6 +30,7 @@ class DefaultKtorRequestsExecutor internal constructor( private val logger: KSLog, diff: Unit ) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { + override val Log: KSLog? = logger private val callsFactories: List = callsFactories.run { if (!excludeDefaultFactories) { this@DefaultKtorRequestsExecutor.logger.v { "Installing default factories" } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/MultipleClientKtorRequestsExecutor.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/MultipleClientKtorRequestsExecutor.kt index 819aa66132..a66156aa58 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/MultipleClientKtorRequestsExecutor.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/ktor/base/MultipleClientKtorRequestsExecutor.kt @@ -46,7 +46,7 @@ class MultipleClientKtorRequestsExecutor( jsonFormatter: Json, pipelineStepsHolder: TelegramBotPipelinesHandler, requestExecutorsCount: Int, - logger: KSLog, + override val Log: KSLog, clientFactory: () -> HttpClient, ) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { private val requestExecutors = (0 until requestExecutorsCount).map { @@ -58,7 +58,7 @@ class MultipleClientKtorRequestsExecutor( requestsLimiter, jsonFormatter, pipelineStepsHolder, - logger, + Log, Unit ) }.toSet() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/multiserver/SimpleMultiServerRequestsExecutor.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/multiserver/SimpleMultiServerRequestsExecutor.kt index bed97ffbed..e4395c73e7 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/multiserver/SimpleMultiServerRequestsExecutor.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/multiserver/SimpleMultiServerRequestsExecutor.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.bot.multiserver +import dev.inmo.kslog.common.KSLog import dev.inmo.tgbotapi.bot.ktor.KtorRequestsExecutorBuilder import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.RequestsExecutor @@ -29,6 +30,8 @@ class SimpleMultiServerRequestsExecutor( bots.forEach(TelegramBot::close) } ) : RequestsExecutor { + override val Log: KSLog? + get() = bots.firstNotNullOfOrNull { it.Log } override suspend fun execute(request: Request): T { var currentBot = bots.botSelector(-1, null) while (currentCoroutineContext().isActive) { diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt index e39765987c..f1fcb4c938 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt @@ -33,7 +33,7 @@ fun TelegramBot.longPollingFlow( mediaGroupsDebounceTimeMillis: Long? = 1000L, ): Flow = channelFlow { if (autoDisableWebhooks) { - runCatchingSafely { + runCatching { execute(DeleteWebhook()) } } @@ -72,6 +72,13 @@ fun TelegramBot.longPollingFlow( } else { { originalUpdates: List -> val converted = originalUpdates.convertWithMediaGroupUpdates() + + /** + * Dirty hack for cases when the media group was retrieved not fully: + * + * We are throw out the last media group and will reretrieve it again in the next get updates + * and it will guarantee that it is full + */ /** * Dirty hack for cases when the media group was retrieved not fully: * @@ -80,14 +87,14 @@ fun TelegramBot.longPollingFlow( */ val updates = if ( originalUpdates.size == getUpdatesLimit.last - && ((converted.last() as? BaseSentMessageUpdate) ?.data as? CommonMessage<*>) ?.content is MediaGroupContent<*> + && ((converted.last() as? BaseSentMessageUpdate)?.data as? CommonMessage<*>)?.content is MediaGroupContent<*> ) { converted - converted.last() } else { converted } - safelyWithResult { + runCatching { for (update in updates) { send(update) @@ -96,25 +103,16 @@ fun TelegramBot.longPollingFlow( } } }.onFailure { - cancel(it as? CancellationException ?: return@onFailure) + if (it is CancellationException) { + cancel(it) + } } } } withContext(contextToWork) { while (isActive) { - safely( - { e -> - val isHttpRequestTimeoutException = e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException) - if (isHttpRequestTimeoutException && autoSkipTimeoutExceptions) { - return@safely - } - exceptionsHandler ?.invoke(e) - if (e is RequestException) { - delay(1000L) - } - } - ) { + runCatching { execute( GetUpdates( offset = lastUpdateIdentifier?.plus(1), @@ -124,6 +122,16 @@ fun TelegramBot.longPollingFlow( ).let { originalUpdates -> updatesHandler(originalUpdates) } + }.onFailure { e -> + val isHttpRequestTimeoutException = + e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException) + if (isHttpRequestTimeoutException && autoSkipTimeoutExceptions) { + return@onFailure + } + exceptionsHandler?.invoke(e) + if (e is RequestException) { + delay(1000L) + } } } }