mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI-examples.git
synced 2024-11-22 16:23:54 +00:00
commit
12ef88c757
10
FSMBot/README.md
Normal file
10
FSMBot/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# FSM
|
||||
|
||||
This bot contains an example of working with FSM included in project
|
||||
[MicroUtils](https://github.com/InsanusMokrassar/MicroUtils)
|
||||
|
||||
## Launch
|
||||
|
||||
```bash
|
||||
../gradlew run --args="BOT_TOKEN"
|
||||
```
|
22
FSMBot/build.gradle
Normal file
22
FSMBot/build.gradle
Normal file
@ -0,0 +1,22 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'application'
|
||||
|
||||
mainClassName="SimpleFSMBotKt"
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
|
||||
implementation "dev.inmo:micro_utils.fsm.common:$micro_utils_version"
|
||||
}
|
90
FSMBot/src/main/kotlin/SimpleFSMBot.kt
Normal file
90
FSMBot/src/main/kotlin/SimpleFSMBot.kt
Normal file
@ -0,0 +1,90 @@
|
||||
import dev.inmo.micro_utils.fsm.common.State
|
||||
import dev.inmo.micro_utils.fsm.common.dsl.buildFSM
|
||||
import dev.inmo.micro_utils.fsm.common.dsl.strictlyOn
|
||||
import dev.inmo.tgbotapi.extensions.api.send.media.sendMediaGroup
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.api.send.sendMessage
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.command
|
||||
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithParams
|
||||
import dev.inmo.tgbotapi.extensions.utils.formatting.*
|
||||
import dev.inmo.tgbotapi.extensions.utils.shortcuts.chat
|
||||
import dev.inmo.tgbotapi.types.ChatId
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.TextContent
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
sealed interface State : State
|
||||
data class ExpectContentOrStopState(override val context: ChatId, val sourceMessage: CommonMessage<TextContent>) : State
|
||||
data class StopState(override val context: ChatId) : State
|
||||
|
||||
fun TextContent.containsStopCommand() = parseCommandsWithParams().keys.firstOrNull { it == "stop" } != null
|
||||
|
||||
suspend fun main(args: Array<String>) {
|
||||
val botToken = args.first()
|
||||
|
||||
telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
|
||||
val fsm = buildFSM {
|
||||
strictlyOn<ExpectContentOrStopState> {
|
||||
sendMessage(
|
||||
it.context,
|
||||
buildEntities {
|
||||
+"Send me some content or "
|
||||
botCommand("stop")
|
||||
+" if you want to stop sending"
|
||||
}
|
||||
)
|
||||
|
||||
val content = oneOf(
|
||||
parallel {
|
||||
waitContentMessage(includeMediaGroups = false) { if (chat.id == it.context) content else null }.also(::println)
|
||||
},
|
||||
parallel {
|
||||
waitMediaGroup { chat ?.id == it.context }.also(::println)
|
||||
},
|
||||
parallel {
|
||||
waitText { if (content.containsStopCommand()) content else null }.also(::println)
|
||||
}
|
||||
).first()
|
||||
|
||||
when {
|
||||
content is TextContent && content.containsStopCommand() -> StopState(it.context) // assume we got "stop" command
|
||||
content is List<*> -> { // assume it is media group
|
||||
val casted = (content as List<MediaGroupContent>)
|
||||
|
||||
reply(it.sourceMessage, "Ok, I got this media group and now will resend it to you")
|
||||
sendMediaGroup(it.context, casted.map { it.toMediaGroupMemberInputMedia() })
|
||||
|
||||
it
|
||||
}
|
||||
content is MessageContent -> {
|
||||
|
||||
reply(it.sourceMessage, "Ok, I got this content and now will resend it to you")
|
||||
execute(content.createResend(it.context))
|
||||
|
||||
it
|
||||
}
|
||||
else -> {
|
||||
sendMessage(it.context, "Unknown internal error")
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
strictlyOn<StopState> {
|
||||
sendMessage(it.context, "You have stopped sending of content")
|
||||
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
command("start") {
|
||||
fsm.startChain(ExpectContentOrStopState(it.chat.id, it))
|
||||
}
|
||||
|
||||
fsm.start(this)
|
||||
}.second.join()
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
|
||||
import dev.inmo.tgbotapi.extensions.api.downloadFile
|
||||
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
|
||||
import dev.inmo.tgbotapi.extensions.utils.flatMap
|
||||
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
|
||||
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia
|
||||
import dev.inmo.tgbotapi.utils.filenameFromUrl
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -19,24 +17,15 @@ suspend fun main(args: Array<String>) {
|
||||
val directoryOrFile = args.getOrNull(1) ?.let { File(it) } ?: File("")
|
||||
directoryOrFile.mkdirs()
|
||||
|
||||
val bot = telegramBot(botToken)
|
||||
val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
bot.longPolling(scope = scope) {
|
||||
val flow = merge (
|
||||
filterContentMessages<MediaContent>(),
|
||||
mediaGroupMessages().flatMap()
|
||||
)
|
||||
flow.onEach {
|
||||
safely({ it.printStackTrace() }) {
|
||||
telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
|
||||
onMedia(includeMediaGroups = true) {
|
||||
val pathedFile = bot.getFileAdditionalInfo(it.content.media)
|
||||
File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
|
||||
val file = File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
|
||||
createNewFile()
|
||||
writeBytes(bot.downloadFile(pathedFile))
|
||||
}
|
||||
reply(it, "Saved to ${file.absolutePath}")
|
||||
}
|
||||
}.launchIn(scope)
|
||||
}
|
||||
|
||||
scope.coroutineContext[Job]!!.join()
|
||||
onContentMessage { println(it) }
|
||||
}.second.join()
|
||||
}
|
||||
|
@ -1,17 +1,12 @@
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.micro_utils.coroutines.defaultSafelyExceptionHandler
|
||||
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
|
||||
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
|
||||
import dev.inmo.tgbotapi.extensions.api.telegramBot
|
||||
import dev.inmo.tgbotapi.extensions.utils.*
|
||||
import dev.inmo.tgbotapi.extensions.utils.formatting.codeMarkdownV2
|
||||
import dev.inmo.tgbotapi.extensions.utils.formatting.regularMarkdownV2
|
||||
import dev.inmo.tgbotapi.extensions.utils.shortcuts.mediaGroupMessages
|
||||
import dev.inmo.tgbotapi.extensions.utils.updates.asContentMessagesFlow
|
||||
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
|
||||
import dev.inmo.tgbotapi.extensions.utils.formatting.*
|
||||
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
|
||||
import dev.inmo.tgbotapi.types.message.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* This bot will always return message about forwarder. In cases when sent message was not a forward message it will
|
||||
@ -20,26 +15,25 @@ import kotlinx.coroutines.flow.*
|
||||
suspend fun main(vararg args: String) {
|
||||
val botToken = args.first()
|
||||
|
||||
val bot = telegramBot(botToken)
|
||||
|
||||
val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
bot.longPolling(scope = scope) {
|
||||
(merge(messageFlow.asContentMessagesFlow(), mediaGroupMessages(scope).flatMap())).mapNotNull { it.asPossiblyForwardedMessage() }.onEach { message ->
|
||||
safely({ it.printStackTrace() }) {
|
||||
val toAnswer = when (val forwardInfo = message.forwardInfo) {
|
||||
null -> "There is no forward info"
|
||||
is AnonymousForwardInfo -> "Anonymous user which signed as \"${forwardInfo.senderName.codeMarkdownV2()}\""
|
||||
is UserForwardInfo -> forwardInfo.from.let { user ->
|
||||
"User ${user.id.chatId.toString().codeMarkdownV2()} " + "(${user.firstName} ${user.lastName}: ${user.username ?.username ?: "Without username"})".regularMarkdownV2()
|
||||
telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
|
||||
onContentMessage(includeMediaGroups = true) {
|
||||
val toAnswer = buildEntities {
|
||||
when (val forwardInfo = it.forwardInfo) {
|
||||
null -> +"There is no forward info"
|
||||
is AnonymousForwardInfo -> {
|
||||
regular("Anonymous user which signed as \"") + code(forwardInfo.senderName) + "\""
|
||||
}
|
||||
is ForwardFromChannelInfo -> "Channel (".regularMarkdownV2() + (forwardInfo.channelChat).title.codeMarkdownV2() + ")".regularMarkdownV2()
|
||||
is ForwardFromSupergroupInfo -> "Supergroup (".regularMarkdownV2() + (forwardInfo.group).title.codeMarkdownV2() + ")".regularMarkdownV2()
|
||||
is UserForwardInfo -> {
|
||||
val user = forwardInfo.from
|
||||
regular("User ") + code(user.id.chatId.toString()) + " (${user.firstName} ${user.lastName}: ${user.username ?.username ?: "Without username"})"
|
||||
}
|
||||
bot.sendTextMessage(message.chat, toAnswer, MarkdownV2)
|
||||
is ForwardFromChannelInfo -> regular("Channel (") + code((forwardInfo.channelChat).title) + ")"
|
||||
is ForwardFromSupergroupInfo -> regular("Supergroup (") + code((forwardInfo.group).title) + ")"
|
||||
}
|
||||
}.launchIn(scope)
|
||||
}
|
||||
|
||||
scope.coroutineContext[Job]!!.join()
|
||||
reply(it, toAnswer)
|
||||
coroutineContext.job.invokeOnCompletion { println("completance of onContentMessage") }
|
||||
}
|
||||
coroutineContext.job.invokeOnCompletion { println("Completed :)") }
|
||||
}.second.join()
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
|
||||
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
|
||||
import dev.inmo.tgbotapi.extensions.utils.asChannelChat
|
||||
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
|
||||
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
|
||||
@ -21,19 +23,18 @@ import kotlinx.coroutines.flow.onEach
|
||||
suspend fun main(vararg args: String) {
|
||||
val botToken = args.first()
|
||||
|
||||
val bot = telegramBot(botToken)
|
||||
|
||||
val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
bot.longPolling(scope = scope) {
|
||||
messageFlow.onEach {
|
||||
safely {
|
||||
val message = it.data
|
||||
telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
|
||||
onContentMessage { message ->
|
||||
val chat = message.chat
|
||||
if (chat is ChannelChat) {
|
||||
val answer = "Hi everybody in this channel \"${chat.title}\""
|
||||
sendTextMessage(chat, answer, MarkdownV2)
|
||||
return@onContentMessage
|
||||
}
|
||||
val answerText = "Oh, hi, " + when (chat) {
|
||||
is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
|
||||
is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
|
||||
is SupergroupChat -> (chat.username ?.username ?: bot.getChat(chat).inviteLink) ?.let {
|
||||
is SupergroupChat -> (chat.username ?.username ?: getChat(chat).inviteLink) ?.let {
|
||||
chat.title.linkMarkdownV2(it)
|
||||
} ?: chat.title
|
||||
is GroupChat -> bot.getChat(chat).inviteLink ?.let {
|
||||
@ -41,21 +42,11 @@ suspend fun main(vararg args: String) {
|
||||
} ?: chat.title
|
||||
else -> "Unknown :(".escapeMarkdownV2Common()
|
||||
}
|
||||
bot.reply(
|
||||
reply(
|
||||
message,
|
||||
answerText,
|
||||
MarkdownV2
|
||||
)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
channelPostFlow.onEach {
|
||||
safely {
|
||||
val chat = it.data.chat
|
||||
val message = "Hi everybody in this channel \"${(chat.asChannelChat()) ?.title}\""
|
||||
bot.sendTextMessage(chat, message, MarkdownV2)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
}
|
||||
|
||||
scope.coroutineContext[Job]!!.join()
|
||||
}.second.join()
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
kotlin.code.style=official
|
||||
org.gradle.parallel=true
|
||||
|
||||
kotlin_version=1.5.10
|
||||
telegram_bot_api_version=0.35.0
|
||||
|
||||
kotlin_version=1.5.20
|
||||
telegram_bot_api_version=0.35.1
|
||||
micro_utils_version=0.5.15
|
||||
|
@ -6,3 +6,4 @@ include ":FilesLoaderBot"
|
||||
include ":ResenderBot:ResenderBotLib"
|
||||
include ":ResenderBot:jvm_launcher"
|
||||
include ":SlotMachineDetectorBot"
|
||||
include ":FSMBot"
|
||||
|
Loading…
Reference in New Issue
Block a user