From 5b4374f0c9abbdb03d310260e1efa839152c21ec Mon Sep 17 00:00:00 2001 From: kraftwerk28 Date: Sat, 10 Jul 2021 02:00:22 +0300 Subject: [PATCH] fix: stability issues --- .../spigot_tg_bridge/AsyncJavaPlugin.kt | 12 +- .../kraftwerk28/spigot_tg_bridge/Plugin.kt | 1 + .../org/kraftwerk28/spigot_tg_bridge/TgBot.kt | 108 +++++++++++------- 3 files changed, 69 insertions(+), 52 deletions(-) diff --git a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/AsyncJavaPlugin.kt b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/AsyncJavaPlugin.kt index 7e01bd4..71950cf 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/AsyncJavaPlugin.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/AsyncJavaPlugin.kt @@ -2,15 +2,13 @@ package org.kraftwerk28.spigot_tg_bridge import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.joinAll +import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.bukkit.plugin.java.JavaPlugin open class AsyncJavaPlugin : JavaPlugin() { private val scope = CoroutineScope(Dispatchers.Default) - private val jobs: MutableList = mutableListOf() override fun onEnable() { runBlocking { onEnableAsync() } @@ -19,7 +17,7 @@ open class AsyncJavaPlugin : JavaPlugin() { override fun onDisable() { runBlocking { onDisableAsync() - jobs.joinAll() + scope.cancel() } } @@ -27,9 +25,5 @@ open class AsyncJavaPlugin : JavaPlugin() { open suspend fun onDisableAsync() = Unit - fun launch(f: suspend () -> T) = scope.launch { - f() - }.also { - jobs.add(it) - } + fun launch(f: suspend () -> T) = scope.launch { f() } } diff --git a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Plugin.kt b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Plugin.kt index 67fba90..4880eba 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Plugin.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Plugin.kt @@ -82,6 +82,7 @@ class Plugin : AsyncJavaPlugin() { eventHandler?.let { HandlerList.unregisterAll(it) } tgBot?.run { stop() } tgBot = TgBot(this, config).also { bot -> + bot.startPolling() eventHandler = EventHandler(this, config, bot).also { server.pluginManager.registerEvents(it, this) } diff --git a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/TgBot.kt b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/TgBot.kt index b36e237..725c532 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/TgBot.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/TgBot.kt @@ -14,6 +14,14 @@ import java.time.Duration import org.kraftwerk28.spigot_tg_bridge.Constants as C typealias UpdateRequest = Call>>? +typealias CmdHandler = suspend (HandlerContext) -> Unit + +data class HandlerContext( + val update: Update, + val message: Message?, + val chat: Chat?, + val commandArgs: List, +) class TgBot( private val plugin: Plugin, @@ -27,16 +35,16 @@ class TgBot( private var currentOffset: Long = -1 private var me: User? = null private var commandRegex: Regex? = null - private val commandMap: Map Unit> = - config.commands.run { - mapOf( - online to ::onlineHandler, - time to ::timeHandler, - chatID to ::chatIdHandler, - linkIgn to ::linkIgnHandler, - getAllLinked to ::getLinkedUsersHandler, - ) - } + private val commandMap: Map = config.commands.run { + mapOf( + online to ::onlineHandler, + time to ::timeHandler, + chatID to ::chatIdHandler, + // TODO: + // linkIgn to ::linkIgnHandler, + // getAllLinked to ::getLinkedUsersHandler, + ) + } init { client = OkHttpClient @@ -55,7 +63,7 @@ class TgBot( me = api.getMe().result!! // I intentionally don't put optional @username in regex // since bot is only used in group chats - commandRegex = """^\/(\w+)(?:@${me!!.username})$""".toRegex() + commandRegex = """^\/(\w+)(?:@${me!!.username})(?:\s+(.+))?$""".toRegex() val commands = config.commands.run { listOf(time, online, chatID) } .zip( C.COMMAND_DESC.run { @@ -118,17 +126,26 @@ class TgBot( // Ignore PM or channel if (listOf("private", "channel").contains(update.message?.chat?.type)) return + var ctx = HandlerContext( + update, + update.message, + update.message?.chat, + listOf(), + ) update.message?.text?.let { commandRegex?.matchEntire(it)?.groupValues?.let { - commandMap.get(it[1])?.let { it(update) } + commandMap.get(it[1])?.run { + val args = it[2].split("\\s+".toRegex()) + this(ctx.copy(commandArgs = args)) + } } ?: run { - onTextHandler(update) + onTextHandler(ctx) } } } - private suspend fun timeHandler(update: Update) { - val msg = update.message!! + private suspend fun timeHandler(ctx: HandlerContext) { + val msg = ctx.message!! if (!config.allowedChats.contains(msg.chat.id)) { return } @@ -154,8 +171,8 @@ class TgBot( api.sendMessage(msg.chat.id, text, replyToMessageId = msg.messageId) } - private suspend fun onlineHandler(update: Update) { - val msg = update.message!! + private suspend fun onlineHandler(ctx: HandlerContext) { + val msg = ctx.message!! if (!config.allowedChats.contains(msg.chat.id)) { return } @@ -170,8 +187,8 @@ class TgBot( api.sendMessage(msg.chat.id, text, replyToMessageId = msg.messageId) } - private suspend fun chatIdHandler(update: Update) { - val msg = update.message!! + private suspend fun chatIdHandler(ctx: HandlerContext) { + val msg = ctx.message!! val chatId = msg.chat.id val text = """ |Chat ID: $chatId. @@ -184,25 +201,45 @@ class TgBot( api.sendMessage(chatId, text, replyToMessageId = msg.messageId) } - private suspend fun linkIgnHandler(update: Update) { - val tgUser = update.message!!.from!! - val mcUuid = getMinecraftUuidByUsername(update.message.text!!) - if (mcUuid == null) { + private suspend fun linkIgnHandler(ctx: HandlerContext) { + val tgUser = ctx.message!!.from!! + val mcUuid = getMinecraftUuidByUsername(ctx.message.text!!) + if (mcUuid == null || ctx.commandArgs.size < 1) { // Respond... return } + val (minecraftIgn) = ctx.commandArgs val linked = plugin.ignAuth?.linkUser( tgId = tgUser.id, tgFirstName = tgUser.firstName, tgLastName = tgUser.lastName, - minecraftUsername = tgUser.username, + minecraftUsername = minecraftIgn, minecraftUuid = mcUuid, - ) - println(tgUser.toString()) + ) ?: false + if (linked) { + // TODO + } } - private suspend fun onTextHandler(update: Update) { - val msg = update.message!! + private suspend fun getLinkedUsersHandler(ctx: HandlerContext) { + val linkedUsers = plugin.ignAuth?.run { + getAllLinkedUsers() + } ?: listOf() + if (linkedUsers.isEmpty()) { + api.sendMessage(ctx.message!!.chat.id, "No linked users.") + } else { + val text = "Linked users:\n" + + linkedUsers.mapIndexed { i, dbUser -> + "${i + 1}. ${dbUser.fullName()}" + }.joinToString("\n") + api.sendMessage(ctx.message!!.chat.id, text) + } + } + + private suspend fun onTextHandler( + @Suppress("unused_parameter") ctx: HandlerContext + ) { + val msg = ctx.message!! if (!config.logFromTGtoMC || msg.from == null) return plugin.sendMessageToMinecraft( @@ -212,21 +249,6 @@ class TgBot( ) } - private suspend fun getLinkedUsersHandler(update: Update) { - val linkedUsers = plugin.ignAuth?.run { - getAllLinkedUsers() - } ?: listOf() - if (linkedUsers.isEmpty()) { - api.sendMessage(update.message!!.chat.id, "No linked users.") - } else { - val text = "Linked users:\n" + - linkedUsers.mapIndexed { i, dbUser -> - "${i + 1}. ${dbUser.fullName()}" - }.joinToString("\n") - api.sendMessage(update.message!!.chat.id, text) - } - } - suspend fun sendMessageToTelegram(text: String, username: String? = null) { val formatted = username?.let { config.telegramFormat