diff --git a/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt b/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt index 17015fe5ee..a7e41bad85 100644 --- a/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt +++ b/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt @@ -1,7 +1,6 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder -import dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler -import dev.inmo.micro_utils.coroutines.ExceptionHandler +import dev.inmo.micro_utils.coroutines.* import dev.inmo.micro_utils.fsm.common.* import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager import dev.inmo.micro_utils.fsm.common.managers.InMemoryDefaultStatesManagerRepo @@ -48,6 +47,32 @@ class BehaviourContextWithFSMBuilder internal constructor( handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, true, handler)) } + + /** + * Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that + * for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement + * + * @see BehaviourWithFSMStateHandlerHolder + * @see BehaviourContextWithFSMBuilder.add + */ + @Suppress("MemberVisibilityCanBePrivate") + inline fun onStateOrSubstate(handler: BehaviourWithFSMStateHandler) { + add(I::class, handler) + } + + /** + * Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that + * for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass + * requirements + * + * @see BehaviourWithFSMStateHandlerHolder + * @see BehaviourContextWithFSMBuilder.addStrict + */ + @Suppress("MemberVisibilityCanBePrivate") + inline fun strictlyOn(handler: BehaviourWithFSMStateHandler) { + addStrict(I::class, handler) + } + /** * Returns completed [resultBehaviourContext], [handlers] and [statesManager] */ @@ -55,61 +80,52 @@ class BehaviourContextWithFSMBuilder internal constructor( } /** - * Add NON STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Non strict means that - * for input [State] will be used [KClass.isInstance] and any inheritor of [kClass] will pass this requirement + * Creates [BehaviourContextWithFSM] via creating of [DefaultBehaviourContext] with [this] as [TelegramBot], + * [scope] as target scope for that [DefaultBehaviourContext] and [upstreamUpdatesFlow]. Pass [statesManager] + * to customize some internal logic of states changes. Pass [presetHandlers] in case you have some list of + * [BehaviourWithFSMStateHandlerHolder] with presets. * - * @see BehaviourWithFSMStateHandlerHolder - * @see BehaviourContextWithFSMBuilder.add - */ -inline fun BehaviourContextWithFSMBuilder.onStateOrSubstate(handler: BehaviourWithFSMStateHandler) { - add(I::class, handler) -} - -/** - * Add STRICT [handler] to list of available in future [BehaviourContextWithFSM]. Strict means that - * for input [State] will be used [State]::class == [kClass] and any [State] with exactly the same type will pass - * requirements - * - * @see BehaviourWithFSMStateHandlerHolder - * @see BehaviourContextWithFSMBuilder.addStrict - */ -inline fun BehaviourContextWithFSMBuilder.strictlyOn(handler: BehaviourWithFSMStateHandler) { - addStrict(I::class, handler) -} - -/** - * Use this factory to create and organize behaviour of your bot with attention to FSM logic. This factory WILL NOT - * start any incoming updates handling of FSM handling, you must start it by yourself - * - * @param upstreamUpdatesFlow Will be used in [BehaviourContextWithFSMBuilder.build] to put it in new [BehaviourContextWithFSM] - * @param scope This [CoroutineScope] will be used in [BehaviourContextWithFSMBuilder.build] to put it in new [BehaviourContextWithFSM] + * !!! WARNING !!! This method WILL NOT call [BehaviourContextWithFSM.start] of result object and WILL NOT + * start any updates retrieving. See [buildBehaviourWithFSMAndStartLongPolling] or + * [telegramBotWithBehaviourAndFSMAndStartLongPolling] in case you wish to start [longPolling] automatically */ suspend fun TelegramBot.buildBehaviourWithFSM( upstreamUpdatesFlow: Flow? = null, scope: CoroutineScope = defaultCoroutineScopeProvider(), - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - handlersPreset: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver -) = BehaviourContextWithFSMBuilder( - DefaultBehaviourContext(this, scope, upstreamUpdatesFlow = upstreamUpdatesFlow), - statesManager, - handlersPreset -).apply { block() }.build() - -/** - * Use this factory to create and organize behaviour of your bot with attention to FSM logic. This factory will start - * listening of updates by [longPolling] - * - * @param upstreamUpdatesFlow Will be used in [BehaviourContextWithFSMBuilder.build] to put it in new [BehaviourContextWithFSM] - * @param scope This [CoroutineScope] will be used in [BehaviourContextWithFSMBuilder.build] to put it in new [BehaviourContextWithFSM] - */ -suspend fun TelegramBot.buildBehaviourWithFSMAndLongPolling( - upstreamUpdatesFlow: Flow? = null, - scope: CoroutineScope = defaultCoroutineScopeProvider(), + defaultExceptionsHandler: ExceptionHandler? = null, statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), presetHandlers: MutableList> = mutableListOf(), block: CustomBehaviourContextReceiver -) = buildBehaviourWithFSM(upstreamUpdatesFlow, scope, statesManager, presetHandlers, block).run { +): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( + DefaultBehaviourContext( + this, + defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, + upstreamUpdatesFlow = upstreamUpdatesFlow + ), + statesManager, + presetHandlers +).apply { block() }.build() + +/** + * Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates + * using [longPolling]. For [longPolling] will be used result [BehaviourContextWithFSM] for both parameters + * flowsUpdatesFilter and scope + */ +suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( + upstreamUpdatesFlow: Flow? = null, + scope: CoroutineScope = defaultCoroutineScopeProvider(), + defaultExceptionsHandler: ExceptionHandler? = null, + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver +): Pair = buildBehaviourWithFSM( + upstreamUpdatesFlow, + scope, + defaultExceptionsHandler, + statesManager, + presetHandlers, + block +).run { this to scope.launch { start() longPolling(flowsUpdatesFilter, scope = scope) @@ -117,16 +133,22 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndLongPolling( } /** + * Creates [BehaviourContextWithFSM] via creating of [DefaultBehaviourContext] with [this] as [TelegramBot], + * [scope] as target scope for that [DefaultBehaviourContext] and [FlowsUpdatesFilter.allUpdatesFlow] of + * [flowUpdatesFilter] as [DefaultBehaviourContext.upstreamUpdatesFlow]. Pass [statesManager] + * to customize some internal logic of states changes. Pass [presetHandlers] in case you have some list of + * [BehaviourWithFSMStateHandlerHolder] with presets. * Use this method in case you wish to make some additional actions with [flowUpdatesFilter]. * - * **WARNING** This method WILL NOT launch any listening of updates. Use something like - * [startGettingOfUpdatesByLongPolling] (or just [longPolling]) or tools for work with webhooks + * !!! WARNING !!! This method WILL NOT call [BehaviourContextWithFSM.start] of result object and WILL NOT + * start any updates retrieving. See [buildBehaviourWithFSMAndStartLongPolling] or + * [telegramBotWithBehaviourAndFSMAndStartLongPolling] in case you wish to start [longPolling] automatically * * @see BehaviourContext * @see BehaviourContextWithFSM * @see longPolling - * @see strictlyOn - * @see onStateOrSubstate + * @see BehaviourContextWithFSMBuilder.strictlyOn + * @see BehaviourContextWithFSMBuilder.onStateOrSubstate */ @PreviewFeature suspend fun TelegramBot.buildBehaviourWithFSM( @@ -137,34 +159,28 @@ suspend fun TelegramBot.buildBehaviourWithFSM( presetHandlers: MutableList> = mutableListOf(), block: CustomBehaviourContextReceiver ): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( - BehaviourContext( + DefaultBehaviourContext( this, - scope.let { - if (defaultExceptionsHandler == null) { - it - } else { - it + ContextSafelyExceptionHandler(defaultExceptionsHandler) - } - }, - flowUpdatesFilter + defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, + upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow ), statesManager, presetHandlers ).apply { block() }.build() /** - * Use this method to build bot behaviour with FSM and run it via long polling. In case you wish to use - * [FlowsUpdatesFilter] of result [BehaviourContextWithFSM] for additional manipulations, you must provide external - * [FlowsUpdatesFilter] in other [buildBehaviourWithFSM] function. + * Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates + * using [longPolling]. For [longPolling] will be used result [BehaviourContextWithFSM] for both parameters + * flowsUpdatesFilter and scope * - * @see buildBehaviourWithFSM + * @see buildBehaviourWithFSMAndStartLongPolling * @see BehaviourContext * @see longPolling - * @see strictlyOn - * @see onStateOrSubstate + * @see BehaviourContextWithFSMBuilder.strictlyOn + * @see BehaviourContextWithFSMBuilder.onStateOrSubstate */ @PreviewFeature -suspend fun TelegramBot.buildBehaviourWithFSM( +suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), diff --git a/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt b/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt index 39f4ba3c69..811039d473 100644 --- a/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt +++ b/tgbotapi.extensions.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt @@ -16,7 +16,7 @@ import kotlin.coroutines.coroutineContext /** - * Create bot using [telegramBot] and start listening for updates using [buildBehaviour]. + * Create bot using [telegramBot] and start listening for updates using [buildBehaviourWithFSM]. * Use this method in case you wish to make some additional actions with [flowsUpdatesFilter]. * * **WARNING** This method WILL NOT launch any listening of updates. Use something like @@ -43,8 +43,8 @@ suspend fun telegramBotWithBehaviourAndFSM( apiUrl, builder ).apply { - buildBehaviourWithFSM( - flowsUpdatesFilter, + buildBehaviourWithFSMAndStartLongPolling( + flowsUpdatesFilter.allUpdatesFlow, scope ?: CoroutineScope(coroutineContext), defaultExceptionsHandler, statesManager, @@ -67,7 +67,7 @@ suspend fun telegramBotWithBehaviourAndFSM( * @see [buildBehaviour] * @see startGettingOfUpdatesByLongPolling */ -suspend fun telegramBotWithBehaviourAndFSM( +suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling( token: String, scope: CoroutineScope? = null, apiUrl: String = telegramBotAPIDefaultUrl, @@ -82,7 +82,7 @@ suspend fun telegramBotWithBehaviourAndFSM( apiUrl, builder ).let { - it to it.buildBehaviourWithFSM ( + it to it.buildBehaviourWithFSMAndStartLongPolling ( scope ?: CoroutineScope(coroutineContext), defaultExceptionsHandler, statesManager, diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt index 11fdc2142b..0b62483ba6 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt @@ -67,8 +67,8 @@ interface BehaviourContext : FlowsUpdatesFilter, TelegramBot, CoroutineScope { class DefaultBehaviourContext( override val bot: TelegramBot, override val scope: CoroutineScope, - private val broadcastChannelsSize: Int = 100, - private val onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND, + broadcastChannelsSize: Int = 100, + onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND, private val upstreamUpdatesFlow: Flow? = null, private val updatesFilter: BehaviourContextAndTypeReceiver? = null ) : AbstractFlowsUpdatesFilter(), TelegramBot by bot, CoroutineScope by scope, BehaviourContext {