diff --git a/build.gradle.kts b/build.gradle.kts index 3be5592..ab4439b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,9 +6,11 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile buildscript { repositories { mavenCentral() + maven("https://plugins.gradle.org/m2/") } dependencies { - classpath(group = "org.yaml", name = "snakeyaml", version = "1.26") + classpath("org.yaml:snakeyaml:1.26") + classpath("org.jlleitschuh.gradle:ktlint-gradle:10.1.0") } } @@ -17,11 +19,12 @@ plugins { id("com.github.johnrengelman.shadow") version "5.2.0" } +apply(plugin = "org.jlleitschuh.gradle.ktlint") + group = "org.kraftwerk28" -val cfg: Map = Yaml().load( - FileInputStream("src/main/resources/plugin.yml") -) +val cfg: Map = Yaml() + .load(FileInputStream("$projectDir/src/main/resources/plugin.yml")) val pluginVersion = cfg.get("version") val spigotApiVersion = cfg.get("api-version") version = pluginVersion as Any diff --git a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/ApiService.kt b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/ApiService.kt index 19e1b52..fd06cef 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/ApiService.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/ApiService.kt @@ -57,11 +57,11 @@ interface TgApiService { ): TgResponse @GET("getUpdates") - fun getUpdates( + suspend fun getUpdates( @Query("offset") offset: Long, @Query("limit") limit: Int = 100, @Query("timeout") timeout: Int = 0, - ): Call>> + ): TgResponse> @GET("getMe") suspend fun getMe(): TgResponse diff --git a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Configuration.kt b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Configuration.kt index 904ef59..8f08045 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Configuration.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Configuration.kt @@ -36,8 +36,9 @@ class Configuration(plugin: Plugin) { // plugin.saveResource(C.configFilename, false); throw Exception(C.WARN.noConfigWarning) } - val pluginConfig = plugin.getConfig() + pluginConfig.load(cfgFile) + pluginConfig.getString("minecraftMessageFormat")?.let { plugin.logger.warning(""" Config option "minecraftMessageFormat" is deprecated. @@ -47,6 +48,7 @@ class Configuration(plugin: Plugin) { pluginConfig.set("minecraftMessageFormat", null) plugin.saveConfig() } + pluginConfig.getString("telegramMessageFormat")?.let { plugin.logger.warning(""" Config option "telegramMessageFormat" is deprecated. diff --git a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/EventHandler.kt b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/EventHandler.kt index 0be14f3..556a40e 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/EventHandler.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/EventHandler.kt @@ -7,6 +7,8 @@ import org.bukkit.event.player.AsyncPlayerChatEvent import org.bukkit.event.player.PlayerBedEnterEvent import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerQuitEvent +import org.bukkit.event.world.WorldLoadEvent +import org.bukkit.event.world.WorldUnloadEvent class EventHandler( private val tgBot: TgBot, @@ -17,9 +19,7 @@ class EventHandler( fun onPlayerChat(event: AsyncPlayerChatEvent) { if (!config.logFromMCtoTG) return event.run { - tgBot.sendMessageToTelegram( - message, player.displayName - ) + tgBot.sendMessageToTelegram(message, player.displayName) } } 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 fdda5db..228b106 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Plugin.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Plugin.kt @@ -29,25 +29,22 @@ class Plugin : JavaPlugin() { } getCommand(C.COMMANDS.PLUGIN_RELOAD)?.setExecutor(cmdHandler) - // Notify Telegram groups about server start config.serverStartMessage?.let { message -> tgBot?.sendMessageToTelegram(message) } - logger.info("Plugin started.") } fun loadBot() { - tgBot?.let { it.stop() } + tgBot?.run { stop() } tgBot = TgBot(this, config) } override fun onDisable() { - if (!config.isEnabled) - return + if (!config.isEnabled) return config.serverStopMessage?.let { - tgBot?.sendMessageToTelegram(it) + tgBot?.sendMessageToTelegram(it, blocking = true) } - logger.info("Plugin stopped.") + tgBot?.run { stop() } } fun sendMessageToMinecraft( 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 98b534b..0b8c73b 100644 --- a/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/TgBot.kt +++ b/src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/TgBot.kt @@ -10,6 +10,10 @@ import retrofit2.Call import retrofit2.converter.gson.GsonConverterFactory import java.time.Duration +typealias UpdateRequest = Call< + TgApiService.TgResponse> +>? + class TgBot( private val plugin: Plugin, private val config: Configuration, @@ -66,40 +70,47 @@ class TgBot( } private fun initPolling() = scope.launch { - var request: - Call>>? = null - try { - while (true) { - try { - request = api.getUpdates( - offset = currentOffset, - timeout = pollTimeout, - ) - val response = request.execute().body() - response?.result?.let { updates -> + loop@ while (true) { + try { + api.getUpdates(offset = currentOffset, timeout = pollTimeout) + .result?.let { updates -> if (!updates.isEmpty()) { updates.forEach { updateChan.send(it) } currentOffset = updates.last().updateId + 1 } } - } catch (e: Exception) { - e.printStackTrace() + } catch (e: Exception) { + when (e) { + is CancellationException -> break@loop + else -> { + e.printStackTrace() + continue@loop + } } } - } catch (e: CancellationException) { - request?.cancel() } } private fun initHandler() = scope.launch { - try { - while (true) { + loop@ while (true) { + try { handleUpdate(updateChan.receive()) + } catch (e: Exception) { + when (e) { + is CancellationException -> break@loop + else -> { + e.printStackTrace() + continue@loop + } + } } - } catch (e: CancellationException) {} + } } suspend fun handleUpdate(update: TgApiService.Update) { + // Ignore PM or channel + if (listOf("private", "channel").contains(update.message?.chat?.type)) + return update.message?.text?.let { commandRegex.matchEntire(it)?.groupValues?.let { commandMap[it[1]]?.let { it(update) } @@ -167,25 +178,16 @@ class TgBot( val msg = update.message!! val chatId = msg.chat.id val text = """ - Chat ID: - ${chatId} - paste this id to chats: section in you config.yml file so it will look like this: - """.trimIndent() + - "\n\nchats:\n # other ids...\n - ${chatId}" + |Chat ID: ${chatId}. + |Copy this id to chats section in your config.yml file so it will look like this: + | + |
chats:
+        |  # other ids...
+        |  - ${chatId}
+ """.trimMargin() api.sendMessage(chatId, text, replyToMessageId = msg.messageId) } - fun sendMessageToTelegram(text: String, username: String? = null) { - val messageText = username?.let { - formatMsgFromMinecraft(it, text) - } ?: text - config.allowedChats.forEach { chatId -> - scope.launch { - api.sendMessage(chatId, messageText) - } - } - } - private suspend fun onTextHandler(update: TgApiService.Update) { val msg = update.message!! if (!config.logFromTGtoMC || msg.from == null) @@ -197,11 +199,22 @@ class TgBot( ) } - private fun formatMsgFromMinecraft( - username: String, - text: String - ): String = - config.telegramFormat - .replace(C.USERNAME_PLACEHOLDER, username.fullEscape()) - .replace(C.MESSAGE_TEXT_PLACEHOLDER, text.escapeHtml()) + fun sendMessageToTelegram( + text: String, + username: String? = null, + blocking: Boolean = false, + ) { + val formatted = username?.let { + config.telegramFormat + .replace(C.USERNAME_PLACEHOLDER, username.fullEscape()) + .replace(C.MESSAGE_TEXT_PLACEHOLDER, text.escapeHtml()) + } ?: text + scope.launch { + config.allowedChats.forEach { chatId -> + api.sendMessage(chatId, formatted) + } + }.also { + if (blocking) runBlocking { it.join() } + } + } }