mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-12-08 15:25:52 +00:00
Compare commits
17 Commits
df01976ea8
...
1.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e73aac750 | |||
| 82c6eda0b7 | |||
| e9ff93cde1 | |||
| 9b179ea1c9 | |||
| 72d20d2344 | |||
| bcd288fe05 | |||
| 75477060e9 | |||
| 60df609486 | |||
| 556b492b35 | |||
| 53e8c53fb1 | |||
| 69d36c5c1b | |||
| ad97008f12 | |||
| 3e58114eeb | |||
| d55d8fa000 | |||
| bd32dbb3ab | |||
| 8e0389f032 | |||
| cb37b85234 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,9 +1,24 @@
|
||||
# TelegramBotAPI changelog
|
||||
|
||||
## 1.1.0
|
||||
|
||||
* `Utils`:
|
||||
* New parameter `additionalApplicationEngineEnvironmentConfigurator` in `RequestsExecutor#setWebhookInfoAndStartListenWebhooks` and `startListenWebhooks`
|
||||
|
||||
## 1.0.1
|
||||
|
||||
* `Versions`:
|
||||
* `Serialization`: `1.3.2` -> `1.3.3`
|
||||
* `MicroUtils`: `0.10.3` -> `0.10.4`
|
||||
|
||||
## 1.0.0
|
||||
|
||||
__All the `tgbotapi.extensions.*` packages have been removed__
|
||||
|
||||
* `Versions`:
|
||||
* `Kotlin`: `1.6.10` -> `1.6.21`
|
||||
* `Ktor`: `1.6.8` -> `2.0.1`
|
||||
* `MicroUtils`: `0.9.24` -> `0.10.3`
|
||||
* `Core`:
|
||||
* **`Ktor` package renamed. Migration:** `dev.inmo.tgbotapi.bot.Ktor` -> `dev.inmo.tgbotapi.bot.ktor`
|
||||
* **`CallbackQuery` package renamed. Migration:** `dev.inmo.tgbotapi.types.CallbackQuery([\s\\.])` -> `dev.inmo.tgbotapi.types.queries.callback$1`
|
||||
@@ -46,6 +61,16 @@ __All the `tgbotapi.extensions.*` packages have been removed__
|
||||
* New typealias `FileUrl` (represents `FileId` but declare that they are the same)
|
||||
* `BehaviourBuilder`:
|
||||
* `SimpleFilter` now is a `fun interface` instead of just callback (fix of [#546](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/546))
|
||||
* New extension `BehaviourContext#createSubContext`. It uses separated `AccumulatorFlow` and will retrieve updates by itself
|
||||
* New extension `BehaviourContext#doInContext`
|
||||
* Extension `BehaviourContext#doInSubContextWithUpdatesFilter` has been renamed to `BehaviourContext#createSubContextAndDoWithUpdatesFilter`
|
||||
* Extension `BehaviourContext#doInSubContext` has been deprecated
|
||||
* `BehaviourContextWithFSM`:
|
||||
* `launchStateHandling` lost its parameter `contextUpdatesFlow: Flow`
|
||||
* `handleState` of `BehaviourContextWithFSM` now will get/create sub context for the state and launch handling in it
|
||||
* `BehaviourWithFSMStateHandler` now extends `StatesHandler`
|
||||
* `BehaviourWithFSMStateHandlerHolder` now extends `CheckableHandlerHolder` and `BehaviourWithFSMStateHandler`
|
||||
* Function `checkHandleable` of `BehaviourWithFSMStateHandlerHolder` now is `suspend`
|
||||
|
||||
## 0.38.23
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ kotlin.incremental.js=true
|
||||
|
||||
kotlin_version=1.6.21
|
||||
kotlin_coroutines_version=1.6.1
|
||||
kotlin_serialisation_runtime_version=1.3.2
|
||||
kotlin_serialisation_runtime_version=1.3.3
|
||||
klock_version=2.7.0
|
||||
uuid_version=0.4.0
|
||||
ktor_version=2.0.1
|
||||
|
||||
micro_utils_version=0.10.1
|
||||
micro_utils_version=0.10.4
|
||||
|
||||
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.0.0
|
||||
library_version=1.1.0
|
||||
|
||||
github_release_plugin_version=2.3.7
|
||||
|
||||
@@ -5,12 +5,10 @@ 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 dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar.TriggersHolder
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
@@ -23,18 +21,6 @@ import kotlin.reflect.KClass
|
||||
interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T> {
|
||||
suspend fun start() = start(this)
|
||||
|
||||
suspend fun launchStateHandling(
|
||||
state: T,
|
||||
contextUpdatesFlow: Flow<Update>,
|
||||
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
|
||||
): T? {
|
||||
return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
|
||||
doInSubContext(updatesUpstreamFlow = contextUpdatesFlow) {
|
||||
handleState(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -104,19 +90,22 @@ class DefaultBehaviourContextWithFSM<T : State>(
|
||||
private val statesManager: StatesManager<T>,
|
||||
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
|
||||
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
|
||||
private val updatesFlows = mutableMapOf<Any, Flow<Update>>()
|
||||
private val updatesFlows = mutableMapOf<Any, DefaultBehaviourContextWithFSM<T>>()
|
||||
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
|
||||
private var actualHandlersList = additionalHandlers + handlers
|
||||
|
||||
private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) {
|
||||
allUpdatesFlow.accumulatorFlow(scope)
|
||||
private fun getSubContext(context: Any) = updatesFlows.getOrPut(context) {
|
||||
createSubContext()
|
||||
}
|
||||
|
||||
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(
|
||||
state,
|
||||
allUpdatesFlow,
|
||||
actualHandlersList
|
||||
)
|
||||
override suspend fun StatesMachine<in T>.handleState(state: T): T? {
|
||||
return getSubContext(
|
||||
state.context
|
||||
).launchStateHandling(
|
||||
state,
|
||||
actualHandlersList
|
||||
)
|
||||
}
|
||||
|
||||
override fun <I : T> add(kClass: KClass<I>, strict: Boolean, handler: BehaviourWithFSMStateHandler<I, T>) {
|
||||
additionalHandlers.add(BehaviourWithFSMStateHandlerHolder(kClass, strict, handler))
|
||||
@@ -125,7 +114,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
|
||||
|
||||
override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions {
|
||||
val statePerformer: suspend (T) -> Unit = { state: T ->
|
||||
val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), actualHandlersList)
|
||||
val newState = getSubContext(state.context).launchStateHandling(state, actualHandlersList)
|
||||
if (newState != null) {
|
||||
statesManager.update(state, newState)
|
||||
} else {
|
||||
|
||||
@@ -88,7 +88,6 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
|
||||
* @see BehaviourContextWithFSM.strictlyOn
|
||||
* @see BehaviourContextWithFSM.onStateOrSubstate
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
|
||||
flowUpdatesFilter: FlowsUpdatesFilter,
|
||||
scope: CoroutineScope = defaultCoroutineScopeProvider(),
|
||||
@@ -117,7 +116,6 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
|
||||
* @see BehaviourContextWithFSM.strictlyOn
|
||||
* @see BehaviourContextWithFSM.onStateOrSubstate
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
|
||||
scope: CoroutineScope = defaultCoroutineScopeProvider(),
|
||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||
|
||||
@@ -2,6 +2,12 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder
|
||||
|
||||
import dev.inmo.micro_utils.fsm.common.*
|
||||
|
||||
fun interface BehaviourWithFSMStateHandler<I : O, O : State> {
|
||||
fun interface BehaviourWithFSMStateHandler<I : O, O : State> : StatesHandler<I, O> {
|
||||
suspend fun BehaviourContextWithFSM<in O>.handleState(state: I): O?
|
||||
|
||||
override suspend fun StatesMachine<in O>.handleState(state: I): O? = if (this is BehaviourContextWithFSM) {
|
||||
handleState(state)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -23,21 +17,25 @@ class BehaviourWithFSMStateHandlerHolder<I : O, O : State>(
|
||||
private val inputKlass: KClass<I>,
|
||||
private val strict: Boolean = false,
|
||||
private val delegateTo: BehaviourWithFSMStateHandler<I, O>
|
||||
) {
|
||||
) : CheckableHandlerHolder<O, O>, BehaviourWithFSMStateHandler<O, O> {
|
||||
/**
|
||||
* 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: O): Boolean = state::class == inputKlass || (!strict && inputKlass.isInstance(state))
|
||||
override suspend fun checkHandleable(state: O): Boolean = state::class == inputKlass || (!strict && inputKlass.isInstance(state))
|
||||
|
||||
/**
|
||||
* Handling of state :)
|
||||
*/
|
||||
suspend fun BehaviourContextWithFSM<in O>.handleState(
|
||||
state: O
|
||||
): O? = with(delegateTo) {
|
||||
override suspend fun BehaviourContextWithFSM<in O>.handleState(state: O): O? = with(delegateTo) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
handleState(state as I)
|
||||
}
|
||||
|
||||
override suspend fun StatesMachine<in O>.handleState(state: O): O? = with(delegateTo) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
handleState(state as I)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ expect var defaultCoroutineScopeProvider: () -> CoroutineScope
|
||||
* @see [BehaviourContext]
|
||||
* @see startGettingOfUpdatesByLongPolling
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun TelegramBot.buildBehaviour(
|
||||
flowUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(),
|
||||
scope: CoroutineScope = defaultCoroutineScopeProvider(),
|
||||
@@ -53,7 +52,6 @@ suspend fun TelegramBot.buildBehaviour(
|
||||
* @see BehaviourContext
|
||||
* @see startGettingOfUpdatesByLongPolling
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun TelegramBot.buildBehaviourWithLongPolling(
|
||||
scope: CoroutineScope = defaultCoroutineScopeProvider(),
|
||||
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
|
||||
|
||||
@@ -84,7 +84,7 @@ class DefaultBehaviourContext(
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}.accumulatorFlow(scope)
|
||||
override val asUpdateReceiver: UpdateReceiver<Update> = additionalUpdatesSharedFlow::emit
|
||||
|
||||
override fun copy(
|
||||
@@ -113,10 +113,70 @@ inline fun <T> BehaviourContext(
|
||||
crossinline block: BehaviourContext.() -> T
|
||||
) = DefaultBehaviourContext(bot, scope, upstreamUpdatesFlow = flowsUpdatesFilter.allUpdatesFlow, triggersHolder = triggersHolder).run(block)
|
||||
|
||||
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 one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [updatesFilter] is provided and
|
||||
* [CoroutineScope] as new [BehaviourContext.scope]
|
||||
* Launch [behaviourContextReceiver] in context of [this] as [BehaviourContext] and as [kotlin.coroutines.CoroutineContext]
|
||||
*
|
||||
* @param stopOnCompletion ___FALSE BY DEFAULT___. Will stop [this] in case if passed true
|
||||
*/
|
||||
suspend fun <T, BC : BehaviourContext> BC.doInContext(
|
||||
stopOnCompletion: Boolean = false,
|
||||
behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T>
|
||||
): T {
|
||||
return withContext(coroutineContext) {
|
||||
behaviourContextReceiver().also { if (stopOnCompletion) stop() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new one [BehaviourContext] using [createSubContext] and launches [behaviourContextReceiver] in a new context
|
||||
* using [doInContext]
|
||||
*
|
||||
* @param stopOnCompletion ___TRUE BY DEFAULT___
|
||||
*/
|
||||
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
|
||||
).doInContext(
|
||||
stopOnCompletion,
|
||||
behaviourContextReceiver
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new one [BehaviourContext] using [createSubContext] and launches [behaviourContextReceiver] in a new context
|
||||
* using [doInContext]
|
||||
*
|
||||
* @param stopOnCompletion ___TRUE BY DEFAULT___
|
||||
*/
|
||||
@Deprecated("Renamed", ReplaceWith("createSubContextAndDoWithUpdatesFilter", "dev.inmo.tgbotapi.extensions.behaviour_builder.createSubContextAndDoWithUpdatesFilter"))
|
||||
suspend fun <T, BC : BehaviourContext> BC.doInSubContextWithUpdatesFilter(
|
||||
updatesFilter: CustomBehaviourContextAndTypeReceiver<BC, Boolean, Update>?,
|
||||
stopOnCompletion: Boolean = true,
|
||||
@@ -125,30 +185,32 @@ suspend fun <T, BC : BehaviourContext> BC.doInSubContextWithUpdatesFilter(
|
||||
triggersHolder: TriggersHolder = this.triggersHolder,
|
||||
behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T>
|
||||
): T {
|
||||
val newContext = copy(
|
||||
scope = scope,
|
||||
updatesFilter = updatesFilter ?.let { _ ->
|
||||
{
|
||||
(this as? BC) ?.run {
|
||||
updatesFilter(it)
|
||||
} ?: true
|
||||
}
|
||||
},
|
||||
upstreamUpdatesFlow = updatesUpstreamFlow,
|
||||
triggersHolder = triggersHolder
|
||||
) as BC
|
||||
return withContext(currentCoroutineContext()) {
|
||||
newContext.behaviourContextReceiver().also { if (stopOnCompletion) newContext.stop() }
|
||||
}
|
||||
return createSubContext(
|
||||
scope,
|
||||
triggersHolder,
|
||||
updatesUpstreamFlow,
|
||||
updatesFilter
|
||||
).doInContext(
|
||||
stopOnCompletion,
|
||||
behaviourContextReceiver
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Redundant", ReplaceWith("createSubContextAndDoWithUpdatesFilter", "dev.inmo.tgbotapi.extensions.behaviour_builder.createSubContextAndDoWithUpdatesFilter"))
|
||||
suspend fun <T> BehaviourContext.doInSubContext(
|
||||
stopOnCompletion: Boolean = true,
|
||||
updatesUpstreamFlow: Flow<Update> = allUpdatesFlow,
|
||||
scope: CoroutineScope = LinkedSupervisorScope(),
|
||||
triggersHolder: TriggersHolder = this.triggersHolder,
|
||||
behaviourContextReceiver: BehaviourContextReceiver<T>
|
||||
) = doInSubContextWithUpdatesFilter(updatesFilter = null, stopOnCompletion, updatesUpstreamFlow, scope, triggersHolder, behaviourContextReceiver)
|
||||
) = createSubContextAndDoWithUpdatesFilter(
|
||||
scope,
|
||||
triggersHolder,
|
||||
updatesUpstreamFlow,
|
||||
updatesFilter = null,
|
||||
stopOnCompletion,
|
||||
behaviourContextReceiver
|
||||
)
|
||||
|
||||
/**
|
||||
* This method will cancel ALL subsequent contexts, expectations and waiters
|
||||
|
||||
@@ -36,7 +36,7 @@ internal suspend fun <O : MessageContent> BehaviourContext.waitCommonMessage(
|
||||
val messages = when (it) {
|
||||
is SentMediaGroupUpdate -> {
|
||||
if (includeMediaGroups) {
|
||||
it.data.map { it as CommonMessage<MessageContent> }
|
||||
it.data
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
@@ -45,7 +45,8 @@ internal suspend fun <O : MessageContent> BehaviourContext.waitCommonMessage(
|
||||
else -> return@expectFlow emptyList()
|
||||
}
|
||||
messages.mapNotNull { message ->
|
||||
val asCommonMessage = message as CommonMessage<MessageContent>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val asCommonMessage = message as? CommonMessage<MessageContent> ?: return@mapNotNull null
|
||||
if (filter == null || filter(asCommonMessage)) {
|
||||
asCommonMessage.mapper()
|
||||
} else {
|
||||
|
||||
@@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.toList
|
||||
|
||||
typealias MediaGroupFilter<T> = suspend List<MediaGroupMessage<T>>.() -> Boolean
|
||||
|
||||
@PreviewFeature
|
||||
internal suspend inline fun <reified T : MediaGroupContent> BehaviourContext.buildMediaGroupWaiter(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
|
||||
@@ -45,14 +45,10 @@ private suspend inline fun BehaviourContext.waitPollAnswers(
|
||||
}
|
||||
}
|
||||
) {
|
||||
if (this is PollAnswer) {
|
||||
if (mapper == null) {
|
||||
this
|
||||
} else {
|
||||
mapper(this)
|
||||
}
|
||||
if (mapper == null) {
|
||||
this
|
||||
} else {
|
||||
null
|
||||
mapper(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
/**
|
||||
* Allow only messages which are not [MediaGroupMessage]
|
||||
*/
|
||||
val MessageFilterExcludingMediaGroups: BehaviourContextAndTwoTypesReceiver<Boolean, CommonMessage<*>, Update> = { message, update ->
|
||||
val MessageFilterExcludingMediaGroups: BehaviourContextAndTwoTypesReceiver<Boolean, CommonMessage<*>, Update> = { _, update ->
|
||||
update !is MediaGroupMessage<*>
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,9 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CallbackQueryFilte
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.*
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByUserCallbackQueryMarkerFactory
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.MarkerFactory
|
||||
import dev.inmo.tgbotapi.types.CallbackQuery.*
|
||||
import dev.inmo.tgbotapi.types.queries.callback.*
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import dev.inmo.tgbotapi.utils.PreviewFeature
|
||||
|
||||
/**
|
||||
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call
|
||||
@@ -22,6 +23,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
|
||||
* data
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.onUnhandledDataCallbackQuery(
|
||||
initialFilter: SimpleFilter<DataCallbackQuery>? = null,
|
||||
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, DataCallbackQuery, Update>? = CallbackQueryFilterByUser,
|
||||
@@ -46,6 +48,7 @@ suspend fun <BC : BehaviourContext> BC.onUnhandledDataCallbackQuery(
|
||||
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
|
||||
* data
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.onUnhandledInlineMessageIdDataCallbackQuery(
|
||||
initialFilter: SimpleFilter<InlineMessageIdDataCallbackQuery>? = null,
|
||||
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, InlineMessageIdDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
|
||||
@@ -70,6 +73,7 @@ suspend fun <BC : BehaviourContext> BC.onUnhandledInlineMessageIdDataCallbackQue
|
||||
* @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that
|
||||
* data
|
||||
*/
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.onUnhandledMessageDataCallbackQuery(
|
||||
initialFilter: SimpleFilter<MessageDataCallbackQuery>? = null,
|
||||
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, MessageDataCallbackQuery, Update>? = CallbackQueryFilterByUser,
|
||||
|
||||
@@ -13,9 +13,11 @@ import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithParams
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.TextContent
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import dev.inmo.tgbotapi.utils.PreviewFeature
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.unhandledCommand(
|
||||
requireOnlyCommandInMessage: Boolean = true,
|
||||
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
|
||||
@@ -43,6 +45,7 @@ suspend fun <BC : BehaviourContext> BC.unhandledCommand(
|
||||
scenarioReceiver
|
||||
)
|
||||
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.onUnhandledCommand(
|
||||
requireOnlyCommandInMessage: Boolean = true,
|
||||
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
|
||||
@@ -51,6 +54,7 @@ suspend fun <BC : BehaviourContext> BC.onUnhandledCommand(
|
||||
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<TextContent>>
|
||||
): Job = unhandledCommand(requireOnlyCommandInMessage, initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
|
||||
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.unhandledCommandWithArgs(
|
||||
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
|
||||
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
|
||||
@@ -68,6 +72,7 @@ suspend fun <BC : BehaviourContext> BC.unhandledCommandWithArgs(
|
||||
scenarioReceiver(it, args)
|
||||
}
|
||||
|
||||
@PreviewFeature
|
||||
suspend fun <BC : BehaviourContext> BC.onUnhandledCommandWithArgs(
|
||||
initialFilter: CommonMessageFilter<TextContent>? = CommonMessageFilterExcludeMediaGroups,
|
||||
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<TextContent>, Update> = MessageFilterByChat,
|
||||
|
||||
@@ -36,7 +36,6 @@ import dev.inmo.tgbotapi.types.update.abstracts.BaseEditMessageUpdate
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import dev.inmo.tgbotapi.utils.PreviewFeature
|
||||
|
||||
@PreviewFeature
|
||||
internal suspend inline fun <BC : BehaviourContext, reified T : MessageContent> BC.onEditedContent(
|
||||
initialFilter: CommonMessageFilter<T>? = null,
|
||||
noinline subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<T>, Update>? = MessageFilterByChat,
|
||||
|
||||
@@ -23,6 +23,7 @@ internal suspend inline fun <BC : BehaviourContext, reified T : ChatEvent> BC.on
|
||||
markerFactory: MarkerFactory<in ChatEventMessage<T>, Any> = ByChatMessageMarkerFactory,
|
||||
noinline scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<T>>
|
||||
) = on(markerFactory, initialFilter, subcontextUpdatesFilter, scenarioReceiver) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(it.asBaseSentMessageUpdate() ?.data ?.asChatEventMessage() ?.takeIf { it.chatEvent is T } as? ChatEventMessage<T>) ?.let(::listOfNotNull)
|
||||
}
|
||||
|
||||
@@ -584,7 +585,7 @@ suspend fun <BC : BehaviourContext> BC.onWebAppData(
|
||||
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, PrivateEventMessage<WebAppData>>
|
||||
) = onEvent(
|
||||
initialFilter ?.let { { it is PrivateEventMessage<WebAppData> && initialFilter(it) } },
|
||||
subcontextUpdatesFilter ?.let { { it: ChatEventMessage<WebAppData>, update: Update -> it is PrivateEventMessage<WebAppData> && subcontextUpdatesFilter(it, update) } },
|
||||
subcontextUpdatesFilter ?.let { { message: ChatEventMessage<WebAppData>, update: Update -> message is PrivateEventMessage<WebAppData> && subcontextUpdatesFilter(message, update) } },
|
||||
markerFactory
|
||||
) {
|
||||
if (it is PrivateEventMessage<WebAppData>) {
|
||||
|
||||
@@ -21,12 +21,9 @@ internal suspend inline fun <BC : BehaviourContext, reified T> BC.on(
|
||||
scope,
|
||||
markerFactory::invoke
|
||||
) { triggerData ->
|
||||
val scope = LinkedSupervisorScope()
|
||||
doInSubContextWithUpdatesFilter(
|
||||
createSubContextAndDoWithUpdatesFilter(
|
||||
updatesFilter = subcontextUpdatesFilter ?.toOneType(triggerData),
|
||||
stopOnCompletion = false,
|
||||
updatesUpstreamFlow = allUpdatesFlow.accumulatorFlow(scope),
|
||||
scope = scope
|
||||
stopOnCompletion = false
|
||||
) {
|
||||
scenarioReceiver(triggerData)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar
|
||||
|
||||
import dev.inmo.tgbotapi.types.CallbackQuery.DataCallbackQuery
|
||||
import dev.inmo.tgbotapi.types.queries.callback.DataCallbackQuery
|
||||
|
||||
class TriggersHolder {
|
||||
val handleableCommandsHolder = HandleableRegexesHolder()
|
||||
|
||||
@@ -391,6 +391,8 @@ const val requireShippingAddressField = "need_shipping_address"
|
||||
const val shouldSendPhoneNumberToProviderField = "send_phone_number_to_provider"
|
||||
const val shouldSendEmailToProviderField = "send_email_to_provider"
|
||||
|
||||
const val resizeKeyboardField = "resize_keyboard"
|
||||
const val oneTimeKeyboardField = "one_time_keyboard"
|
||||
const val inputFieldPlaceholderField = "input_field_placeholder"
|
||||
|
||||
const val priceDependOnShipAddressField = "is_flexible"
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package dev.inmo.tgbotapi.types.buttons
|
||||
|
||||
import dev.inmo.tgbotapi.types.inputFieldPlaceholderField
|
||||
import dev.inmo.tgbotapi.types.inputFieldPlaceholderLimit
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ReplyKeyboardMarkup(
|
||||
val keyboard: Matrix<KeyboardButton>,
|
||||
@SerialName("resize_keyboard")
|
||||
@SerialName(resizeKeyboardField)
|
||||
val resizeKeyboard: Boolean? = null,
|
||||
@SerialName("one_time_keyboard")
|
||||
@SerialName(oneTimeKeyboardField)
|
||||
val oneTimeKeyboard: Boolean? = null,
|
||||
@SerialName(inputFieldPlaceholderField)
|
||||
val inputFieldPlaceholder: String? = null,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package dev.inmo.tgbotapi.extensions.utils.updates.retrieving
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.ExceptionHandler
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.micro_utils.coroutines.*
|
||||
import dev.inmo.tgbotapi.bot.RequestsExecutor
|
||||
import dev.inmo.tgbotapi.extensions.utils.nonstrictJsonFormat
|
||||
import dev.inmo.tgbotapi.extensions.utils.updates.flowsUpdatesFilter
|
||||
@@ -10,6 +9,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.UpdateDeserializationStrategy
|
||||
import dev.inmo.tgbotapi.updateshandlers.*
|
||||
import dev.inmo.tgbotapi.updateshandlers.webhook.WebhookPrivateKeyConfig
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.request.receiveText
|
||||
@@ -39,18 +39,22 @@ fun Route.includeWebhookHandlingInRoute(
|
||||
) {
|
||||
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis)
|
||||
post {
|
||||
safely(
|
||||
exceptionsHandler ?: {}
|
||||
) {
|
||||
val asJson =
|
||||
nonstrictJsonFormat.parseToJsonElement(call.receiveText())
|
||||
val update = nonstrictJsonFormat.decodeFromJsonElement(
|
||||
UpdateDeserializationStrategy,
|
||||
asJson
|
||||
)
|
||||
transformer(update)
|
||||
try {
|
||||
runCatchingSafely {
|
||||
val asJson = nonstrictJsonFormat.parseToJsonElement(call.receiveText())
|
||||
val update = nonstrictJsonFormat.decodeFromJsonElement(
|
||||
UpdateDeserializationStrategy,
|
||||
asJson
|
||||
)
|
||||
transformer(update)
|
||||
}.onSuccess {
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}.onFailure {
|
||||
call.respond(HttpStatusCode.InternalServerError)
|
||||
}.getOrThrow()
|
||||
} catch (e: Throwable) {
|
||||
exceptionsHandler ?.invoke(e)
|
||||
}
|
||||
call.respond("Ok")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +91,7 @@ fun startListenWebhooks(
|
||||
privateKeyConfig: WebhookPrivateKeyConfig? = null,
|
||||
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||
mediaGroupsDebounceTimeMillis: Long = 1000L,
|
||||
additionalApplicationEngineEnvironmentConfigurator: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
|
||||
block: UpdateReceiver<Update>
|
||||
): ApplicationEngine {
|
||||
val env = applicationEngineEnvironment {
|
||||
@@ -98,6 +103,7 @@ fun startListenWebhooks(
|
||||
} ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
|
||||
}
|
||||
}
|
||||
|
||||
privateKeyConfig ?.let {
|
||||
sslConnector(
|
||||
privateKeyConfig.keyStore,
|
||||
@@ -113,6 +119,7 @@ fun startListenWebhooks(
|
||||
port = listenPort
|
||||
}
|
||||
|
||||
additionalApplicationEngineEnvironmentConfigurator()
|
||||
}
|
||||
|
||||
return embeddedServer(engineFactory, env).also {
|
||||
@@ -142,10 +149,11 @@ suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
|
||||
privateKeyConfig: WebhookPrivateKeyConfig? = null,
|
||||
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
|
||||
mediaGroupsDebounceTimeMillis: Long = 1000L,
|
||||
additionalApplicationEngineEnvironmentConfigurator: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
|
||||
block: UpdateReceiver<Update>
|
||||
): ApplicationEngine = try {
|
||||
execute(setWebhookRequest)
|
||||
startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, block)
|
||||
startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, additionalApplicationEngineEnvironmentConfigurator, block)
|
||||
} catch (e: Exception) {
|
||||
throw e
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user