mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 08:13:47 +00:00
preview state of steps
This commit is contained in:
parent
6bd423dc11
commit
00873a255c
@ -8,5 +8,6 @@ pluginManagement {
|
||||
include ":tgbotapi.core"
|
||||
include ":tgbotapi.extensions.api"
|
||||
include ":tgbotapi.extensions.utils"
|
||||
include ":tgbotapi.extensions.steps"
|
||||
include ":tgbotapi"
|
||||
include ":docs"
|
||||
|
@ -19,13 +19,17 @@ interface TextedOutput : ParsableOutput, EntitiesOutput
|
||||
|
||||
interface TextedInput : Texted {
|
||||
/**
|
||||
* Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
|
||||
* Here must be full list of entities. This list must contains [TextPart]s with
|
||||
* [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] in case if source text contains parts of
|
||||
* regular text
|
||||
* @see [CaptionedInput.fullEntitiesList]
|
||||
*/
|
||||
val textEntities: List<TextPart>
|
||||
}
|
||||
|
||||
/**
|
||||
* Full list of [TextSource] built from source[TextedInput.textEntities]
|
||||
*
|
||||
* @see TextedInput.textEntities
|
||||
* @see justTextSources
|
||||
*/
|
||||
|
1
tgbotapi.extensions.steps/README.md
Normal file
1
tgbotapi.extensions.steps/README.md
Normal file
@ -0,0 +1 @@
|
||||
# TelegramBotAPI Steps Extensions
|
48
tgbotapi.extensions.steps/build.gradle
Normal file
48
tgbotapi.extensions.steps/build.gradle
Normal file
@ -0,0 +1,48 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
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()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url "https://kotlin.bintray.com/kotlinx" }
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
js(BOTH) {
|
||||
browser()
|
||||
nodejs()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
api project(":tgbotapi.core")
|
||||
api project(":tgbotapi.extensions.utils")
|
||||
api project(":tgbotapi.extensions.api")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
tgbotapi.extensions.steps/mpp_publish_template.kpsb
Normal file
1
tgbotapi.extensions.steps/mpp_publish_template.kpsb
Normal file
@ -0,0 +1 @@
|
||||
{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Steps Extensions","description":"These extensions project contains tools for simple interaction with chats","url":"https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}
|
69
tgbotapi.extensions.steps/publish.gradle
Normal file
69
tgbotapi.extensions.steps/publish.gradle
Normal file
@ -0,0 +1,69 @@
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
task javadocsJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
}
|
||||
task sourceJar (type : Jar) {
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
project.publishing.publications.all {
|
||||
// rename artifacts
|
||||
groupId "${project.group}"
|
||||
if (it.name.contains('kotlinMultiplatform')) {
|
||||
artifactId = "${project.name}"
|
||||
artifact sourceJar
|
||||
} else {
|
||||
artifactId = "${project.name}-$name"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.all {
|
||||
artifact javadocsJar
|
||||
|
||||
pom {
|
||||
description = "These extensions project contains tools for simple interaction with chats"
|
||||
name = "Telegram Bot API Steps Extensions"
|
||||
url = "https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps"
|
||||
|
||||
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 {
|
||||
maven {
|
||||
name = "bintray"
|
||||
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
|
||||
credentials {
|
||||
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
||||
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package dev.inmo.tgbotapi.extensions.steps
|
||||
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
typealias ScenarioReceiver<T> = suspend Scenario.() -> T
|
||||
typealias ScenarioAndTypeReceiver<T, I> = suspend Scenario.(I) -> T
|
||||
|
||||
data class Scenario(
|
||||
val bot: TelegramBot,
|
||||
val flowsUpdatesFilter: FlowsUpdatesFilter,
|
||||
val scope: CoroutineScope
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
package dev.inmo.tgbotapi.extensions.steps
|
||||
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
suspend fun TelegramBot.buildScenarios(
|
||||
scope: CoroutineScope,
|
||||
flowUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(),
|
||||
block: ScenarioReceiver<Unit>
|
||||
) {
|
||||
Scenario(
|
||||
this,
|
||||
flowUpdatesFilter,
|
||||
scope
|
||||
).block()
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package dev.inmo.tgbotapi.extensions.steps.expectations
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.extensions.steps.Scenario
|
||||
import dev.inmo.tgbotapi.extensions.steps.ScenarioReceiver
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
private val cancelledByFilterException = CancellationException("Cancelled by filter precreatedException")
|
||||
|
||||
typealias RequestBuilder<T> = suspend (Update) -> Request<T>
|
||||
typealias NullableRequestBuilder<T> = suspend (Update) -> Request<T>?
|
||||
|
||||
@RiskFeature("This method is not very comfortable to use and too low-level. It is recommended to use methods which already included into library")
|
||||
suspend fun <T> FlowsUpdatesFilter.expectFlow(
|
||||
bot: TelegramBot,
|
||||
initRequest: Request<*>? = null,
|
||||
count: Int? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
||||
filter: suspend (Update) -> T?
|
||||
): Flow<T> {
|
||||
val flow = allUpdatesFlow.mapNotNull {
|
||||
val result = safelyWithoutExceptions { filter(it) }
|
||||
if (result == null) {
|
||||
if (cancelTrigger(it)) {
|
||||
cancelRequestFactory(it) ?.also {
|
||||
safelyWithoutExceptions { bot.execute(it) }
|
||||
throw cancelledByFilterException
|
||||
}
|
||||
}
|
||||
errorFactory(it) ?.also { errorRequest ->
|
||||
safelyWithoutExceptions { bot.execute(errorRequest) }
|
||||
}
|
||||
null
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
val result = if (count == null) {
|
||||
flow
|
||||
} else {
|
||||
flow.take(count)
|
||||
}
|
||||
initRequest ?.also { safelyWithoutExceptions { bot.execute(initRequest) } }
|
||||
return result
|
||||
}
|
||||
|
||||
suspend fun <T> Scenario.expectFlow(
|
||||
initRequest: Request<*>? = null,
|
||||
count: Int? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
||||
filter: suspend (Update) -> T?
|
||||
) = flowsUpdatesFilter.expectFlow(bot, initRequest, count, errorFactory, cancelRequestFactory, cancelTrigger, filter)
|
||||
|
||||
@RiskFeature("This method is not very comfortable to use and too low-level. It is recommended to use methods which already included into library")
|
||||
suspend fun <T> FlowsUpdatesFilter.expectOne(
|
||||
bot: TelegramBot,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
||||
filter: suspend (Update) -> T?,
|
||||
): T = expectFlow(bot, initRequest, 1, errorFactory, cancelRequestFactory, cancelTrigger, filter).first()
|
||||
|
||||
suspend fun <T> Scenario.expectOne(
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
||||
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
||||
filter: suspend (Update) -> T?
|
||||
) = flowsUpdatesFilter.expectOne(bot, initRequest, errorFactory, cancelRequestFactory, cancelTrigger, filter)
|
@ -0,0 +1,175 @@
|
||||
package dev.inmo.tgbotapi.extensions.steps.expectations
|
||||
|
||||
import dev.inmo.tgbotapi.extensions.steps.Scenario
|
||||
import dev.inmo.tgbotapi.extensions.utils.*
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.message.content.media.*
|
||||
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
|
||||
import kotlinx.coroutines.flow.toList
|
||||
|
||||
typealias ContentMessageToContentMapper<T> = suspend ContentMessage<T>.() -> T?
|
||||
|
||||
private suspend fun <O> Scenario.waitContentMessage(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
mapper: suspend ContentMessage<MessageContent>.() -> O?
|
||||
): List<O> = expectFlow(
|
||||
initRequest,
|
||||
count,
|
||||
errorFactory
|
||||
) {
|
||||
it.asMessageUpdate() ?.data ?.asContentMessage() ?.mapper()
|
||||
}.toList().toList()
|
||||
|
||||
private suspend inline fun <reified T : MessageContent> Scenario.waitContent(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||
noinline filter: (suspend (ContentMessage<T>) -> T?)? = null
|
||||
) : List<T> = waitContentMessage<T>(
|
||||
count,
|
||||
initRequest,
|
||||
errorFactory
|
||||
) {
|
||||
if (content is T) {
|
||||
val message = (this as ContentMessage<T>)
|
||||
if (filter == null) {
|
||||
message.content
|
||||
} else {
|
||||
filter(message)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Scenario.waitContact(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<ContactContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitDice(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<DiceContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitGame(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<GameContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitLocation(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<LocationContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitPoll(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<PollContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitText(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<TextContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitVenue(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<VenueContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitAudioMediaGroup(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<AudioMediaGroupContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitDocumentMediaGroup(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<DocumentMediaGroupContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitMedia(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<MediaContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitMediaGroup(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<MediaGroupContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitVisualMediaGroup(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<VisualMediaGroupContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitAnimation(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<AnimationContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitAudio(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<AudioContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitDocument(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<DocumentContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitPhoto(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<PhotoContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitSticker(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<StickerContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitVideo(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<VideoContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitVideoNote(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<VideoNoteContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitVoice(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<VoiceContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitInvoice(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: ContentMessageToContentMapper<InvoiceContent>? = null
|
||||
) = waitContent(count, initRequest, errorFactory, filter)
|
@ -0,0 +1,37 @@
|
||||
package dev.inmo.tgbotapi.extensions.steps.triggers_handling
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.textSources
|
||||
import dev.inmo.tgbotapi.extensions.steps.*
|
||||
import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow
|
||||
import dev.inmo.tgbotapi.extensions.utils.*
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.TextContent
|
||||
|
||||
suspend fun Scenario.command(
|
||||
commandRegex: Regex,
|
||||
requireOnlyCommandInMessage: Boolean = true,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ContentMessage<TextContent>>
|
||||
) {
|
||||
flowsUpdatesFilter.expectFlow(bot) {
|
||||
it.asMessageUpdate() ?.data ?.asContentMessage() ?.let { message ->
|
||||
message.content.asTextContent() ?.let {
|
||||
val textSources = it.textSources
|
||||
val sizeRequirement = if (requireOnlyCommandInMessage) {
|
||||
textSources.size == 1
|
||||
} else {
|
||||
true
|
||||
}
|
||||
if (sizeRequirement && textSources.any { commandRegex.matches(it.asBotCommandTextSource() ?.command ?: return@any false) }) {
|
||||
message as ContentMessage<TextContent>
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}.subscribeSafelyWithoutExceptions(scope) {
|
||||
scenarioReceiver(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user