From 4643ac906a9284e7dc73072d5c4293c8e1e0391c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 18 May 2022 16:45:08 +0600 Subject: [PATCH] StateHandlingErrorHandler --- CHANGELOG.md | 3 ++ .../BehaviourContextWithFSM.kt | 50 ++++++++++++++++--- .../BehaviourContextWithFSMBuilder.kt | 11 ++-- .../StateHandlingErrorHandler.kt | 5 ++ 4 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/StateHandlingErrorHandler.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0f7d0b37..f3de349b49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ * `Core`: * Rename of `TelegramAPIUrlsKeeper#checkWebAppLink` -> `TelegramAPIUrlsKeeper#checkWebAppData` (fix of [#591](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/591)) +* `Behaviour Builder with FSM`: + * New typealias `StateHandlingErrorHandler` + * `BehaviourBuilderWithFSM` now accepts new parameter `onStateHandlingErrorHandler` which will be used in case if state has not been successfully completed ## 1.1.1 diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt index 30ebf58bc3..e799a32060 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt @@ -1,7 +1,6 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder -import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions -import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.micro_utils.coroutines.* import dev.inmo.micro_utils.fsm.common.* import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.types.update.abstracts.Update @@ -50,12 +49,24 @@ interface BehaviourContextWithFSM : BehaviourContext, StatesMachine? ): BehaviourContextWithFSM + fun copy( + bot: TelegramBot = this.bot, + scope: CoroutineScope = this.scope, + broadcastChannelsSize: Int = 100, + onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND, + upstreamUpdatesFlow: Flow? = null, + triggersHolder: TriggersHolder = this.triggersHolder, + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), + updatesFilter: BehaviourContextAndTypeReceiver? = null + ): BehaviourContextWithFSM + companion object { operator fun invoke( behaviourContext: BehaviourContext, handlers: List>, - statesManager: StatesManager - ) = DefaultBehaviourContextWithFSM(behaviourContext, statesManager, handlers) + statesManager: StatesManager, + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler() + ) = DefaultBehaviourContextWithFSM(behaviourContext, statesManager, handlers, onStateHandlingErrorHandler) } } @@ -84,16 +95,26 @@ inline fun BehaviourContextWithFSM.strictlyOn(handl /** * Default realization of [BehaviourContextWithFSM]. It uses [behaviourContext] as a base for this object as * [BehaviourContext], but managing substates contexts updates for avoiding of updates lost between states + * @param onStateHandlingErrorHandler Will be used in case if state handling has not been successfully completed in [launchStateHandling] */ class DefaultBehaviourContextWithFSM( private val behaviourContext: BehaviourContext, private val statesManager: StatesManager, - private val handlers: List> + private val handlers: List>, + private val onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler() ) : BehaviourContext by behaviourContext, BehaviourContextWithFSM { private val updatesFlows = mutableMapOf>() private val additionalHandlers = mutableListOf>() private var actualHandlersList = additionalHandlers + handlers + override suspend fun launchStateHandling(state: T, handlers: List>): T? { + return runCatchingSafely { + super.launchStateHandling(state, handlers) + }.getOrElse { + onStateHandlingErrorHandler(state, it) + } + } + private fun getSubContext(context: Any) = updatesFlows.getOrPut(context) { createSubContext() } @@ -174,6 +195,23 @@ class DefaultBehaviourContextWithFSM( ): DefaultBehaviourContextWithFSM = BehaviourContextWithFSM( behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder, updatesFilter), handlers, - statesManager + statesManager, + onStateHandlingErrorHandler + ) + + override fun copy( + bot: TelegramBot, + scope: CoroutineScope, + broadcastChannelsSize: Int, + onBufferOverflow: BufferOverflow, + upstreamUpdatesFlow: Flow?, + triggersHolder: TriggersHolder, + onStateHandlingErrorHandler: StateHandlingErrorHandler, + updatesFilter: BehaviourContextAndTypeReceiver? + ): DefaultBehaviourContextWithFSM = BehaviourContextWithFSM( + behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder, updatesFilter), + handlers, + statesManager, + onStateHandlingErrorHandler ) } diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt index 9bcc15e42a..ed26ea6d35 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt @@ -6,13 +6,10 @@ import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager import dev.inmo.micro_utils.fsm.common.managers.InMemoryDefaultStatesManagerRepo import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling -import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter -import dev.inmo.tgbotapi.utils.PreviewFeature import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow -import kotlin.reflect.KClass @Deprecated("Will be removed soon") typealias BehaviourContextWithFSMBuilder = BehaviourContextWithFSM @@ -33,6 +30,7 @@ suspend fun TelegramBot.buildBehaviourWithFSM( defaultExceptionsHandler: ExceptionHandler? = null, statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), presetHandlers: List> = listOf(), + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), block: CustomBehaviourContextReceiver, Unit> ): DefaultBehaviourContextWithFSM = BehaviourContextWithFSM( DefaultBehaviourContext( @@ -41,7 +39,8 @@ suspend fun TelegramBot.buildBehaviourWithFSM( upstreamUpdatesFlow = upstreamUpdatesFlow ), presetHandlers, - statesManager + statesManager, + onStateHandlingErrorHandler ).apply { block() } /** @@ -55,6 +54,7 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( defaultExceptionsHandler: ExceptionHandler? = null, statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), presetHandlers: List> = listOf(), + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), block: CustomBehaviourContextReceiver, Unit> ): Pair, Job> = buildBehaviourWithFSM( upstreamUpdatesFlow, @@ -62,6 +62,7 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( defaultExceptionsHandler, statesManager, presetHandlers, + onStateHandlingErrorHandler, block ).run { this to scope.launch { @@ -94,6 +95,7 @@ suspend fun TelegramBot.buildBehaviourWithFSM( defaultExceptionsHandler: ExceptionHandler? = null, statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), presetHandlers: List> = listOf(), + onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), block: CustomBehaviourContextReceiver, Unit> ): DefaultBehaviourContextWithFSM = BehaviourContextWithFSM( DefaultBehaviourContext( @@ -102,6 +104,7 @@ suspend fun TelegramBot.buildBehaviourWithFSM( upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow ), presetHandlers, + onStateHandlingErrorHandler, statesManager ).apply { block() } diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/StateHandlingErrorHandler.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/StateHandlingErrorHandler.kt new file mode 100644 index 0000000000..26e9a06fb4 --- /dev/null +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/StateHandlingErrorHandler.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.extensions.behaviour_builder + +typealias StateHandlingErrorHandler = suspend (T, Throwable) -> T? +val DefaultStateHandlingErrorHandler: StateHandlingErrorHandler<*> = { _, _ -> null } +inline fun defaultStateHandlingErrorHandler(): StateHandlingErrorHandler = DefaultStateHandlingErrorHandler as StateHandlingErrorHandler