1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-18 21:45:06 +00:00

Compare commits

..

7 Commits
1.1.2 ... 1.1.4

9 changed files with 96 additions and 40 deletions

View File

@@ -1,5 +1,15 @@
# TelegramBotAPI changelog
## 1.1.4
* `Behaviour Builder`:
* Improvements in updates passing inside of subcontexts
## 1.1.3
* `Behaviour Builder with FSM`:
* Typealias `StateHandlingErrorHandler` from `1.1.2` has been deprecated and should be replaced with the new one from microutils
## 1.1.2
* `Core`:

View File

@@ -12,7 +12,7 @@ korlibs_version=2.7.0
uuid_version=0.4.0
ktor_version=2.0.1
micro_utils_version=0.10.4
micro_utils_version=0.10.5
javax_activation_version=1.1.1
@@ -20,6 +20,6 @@ javax_activation_version=1.1.1
dokka_version=1.6.21
library_group=dev.inmo
library_version=1.1.2
library_version=1.1.4
github_release_plugin_version=2.3.7

View File

@@ -2,6 +2,8 @@ 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.utils.StateHandlingErrorHandler
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar.TriggersHolder
@@ -116,11 +118,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
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)
}
return launchStateHandling(state, handlers, onStateHandlingErrorHandler)
}
private fun getSubContext(context: Any) = updatesFlows.getOrPut(context) {

View File

@@ -4,6 +4,8 @@ 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.micro_utils.fsm.common.utils.StateHandlingErrorHandler
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
import dev.inmo.tgbotapi.types.update.abstracts.Update

View File

@@ -1,5 +1,10 @@
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>
import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler
@Deprecated("Has been added in microutils", ReplaceWith("StateHandlingErrorHandler", "dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler"))
typealias StateHandlingErrorHandler<T> = StateHandlingErrorHandler<T>
@Deprecated("Has been added in microutils", ReplaceWith("DefaultStateHandlingErrorHandler", "dev.inmo.micro_utils.fsm.common.utils.DefaultStateHandlingErrorHandler"))
val DefaultStateHandlingErrorHandler = dev.inmo.micro_utils.fsm.common.utils.DefaultStateHandlingErrorHandler
@Deprecated("Has been added in microutils", ReplaceWith("defaultStateHandlingErrorHandler", "dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler"))
inline fun <T> defaultStateHandlingErrorHandler() = dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler<T>()

View File

@@ -5,6 +5,8 @@ import dev.inmo.micro_utils.fsm.common.State
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.micro_utils.fsm.common.utils.StateHandlingErrorHandler
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
import dev.inmo.tgbotapi.bot.ktor.KtorRequestsExecutorBuilder
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.bot.TelegramBot

View File

@@ -49,6 +49,19 @@ interface BehaviourContext : FlowsUpdatesFilter, TelegramBot, CoroutineScope {
val triggersHolder: TriggersHolder
fun copy(
bot: TelegramBot = this.bot,
scope: CoroutineScope = this.scope,
broadcastChannelsSize: Int = 100,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND,
upstreamUpdatesFlow: Flow<Update>? = null,
triggersHolder: TriggersHolder = TriggersHolder()
): BehaviourContext
/**
* @param updatesFilter unused
*/
@Deprecated("Do not use this method")
fun copy(
bot: TelegramBot = this.bot,
scope: CoroutineScope = this.scope,
@@ -57,7 +70,7 @@ interface BehaviourContext : FlowsUpdatesFilter, TelegramBot, CoroutineScope {
upstreamUpdatesFlow: Flow<Update>? = null,
triggersHolder: TriggersHolder = TriggersHolder(),
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? = null
): BehaviourContext
): BehaviourContext = copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder)
}
class DefaultBehaviourContext(
@@ -67,20 +80,17 @@ class DefaultBehaviourContext(
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND,
private val upstreamUpdatesFlow: Flow<Update>? = null,
override val triggersHolder: TriggersHolder = TriggersHolder(),
@Deprecated("This method is not used anymore")
private val updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? = null
) : AbstractFlowsUpdatesFilter(), TelegramBot by bot, CoroutineScope by scope, BehaviourContext {
private val additionalUpdatesSharedFlow = MutableSharedFlow<Update>(0, broadcastChannelsSize, onBufferOverflow)
override val allUpdatesFlow: Flow<Update> = (additionalUpdatesSharedFlow.asSharedFlow()).let {
if (upstreamUpdatesFlow != null) {
(it + upstreamUpdatesFlow).distinctUntilChanged { old, new -> old.updateId == new.updateId }
} else {
it
}
}.let {
val updatesFilter = updatesFilter
if (updatesFilter != null) {
it.filter { updatesFilter(it) }
var lastHandledUpdate = -1L
(it + upstreamUpdatesFlow).filter {
(it.updateId > lastHandledUpdate).also { passed -> if (passed) { lastHandledUpdate = it.updateId } }
}
} else {
it
}
@@ -93,9 +103,8 @@ class DefaultBehaviourContext(
broadcastChannelsSize: Int,
onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?,
triggersHolder: TriggersHolder,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): DefaultBehaviourContext = DefaultBehaviourContext(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder, updatesFilter)
triggersHolder: TriggersHolder
): DefaultBehaviourContext = DefaultBehaviourContext(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder)
}
fun BehaviourContext(
@@ -113,24 +122,34 @@ inline fun <T> BehaviourContext(
crossinline block: BehaviourContext.() -> T
) = DefaultBehaviourContext(bot, scope, upstreamUpdatesFlow = flowsUpdatesFilter.allUpdatesFlow, triggersHolder = triggersHolder).run(block)
/**
* Creates new [BehaviourContext] using its [BehaviourContext.copy] method
*
* @param updatesFilter This param will not be used anymore
*/
fun <BC : BehaviourContext> BC.createSubContext(
scope: CoroutineScope = LinkedSupervisorScope(),
triggersHolder: TriggersHolder = this.triggersHolder,
updatesUpstreamFlow: Flow<Update> = allUpdatesFlow,
updatesFilter: CustomBehaviourContextAndTypeReceiver<BC, Boolean, Update>? = null,
) = copy(
scope = scope,
updatesFilter = updatesFilter ?.let { _ ->
{
(this as? BC) ?.run {
updatesFilter(it)
} ?: true
}
},
upstreamUpdatesFlow = updatesUpstreamFlow,
triggersHolder = triggersHolder
) as BC
/**
* Creates new [BehaviourContext] using its [BehaviourContext.copy] method
*
* @param updatesFilter This param will not be used anymore
*/
@Deprecated("It is not recommended to use updates filter anymore")
fun <BC : BehaviourContext> BC.createSubContext(
scope: CoroutineScope = LinkedSupervisorScope(),
triggersHolder: TriggersHolder = this.triggersHolder,
updatesUpstreamFlow: Flow<Update> = allUpdatesFlow,
updatesFilter: CustomBehaviourContextAndTypeReceiver<BC, Boolean, Update>?,
) = createSubContext(scope, triggersHolder, updatesUpstreamFlow)
/**
* Launch [behaviourContextReceiver] in context of [this] as [BehaviourContext] and as [kotlin.coroutines.CoroutineContext]
*
@@ -155,21 +174,40 @@ suspend fun <T, BC : BehaviourContext> BC.createSubContextAndDoWithUpdatesFilter
scope: CoroutineScope = LinkedSupervisorScope(),
triggersHolder: TriggersHolder = this.triggersHolder,
updatesUpstreamFlow: Flow<Update> = allUpdatesFlow,
updatesFilter: CustomBehaviourContextAndTypeReceiver<BC, Boolean, Update>? = null,
stopOnCompletion: Boolean = true,
behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T>
): T {
return createSubContext(
scope,
triggersHolder,
updatesUpstreamFlow,
updatesFilter
updatesUpstreamFlow
).doInContext(
stopOnCompletion,
behaviourContextReceiver
)
}
/**
* Creates new one [BehaviourContext] using [createSubContext] and launches [behaviourContextReceiver] in a new context
* using [doInContext]
*
* @param stopOnCompletion ___TRUE BY DEFAULT___
* @param updatesFilter Is not used anymore
*/
@Deprecated("It is not recommended to use updates filter anymore")
suspend fun <T, BC : BehaviourContext> BC.createSubContextAndDoWithUpdatesFilter(
scope: CoroutineScope = LinkedSupervisorScope(),
triggersHolder: TriggersHolder = this.triggersHolder,
updatesUpstreamFlow: Flow<Update> = allUpdatesFlow,
updatesFilter: CustomBehaviourContextAndTypeReceiver<BC, Boolean, Update>?,
stopOnCompletion: Boolean = true,
behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T>
): T {
return createSubContextAndDoWithUpdatesFilter(
scope, triggersHolder, updatesUpstreamFlow, stopOnCompletion, behaviourContextReceiver
)
}
/**
* Creates new one [BehaviourContext] using [createSubContext] and launches [behaviourContextReceiver] in a new context
* using [doInContext]

View File

@@ -22,8 +22,8 @@ private suspend fun <O> BehaviourContext.waitCallbackQueries(
count,
errorFactory
) {
val data = it.asCallbackQueryUpdate() ?.data
if (data != null && (filter == null || filter(data))) {
val data = it.asCallbackQueryUpdate() ?.data ?: return@expectFlow emptyList()
if (filter == null || filter(data)) {
data.mapper().let(::listOfNotNull)
} else {
emptyList()

View File

@@ -15,16 +15,17 @@ internal suspend inline fun <BC : BehaviourContext, reified T> BC.on(
noinline updateToData: (Update) -> List<T>?
) = flowsUpdatesFilter.expectFlow(bot) {
updateToData(it) ?.mapNotNull { data ->
if (initialFilter ?.invoke(data) != false) data else null
if (initialFilter ?.invoke(data) != false) it to data else null
} ?: emptyList()
}.subscribeSafelyWithoutExceptionsAsync(
scope,
markerFactory::invoke
) { triggerData ->
{ markerFactory(it.second) }
) { (update, triggerData) ->
createSubContextAndDoWithUpdatesFilter(
updatesFilter = subcontextUpdatesFilter ?.toOneType(triggerData),
stopOnCompletion = false
) {
scenarioReceiver(triggerData)
if (subcontextUpdatesFilter ?.invoke(this, triggerData, update) != false) {
scenarioReceiver(triggerData)
}
}
}