1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-06-01 15:35:24 +00:00
tgbotapi/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt

85 lines
3.8 KiB
Kotlin
Raw Normal View History

package dev.inmo.tgbotapi.extensions.behaviour_builder
2021-01-06 17:06:48 +00:00
2021-01-19 12:50:45 +00:00
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
2021-01-06 17:06:48 +00:00
import dev.inmo.tgbotapi.bot.TelegramBot
2021-01-19 12:50:45 +00:00
import dev.inmo.tgbotapi.types.update.abstracts.Update
2021-01-06 17:06:48 +00:00
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
2021-02-17 16:11:26 +00:00
import dev.inmo.tgbotapi.utils.RiskFeature
2021-01-19 12:50:45 +00:00
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.filter
2021-01-06 17:06:48 +00:00
2021-01-07 12:11:01 +00:00
typealias BehaviourContextReceiver<T> = suspend BehaviourContext.() -> T
typealias BehaviourContextAndTypeReceiver<T, I> = suspend BehaviourContext.(I) -> T
2021-01-06 17:06:48 +00:00
/**
* This class contains all necessary tools for work with bots and especially for [buildBehaviour]
*
* @param scope This param will be used for creating of some subscriptions inside of methods, updates listening and
* different other things in context of working with [CoroutineScope] and coroutines.
* @param flowsUpdatesFilter This parameter will be used to subscribe on different types of update
*/
2021-01-07 12:11:01 +00:00
data class BehaviourContext(
2021-01-06 17:06:48 +00:00
val bot: TelegramBot,
2021-01-06 17:21:33 +00:00
val scope: CoroutineScope,
val flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter()
2021-01-19 12:50:45 +00:00
) : FlowsUpdatesFilter by flowsUpdatesFilter, TelegramBot by bot, CoroutineScope by scope
/**
* Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [newFlowsUpdatesFilterSetUp] is provided and
2021-02-17 16:11:26 +00:00
* [CoroutineScope] as new [BehaviourContext.scope]. You must do all subscription/running of longPolling manually.
2021-01-19 12:50:45 +00:00
*
* @param newFlowsUpdatesFilterSetUp As a parameter receives [FlowsUpdatesFilter] from old [this] [BehaviourContext.flowsUpdatesFilter]
*/
2021-02-17 16:11:26 +00:00
@RiskFeature("It is recommended to use doInSubContextWithUpdatesFilter instead. " +
"This method is low level and should not be used in case you are not pretty sure you need it.")
2021-01-19 12:50:45 +00:00
suspend fun <T> BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup(
newFlowsUpdatesFilterSetUp: BehaviourContextAndTypeReceiver<Unit, FlowsUpdatesFilter>?,
2021-02-17 16:11:26 +00:00
stopOnCompletion: Boolean = true,
2021-01-19 12:50:45 +00:00
behaviourContextReceiver: BehaviourContextReceiver<T>
2021-04-05 10:41:27 +00:00
): T = supervisorScope {
val newContext = copy(
flowsUpdatesFilter = FlowsUpdatesFilter(),
scope = this
)
2021-01-19 12:50:45 +00:00
newFlowsUpdatesFilterSetUp ?.let {
2021-04-05 10:41:27 +00:00
it.apply { invoke(newContext, this@doInSubContextWithFlowsUpdatesFilterSetup.flowsUpdatesFilter) }
2021-01-19 12:50:45 +00:00
}
2021-04-05 10:50:31 +00:00
newContext.behaviourContextReceiver().also { if (stopOnCompletion) stop() }
2021-01-19 12:50:45 +00:00
}
/**
* Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [updatesFilter] is provided and
* [CoroutineScope] as new [BehaviourContext.scope]
*/
suspend fun <T> BehaviourContext.doInSubContextWithUpdatesFilter(
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?,
2021-02-17 16:11:26 +00:00
stopOnCompletion: Boolean = true,
2021-01-19 12:50:45 +00:00
behaviourContextReceiver: BehaviourContextReceiver<T>
2021-04-05 10:41:27 +00:00
): T {
val updatesScope = CoroutineScope(coroutineContext + SupervisorJob())
return doInSubContextWithFlowsUpdatesFilterSetup(
newFlowsUpdatesFilterSetUp = updatesFilter ?.let {
{ oldOne ->
oldOne.allUpdatesFlow.filter { updatesFilter(it) }.subscribeSafelyWithoutExceptions(updatesScope, asUpdateReceiver)
}
} ?: { oldOne ->
oldOne.allUpdatesFlow.subscribeSafelyWithoutExceptions(updatesScope, asUpdateReceiver)
},
stopOnCompletion
) {
coroutineContext.job.invokeOnCompletion { updatesScope.cancel() }
behaviourContextReceiver()
}
}
2021-01-19 12:50:45 +00:00
suspend fun <T> BehaviourContext.doInSubContext(
2021-02-17 16:11:26 +00:00
stopOnCompletion: Boolean = true,
2021-01-19 12:50:45 +00:00
behaviourContextReceiver: BehaviourContextReceiver<T>
2021-02-17 16:11:26 +00:00
) = doInSubContextWithUpdatesFilter(updatesFilter = null, stopOnCompletion, behaviourContextReceiver)
2021-01-19 12:50:45 +00:00
/**
* This method will cancel ALL subsequent contexts, expectations and waiters
*/
fun BehaviourContext.stop() = scope.cancel()