1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-11-24 19:18:44 +00:00

Merge branch 'master' into 1.0.0

This commit is contained in:
InsanusMokrassar 2022-05-04 11:13:17 +06:00
commit a2206b99a2
8 changed files with 154 additions and 104 deletions

View File

@ -47,6 +47,22 @@ __All the `tgbotapi.extensions.*` packages have been removed__
* `BehaviourBuilder`: * `BehaviourBuilder`:
* `SimpleFilter` now is a `fun interface` instead of just callback (fix of [#546](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/546)) * `SimpleFilter` now is a `fun interface` instead of just callback (fix of [#546](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/546))
## 0.38.20
* `BehaviourBuilder FSM`:
* Hotfixes
* `WebApps`:
* New extension `TelegramBot#answerWebAppQuery`
* New function `handleResult`
## 0.38.19
* `BehaviourBuilder`:
* Hotfixes
* `BehaviourBuilder FSM`:
* `BehaviourContextWithFSMBuilder` deprecated in favor to `BehaviourContextWithFSM`
* Now it is possible to define additional handlers in subcontexts of `BehaviourBuilderWithFSM`
## 0.38.18 ## 0.38.18
* `Core`: * `Core`:

View File

@ -9,6 +9,8 @@ import dev.inmo.micro_utils.coroutines.accumulatorFlow
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlin.jvm.JvmName
import kotlin.reflect.KClass
/** /**
* Interface which combine [BehaviourContext] and [StatesMachine]. Subcontext of triggers and states contexts must have * Interface which combine [BehaviourContext] and [StatesMachine]. Subcontext of triggers and states contexts must have
@ -26,10 +28,31 @@ interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
): T? { ): T? {
return handlers.firstOrNull { it.checkHandleable(state) } ?.run { return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
handleState(contextUpdatesFlow, state) 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
*
* @see BehaviourWithFSMStateHandlerHolder
* @see onStateOrSubstate
*/
fun <I : T> add(kClass: KClass<I>, strict: Boolean = false, handler: BehaviourWithFSMStateHandler<I, T>)
/**
* 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 : T> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) = add(kClass, strict = true, handler)
override fun copy( override fun copy(
bot: TelegramBot, bot: TelegramBot,
scope: CoroutineScope, scope: CoroutineScope,
@ -48,6 +71,28 @@ interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T
} }
} }
/**
* 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 BehaviourContextWithFSM.add
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : O, O: State> BehaviourContextWithFSM<O>.onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, O>) = add(I::class, strict = 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 BehaviourContextWithFSM.addStrict
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : O, O: State> BehaviourContextWithFSM<O>.strictlyOn(handler: BehaviourWithFSMStateHandler<I, O>) = addStrict(I::class, handler)
/** /**
* Default realization of [BehaviourContextWithFSM]. It uses [behaviourContext] as a base for this object as * 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 * [BehaviourContext], but managing substates contexts updates for avoiding of updates lost between states
@ -58,6 +103,9 @@ class DefaultBehaviourContextWithFSM<T : State>(
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> { ) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
private val updatesFlows = mutableMapOf<Any, Flow<Update>>() private val updatesFlows = mutableMapOf<Any, Flow<Update>>()
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
private var actualHandlersList = additionalHandlers + handlers
private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) { private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) {
allUpdatesFlow.accumulatorFlow(scope) allUpdatesFlow.accumulatorFlow(scope)
} }
@ -65,12 +113,17 @@ class DefaultBehaviourContextWithFSM<T : State>(
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling( override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(
state, state,
allUpdatesFlow, allUpdatesFlow,
handlers actualHandlersList
) )
override fun <I : T> add(kClass: KClass<I>, strict: Boolean, handler: BehaviourWithFSMStateHandler<I, T>) {
additionalHandlers.add(BehaviourWithFSMStateHandlerHolder(kClass, strict, handler))
actualHandlersList = additionalHandlers + handlers
}
override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions {
val statePerformer: suspend (T) -> Unit = { state: T -> val statePerformer: suspend (T) -> Unit = { state: T ->
val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), handlers) val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), actualHandlersList)
if (newState != null) { if (newState != null) {
statesManager.update(state, newState) statesManager.update(state, newState)
} else { } else {
@ -94,6 +147,26 @@ class DefaultBehaviourContextWithFSM<T : State>(
launch { statePerformer(it) } launch { statePerformer(it) }
} }
} }
/**
* 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 BehaviourContextWithFSM.add
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : T> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, T>) = add(I::class, strict = 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 BehaviourContextWithFSM.addStrict
*/
@Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : T> strictlyOn(handler: BehaviourWithFSMStateHandler<I, T>) = addStrict(I::class, handler)
override suspend fun startChain(state: T) { override suspend fun startChain(state: T) {
statesManager.startChain(state) statesManager.startChain(state)
@ -106,7 +179,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
onBufferOverflow: BufferOverflow, onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?, upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM<T> = BehaviourContextWithFSM( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter), behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter),
handlers, handlers,
statesManager statesManager

View File

@ -14,70 +14,8 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass import kotlin.reflect.KClass
class BehaviourContextWithFSMBuilder<T : State> internal constructor( @Deprecated("Will be removed soon")
private val resultBehaviourContext: BehaviourContextWithFSM<T>, typealias BehaviourContextWithFSMBuilder<T> = BehaviourContextWithFSM<T>
private val handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>>
) : BehaviourContextWithFSM<T> by resultBehaviourContext {
internal constructor(
baseBehaviourContext: BehaviourContext,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = 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 : T> add(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) {
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 : T> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) {
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 : T> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, T>) {
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 : T> strictlyOn(handler: BehaviourWithFSMStateHandler<I, T>) {
addStrict(I::class, handler)
}
/**
* Returns completed [resultBehaviourContext], [handlers] and [statesManager]
*/
internal fun build() = resultBehaviourContext
}
/** /**
* Creates [BehaviourContextWithFSM] via creating of [DefaultBehaviourContext] with [this] as [TelegramBot], * Creates [BehaviourContextWithFSM] via creating of [DefaultBehaviourContext] with [this] as [TelegramBot],
@ -94,17 +32,17 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): BehaviourContextWithFSM<T> = BehaviourContextWithFSMBuilder( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
DefaultBehaviourContext( DefaultBehaviourContext(
this, this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope,
upstreamUpdatesFlow = upstreamUpdatesFlow upstreamUpdatesFlow = upstreamUpdatesFlow
), ),
statesManager, presetHandlers,
presetHandlers statesManager
).apply { block() }.build() ).apply { block() }
/** /**
* Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates * Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates
@ -116,9 +54,9 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): Pair<BehaviourContextWithFSM<T>, Job> = buildBehaviourWithFSM( ): Pair<DefaultBehaviourContextWithFSM<T>, Job> = buildBehaviourWithFSM(
upstreamUpdatesFlow, upstreamUpdatesFlow,
scope, scope,
defaultExceptionsHandler, defaultExceptionsHandler,
@ -147,8 +85,8 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
* @see BehaviourContext * @see BehaviourContext
* @see BehaviourContextWithFSM * @see BehaviourContextWithFSM
* @see longPolling * @see longPolling
* @see BehaviourContextWithFSMBuilder.strictlyOn * @see BehaviourContextWithFSM.strictlyOn
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate * @see BehaviourContextWithFSM.onStateOrSubstate
*/ */
@PreviewFeature @PreviewFeature
suspend fun <T : State> TelegramBot.buildBehaviourWithFSM( suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
@ -156,17 +94,17 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): BehaviourContextWithFSM<T> = BehaviourContextWithFSMBuilder( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
DefaultBehaviourContext( DefaultBehaviourContext(
this, this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope,
upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow upstreamUpdatesFlow = flowUpdatesFilter.allUpdatesFlow
), ),
statesManager, presetHandlers,
presetHandlers statesManager
).apply { block() }.build() ).apply { block() }
/** /**
* Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates * Use [buildBehaviourWithFSM] to create [BehaviourContextWithFSM] and launch getting of updates
@ -176,16 +114,16 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
* @see buildBehaviourWithFSMAndStartLongPolling * @see buildBehaviourWithFSMAndStartLongPolling
* @see BehaviourContext * @see BehaviourContext
* @see longPolling * @see longPolling
* @see BehaviourContextWithFSMBuilder.strictlyOn * @see BehaviourContextWithFSM.strictlyOn
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate * @see BehaviourContextWithFSM.onStateOrSubstate
*/ */
@PreviewFeature @PreviewFeature
suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling( suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
) = FlowsUpdatesFilter().let { ) = FlowsUpdatesFilter().let {
buildBehaviourWithFSM( buildBehaviourWithFSM(
it, it,

View File

@ -34,20 +34,11 @@ class BehaviourWithFSMStateHandlerHolder<I : O, O : State>(
/** /**
* Handling of 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<in O>.handleState( suspend fun BehaviourContextWithFSM<in O>.handleState(
contextUpdatesFlow: Flow<Update>,
state: O state: O
): O? { ): O? = with(delegateTo) {
val subscope = scope.LinkedSupervisorScope() handleState(state as I)
return with(copy(scope = subscope, upstreamUpdatesFlow = contextUpdatesFlow)) {
with(delegateTo) {
handleState(state as I)
}
}
} }
} }

View File

@ -37,9 +37,9 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSM(
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
testServer: Boolean = false, testServer: Boolean = false,
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): TelegramBot = telegramBot( ): TelegramBot = telegramBot(
token, token,
apiUrl, apiUrl,
@ -74,9 +74,9 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
testServer: Boolean = false, testServer: Boolean = false,
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): Pair<TelegramBot, Job> { ): Pair<TelegramBot, Job> {
return telegramBot( return telegramBot(
token, token,

View File

@ -6,6 +6,9 @@ import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQ
import dev.inmo.tgbotapi.types.webapps.query.SentWebAppMessage import dev.inmo.tgbotapi.types.webapps.query.SentWebAppMessage
import kotlinx.serialization.* import kotlinx.serialization.*
/**
* @param webAppQueryId [dev.inmo.tgbotapi.webapps.WebAppInitData.queryId]
*/
@Serializable @Serializable
data class AnswerWebAppQuery( data class AnswerWebAppQuery(
@SerialName(webAppQueryIdField) @SerialName(webAppQueryIdField)

View File

@ -0,0 +1,11 @@
package dev.inmo.tgbotapi.webapps
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.answers.AnswerWebAppQuery
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
suspend fun TelegramBot.answerWebAppQuery(
result: InlineQueryResult
) = webApp.initDataUnsafe.queryId ?.let {
execute(AnswerWebAppQuery(it, result))
}

View File

@ -0,0 +1,18 @@
package dev.inmo.tgbotapi.webapps
import dev.inmo.tgbotapi.types.WebAppQueryId
/**
* @param onSendData Should return the data which must be used in [WebApp.sendData]. If returns null, data will not be sent
* @param onAnswerWebAppQuery In case if [WebAppInitData.queryId] is presented in [WebApp.initDataUnsafe], will be called
* that callback. Before and after calling of this callback will not be used any method of answering to the telegram
* system, so, you must use something like [answerWebAppQuery] by yourself to send the result
*/
inline fun handleResult(
onSendData: () -> String?,
onAnswerWebAppQuery: (WebAppQueryId) -> Unit
) {
webApp.initDataUnsafe.queryId ?.let {
onAnswerWebAppQuery(it)
} ?: webApp.sendData(onSendData() ?: return)
}