Merge pull request #56 from InsanusMokrassar/0.35.1

0.35.1
This commit is contained in:
InsanusMokrassar 2021-06-30 20:42:03 +06:00 committed by GitHub
commit 12ef88c757
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 193 additions and 94 deletions

10
FSMBot/README.md Normal file
View 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
View 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"
}

View 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()
}

View File

@ -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.downloadFile
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.extensions.utils.flatMap import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.utils.shortcuts.* import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia
import dev.inmo.tgbotapi.utils.filenameFromUrl import dev.inmo.tgbotapi.utils.filenameFromUrl
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.* import kotlinx.coroutines.Dispatchers
import java.io.File import java.io.File
/** /**
@ -19,24 +17,15 @@ suspend fun main(args: Array<String>) {
val directoryOrFile = args.getOrNull(1) ?.let { File(it) } ?: File("") val directoryOrFile = args.getOrNull(1) ?.let { File(it) } ?: File("")
directoryOrFile.mkdirs() directoryOrFile.mkdirs()
val bot = telegramBot(botToken) telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
val scope = CoroutineScope(Dispatchers.Default) onMedia(includeMediaGroups = true) {
val pathedFile = bot.getFileAdditionalInfo(it.content.media)
bot.longPolling(scope = scope) { val file = File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
val flow = merge ( createNewFile()
filterContentMessages<MediaContent>(), writeBytes(bot.downloadFile(pathedFile))
mediaGroupMessages().flatMap()
)
flow.onEach {
safely({ it.printStackTrace() }) {
val pathedFile = bot.getFileAdditionalInfo(it.content.media)
File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
createNewFile()
writeBytes(bot.downloadFile(pathedFile))
}
} }
}.launchIn(scope) reply(it, "Saved to ${file.absolutePath}")
} }
onContentMessage { println(it) }
scope.coroutineContext[Job]!!.join() }.second.join()
} }

View File

@ -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.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.telegramBot import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.codeMarkdownV2 import dev.inmo.tgbotapi.extensions.utils.formatting.*
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.types.ParseMode.MarkdownV2 import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.message.* import dev.inmo.tgbotapi.types.message.*
import kotlinx.coroutines.* 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 * 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) { suspend fun main(vararg args: String) {
val botToken = args.first() val botToken = args.first()
val bot = telegramBot(botToken) telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
onContentMessage(includeMediaGroups = true) {
val scope = CoroutineScope(Dispatchers.Default) val toAnswer = buildEntities {
when (val forwardInfo = it.forwardInfo) {
bot.longPolling(scope = scope) { null -> +"There is no forward info"
(merge(messageFlow.asContentMessagesFlow(), mediaGroupMessages(scope).flatMap())).mapNotNull { it.asPossiblyForwardedMessage() }.onEach { message -> is AnonymousForwardInfo -> {
safely({ it.printStackTrace() }) { regular("Anonymous user which signed as \"") + code(forwardInfo.senderName) + "\""
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()
} }
is ForwardFromChannelInfo -> "Channel (".regularMarkdownV2() + (forwardInfo.channelChat).title.codeMarkdownV2() + ")".regularMarkdownV2() is UserForwardInfo -> {
is ForwardFromSupergroupInfo -> "Supergroup (".regularMarkdownV2() + (forwardInfo.group).title.codeMarkdownV2() + ")".regularMarkdownV2() val user = forwardInfo.from
regular("User ") + code(user.id.chatId.toString()) + " (${user.firstName} ${user.lastName}: ${user.username ?.username ?: "Without username"})"
}
is ForwardFromChannelInfo -> regular("Channel (") + code((forwardInfo.channelChat).title) + ")"
is ForwardFromSupergroupInfo -> regular("Supergroup (") + code((forwardInfo.group).title) + ")"
} }
bot.sendTextMessage(message.chat, toAnswer, MarkdownV2)
} }
}.launchIn(scope) reply(it, toAnswer)
} coroutineContext.job.invokeOnCompletion { println("completance of onContentMessage") }
}
scope.coroutineContext[Job]!!.join() coroutineContext.job.invokeOnCompletion { println("Completed :)") }
}.second.join()
} }

View File

@ -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.reply
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
import dev.inmo.tgbotapi.bot.Ktor.telegramBot 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.asChannelChat
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2 import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2 import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
@ -21,41 +23,30 @@ import kotlinx.coroutines.flow.onEach
suspend fun main(vararg args: String) { suspend fun main(vararg args: String) {
val botToken = args.first() val botToken = args.first()
val bot = telegramBot(botToken) telegramBotWithBehaviour(botToken, CoroutineScope(Dispatchers.IO)) {
onContentMessage { message ->
val scope = CoroutineScope(Dispatchers.Default) val chat = message.chat
if (chat is ChannelChat) {
bot.longPolling(scope = scope) { val answer = "Hi everybody in this channel \"${chat.title}\""
messageFlow.onEach { sendTextMessage(chat, answer, MarkdownV2)
safely { return@onContentMessage
val message = it.data
val chat = message.chat
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 {
chat.title.linkMarkdownV2(it)
} ?: chat.title
is GroupChat -> bot.getChat(chat).inviteLink ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title
else -> "Unknown :(".escapeMarkdownV2Common()
}
bot.reply(
message,
answerText,
MarkdownV2
)
} }
}.launchIn(scope) val answerText = "Oh, hi, " + when (chat) {
channelPostFlow.onEach { is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
safely { is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
val chat = it.data.chat is SupergroupChat -> (chat.username ?.username ?: getChat(chat).inviteLink) ?.let {
val message = "Hi everybody in this channel \"${(chat.asChannelChat()) ?.title}\"" chat.title.linkMarkdownV2(it)
bot.sendTextMessage(chat, message, MarkdownV2) } ?: chat.title
is GroupChat -> bot.getChat(chat).inviteLink ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title
else -> "Unknown :(".escapeMarkdownV2Common()
} }
}.launchIn(scope) reply(
} message,
answerText,
scope.coroutineContext[Job]!!.join() MarkdownV2
} )
}
}.second.join()
}

View File

@ -1,5 +1,7 @@
kotlin.code.style=official kotlin.code.style=official
org.gradle.parallel=true 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

View File

@ -6,3 +6,4 @@ include ":FilesLoaderBot"
include ":ResenderBot:ResenderBotLib" include ":ResenderBot:ResenderBotLib"
include ":ResenderBot:jvm_launcher" include ":ResenderBot:jvm_launcher"
include ":SlotMachineDetectorBot" include ":SlotMachineDetectorBot"
include ":FSMBot"