1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-09-04 07:39:39 +00:00

packages update

This commit is contained in:
2021-10-18 15:20:25 +06:00
parent 91212eaa3a
commit e60eb68b67
235 changed files with 681 additions and 109 deletions

View File

@@ -0,0 +1,8 @@
# TelegramBotAPI Behaviour Builder FSM Extensions
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder.fsm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder.fsm)
This extension has been created to integrate finite state machine in [BehaviourBuilder](../tgbotapi.extensions.behaviour_builder/README.md).
In case you wish to use some custom store for steps (states), you may extend `StatesManager` or use `DefaultStatesManager`
with custom `DefaultStatesManagerRepo`. See [Examples repo](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/tree/master/FSMBot)
to get more info and see how it works on base level

View File

@@ -0,0 +1,50 @@
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
project.version = "$library_version"
project.group = "$library_group"
apply from: "publish.gradle"
repositories {
mavenLocal()
mavenCentral()
}
kotlin {
jvm()
js(IR) {
browser()
nodejs()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
api project(":tgbotapi.behaviour_builder")
api "dev.inmo:micro_utils.fsm.common:$micro_utils_version"
}
}
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
}
}

View File

@@ -0,0 +1 @@
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot Behaviour Builder FSM Extensions","description":"FSM extension for dev.inmo:tgbotapi.extensions.behaviour_builder.fsm","url":"https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.behaviour_builder","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/TelegramBotAPI"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}]}}

View File

@@ -0,0 +1,69 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "FSM extension for dev.inmo:tgbotapi.extensions.behaviour_builder.fsm"
name = "Telegram Bot Behaviour Builder FSM Extensions"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.behaviour_builder"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
maven {
name = "GithubPackages"
url = uri("https://maven.pkg.github.com/InsanusMokrassar/TelegramBotAPI")
credentials {
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
}
}
}
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
}
}
}
}
signing {
useGpgCmd()
sign publishing.publications
}

View File

@@ -0,0 +1,113 @@
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.fsm.common.*
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.micro_utils.coroutines.accumulatorFlow
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.*
private suspend fun <I : State> BehaviourContextWithFSM.launchStateHandling(
state: State,
contextUpdatesFlow: Flow<Update>,
handlers: List<BehaviourWithFSMStateHandlerHolder<out I>>
): State? {
return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
handleState(contextUpdatesFlow, state)
}
}
/**
* Interface which combine [BehaviourContext] and [StatesMachine]. Subcontext of triggers and states contexts must have
* one common flow of updates and must not lose updates between updates
*
* @see DefaultBehaviourContextWithFSM
* @see buildBehaviourWithFSM
*/
interface BehaviourContextWithFSM : BehaviourContext, StatesMachine {
suspend fun start() = start(this)
override fun copy(
bot: TelegramBot,
scope: CoroutineScope,
broadcastChannelsSize: Int,
onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM
companion object {
operator fun invoke(
behaviourContext: BehaviourContext,
handlers: List<BehaviourWithFSMStateHandlerHolder<*>>,
statesManager: StatesManager
) = DefaultBehaviourContextWithFSM(behaviourContext, statesManager, handlers)
}
}
/**
* 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
*/
class DefaultBehaviourContextWithFSM(
private val behaviourContext: BehaviourContext,
private val statesManager: StatesManager,
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*>>
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM {
private val updatesFlows = mutableMapOf<Any, Flow<Update>>()
private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) {
allUpdatesFlow.accumulatorFlow(scope)
}
override suspend fun StatesMachine.handleState(state: State): State? = launchStateHandling(
state,
allUpdatesFlow,
handlers
)
override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions {
val statePerformer: suspend (State) -> Unit = { state: State ->
val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), handlers)
if (newState != null) {
statesManager.update(state, newState)
} else {
statesManager.endChain(state)
}
}
statesManager.onStartChain.subscribeSafelyWithoutExceptions(this) {
launch { statePerformer(it) }
}
statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(this) { (old, new) ->
if (old.context != new.context) {
updatesFlows.remove(old.context)
}
launch { statePerformer(new) }
}
statesManager.onEndChain.subscribeSafelyWithoutExceptions(this) {
updatesFlows.remove(it.context)
}
statesManager.getActiveStates().forEach {
launch { statePerformer(it) }
}
}
override suspend fun startChain(state: State) {
statesManager.startChain(state)
}
override fun copy(
bot: TelegramBot,
scope: CoroutineScope,
broadcastChannelsSize: Int,
onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM = BehaviourContextWithFSM(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter),
handlers,
statesManager
)
}

View File

@@ -0,0 +1,204 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
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
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
class BehaviourContextWithFSMBuilder internal constructor(
private val resultBehaviourContext: BehaviourContextWithFSM,
private val handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>>
) : BehaviourContextWithFSM by resultBehaviourContext {
internal constructor(
baseBehaviourContext: BehaviourContext,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf()
) : this(DefaultBehaviourContextWithFSM(baseBehaviourContext, statesManager, handlers), handlers)
/**
* 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 onStateOrSubstate
*/
fun <I : State> add(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I>) {
handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, false, 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 strictlyOn
*/
fun <I : State> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I>) {
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 <reified I : State> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I>) {
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 <reified I : State> strictlyOn(handler: BehaviourWithFSMStateHandler<I>) {
addStrict(I::class, handler)
}
/**
* Returns completed [resultBehaviourContext], [handlers] and [statesManager]
*/
internal fun build() = resultBehaviourContext
}
/**
* 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.
*
* !!! 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<Update>? = null,
scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit>
): 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<Update>? = null,
scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit>
): Pair<BehaviourContextWithFSM, Job> = buildBehaviourWithFSM(
upstreamUpdatesFlow,
scope,
defaultExceptionsHandler,
statesManager,
presetHandlers,
block
).run {
this to scope.launch {
start()
longPolling(flowsUpdatesFilter, scope = scope)
}
}
/**
* 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 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 BehaviourContextWithFSMBuilder.strictlyOn
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate
*/
@PreviewFeature
suspend fun TelegramBot.buildBehaviourWithFSM(
flowUpdatesFilter: FlowsUpdatesFilter,
scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit>
): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder(
DefaultBehaviourContext(
this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope,
upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow
),
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
*
* @see buildBehaviourWithFSMAndStartLongPolling
* @see BehaviourContext
* @see longPolling
* @see BehaviourContextWithFSMBuilder.strictlyOn
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate
*/
@PreviewFeature
suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit>
) = FlowsUpdatesFilter().let {
buildBehaviourWithFSM(
it,
scope,
defaultExceptionsHandler,
statesManager,
presetHandlers,
block
).run {
start()
longPolling(
flowsUpdatesFilter,
scope = scope
)
}
}

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
import dev.inmo.micro_utils.fsm.common.*
fun interface BehaviourWithFSMStateHandler<T : State> {
suspend fun BehaviourContextWithFSM.handleState(state: T): State?
}

View File

@@ -0,0 +1,52 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope
import dev.inmo.micro_utils.coroutines.weakLaunch
import dev.inmo.micro_utils.fsm.common.*
import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlin.reflect.KClass
/**
* Special holder for [BehaviourContextWithFSM]. This holder helps [BehaviourContextWithFSM] to understand whether it
* can handle input [State] with [delegateTo] or not
*
* @param inputKlass This [KClass] will be used to compare input [State] type and declare ability of [delegateTo] to
* handle incoming [State]. See [checkHandleable] for more info
* @param strict This flag will be used in [checkHandleable] to choose strategy of checking incoming [State]
* @param delegateTo This handler will be called in case [checkHandleable] returns true with class caster incoming
* [State] in [handleState]
*/
class BehaviourWithFSMStateHandlerHolder<I : State>(
private val inputKlass: KClass<I>,
private val strict: Boolean = false,
private val delegateTo: BehaviourWithFSMStateHandler<I>
) {
/**
* Check ability of [delegateTo] to handle this [state]
*
* @return When [state]::class exactly equals to [inputKlass] will always return true. Otherwise when [strict]
* mode is disabled, will be used [KClass.isInstance] of [inputKlass] for checking
*/
fun checkHandleable(state: State) = state::class == inputKlass || (!strict && inputKlass.isInstance(state))
/**
* Handling of state :)
*
* @param contextUpdatesFlow This [Flow] will be used as source of updates. By contract, this [Flow] must be common
* for all [State]s of incoming [state] [State.context] and for the whole chain inside of [BehaviourContextWithFSM]
*/
suspend fun BehaviourContextWithFSM.handleState(
contextUpdatesFlow: Flow<Update>,
state: State
): State? {
val subscope = scope.LinkedSupervisorScope()
return with(copy(scope = subscope, upstreamUpdatesFlow = contextUpdatesFlow)) {
with(delegateTo) {
handleState(state as I)
}
}
}
}

View File

@@ -0,0 +1,90 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
import dev.inmo.micro_utils.coroutines.ExceptionHandler
import dev.inmo.micro_utils.fsm.common.StatesManager
import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager
import dev.inmo.micro_utils.fsm.common.managers.InMemoryDefaultStatesManagerRepo
import dev.inmo.tgbotapi.bot.Ktor.KtorRequestsExecutorBuilder
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.coroutineContext
/**
* 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
* [startGettingOfUpdatesByLongPolling] or tools for work with webhooks
*
* @return Created bot which has been used to create [BehaviourContext] via [buildBehaviour]
*
* @see [BehaviourContext]
* @see [buildBehaviour]
* @see startGettingOfUpdatesByLongPolling
*/
suspend fun telegramBotWithBehaviourAndFSM(
token: String,
flowsUpdatesFilter: FlowsUpdatesFilter,
scope: CoroutineScope? = null,
apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit>
): TelegramBot = telegramBot(
token,
apiUrl,
builder
).apply {
buildBehaviourWithFSMAndStartLongPolling(
flowsUpdatesFilter.allUpdatesFlow,
scope ?: CoroutineScope(coroutineContext),
defaultExceptionsHandler,
statesManager,
presetHandlers,
block
)
}
/**
* Create bot using [telegramBot] and start listening for updates using [buildBehaviourWithFSMAndStartLongPolling]. This
* method will launch updates retrieving via long polling inside of [buildBehaviourWithFSMAndStartLongPolling]
*
* @return Pair of [TelegramBot] and [Job]. This [Job] can be used to stop listening updates in your [block] you passed
* here
*
* @see [BehaviourContext]
* @see [buildBehaviour]
* @see startGettingOfUpdatesByLongPolling
*/
suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling(
token: String,
scope: CoroutineScope? = null,
apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit>
): Pair<TelegramBot, Job> {
return telegramBot(
token,
apiUrl,
builder
).let {
it to it.buildBehaviourWithFSMAndStartLongPolling (
scope ?: CoroutineScope(coroutineContext),
defaultExceptionsHandler,
statesManager,
presetHandlers,
block
)
}
}