StateHandlingErrorHandler

This commit is contained in:
InsanusMokrassar 2022-05-18 16:45:08 +06:00
parent 497974e45c
commit 4643ac906a
4 changed files with 59 additions and 10 deletions

View File

@ -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

View File

@ -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<T : State> : BehaviourContext, StatesMachine<T
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM<T>
fun copy(
bot: TelegramBot = this.bot,
scope: CoroutineScope = this.scope,
broadcastChannelsSize: Int = 100,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND,
upstreamUpdatesFlow: Flow<Update>? = null,
triggersHolder: TriggersHolder = this.triggersHolder,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? = null
): BehaviourContextWithFSM<T>
companion object {
operator fun <T : State> invoke(
behaviourContext: BehaviourContext,
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
statesManager: StatesManager<T>
) = DefaultBehaviourContextWithFSM<T>(behaviourContext, statesManager, handlers)
statesManager: StatesManager<T>,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) = DefaultBehaviourContextWithFSM<T>(behaviourContext, statesManager, handlers, onStateHandlingErrorHandler)
}
}
@ -84,16 +95,26 @@ inline fun <reified I : O, O: State> BehaviourContextWithFSM<O>.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<T : State>(
private val behaviourContext: BehaviourContext,
private val statesManager: StatesManager<T>,
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
private val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
private val updatesFlows = mutableMapOf<Any, DefaultBehaviourContextWithFSM<T>>()
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
private var actualHandlersList = additionalHandlers + handlers
override suspend fun launchStateHandling(state: T, handlers: List<CheckableHandlerHolder<in T, T>>): 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<T : State>(
): DefaultBehaviourContextWithFSM<T> = 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<Update>?,
triggersHolder: TriggersHolder,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T>,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder, updatesFilter),
handlers,
statesManager,
onStateHandlingErrorHandler
)
}

View File

@ -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<T> = BehaviourContextWithFSM<T>
@ -33,6 +30,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
DefaultBehaviourContext(
@ -41,7 +39,8 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
upstreamUpdatesFlow = upstreamUpdatesFlow
),
presetHandlers,
statesManager
statesManager,
onStateHandlingErrorHandler
).apply { block() }
/**
@ -55,6 +54,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): Pair<DefaultBehaviourContextWithFSM<T>, Job> = buildBehaviourWithFSM(
upstreamUpdatesFlow,
@ -62,6 +62,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
defaultExceptionsHandler,
statesManager,
presetHandlers,
onStateHandlingErrorHandler,
block
).run {
this to scope.launch {
@ -94,6 +95,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
DefaultBehaviourContext(
@ -102,6 +104,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow
),
presetHandlers,
onStateHandlingErrorHandler,
statesManager
).apply { block() }

View File

@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
typealias StateHandlingErrorHandler<T> = suspend (T, Throwable) -> T?
val DefaultStateHandlingErrorHandler: StateHandlingErrorHandler<*> = { _, _ -> null }
inline fun <T> defaultStateHandlingErrorHandler(): StateHandlingErrorHandler<T> = DefaultStateHandlingErrorHandler as StateHandlingErrorHandler<T>