Refactoring, 'cause I finally got IJ Idea

This commit is contained in:
kraftwerk28 2021-07-11 17:22:04 +03:00
parent a8aa799b96
commit 4bcd274df4
6 changed files with 71 additions and 74 deletions

1
.gitignore vendored
View File

@ -25,3 +25,4 @@ hs_err_pid*
build/ build/
.gradle/ .gradle/
local.properties local.properties
.idea/

View File

@ -2,7 +2,6 @@ package org.kraftwerk28.spigot_tg_bridge
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.Job import kotlinx.coroutines.Job

View File

@ -37,7 +37,7 @@ class Configuration(plugin: Plugin) {
// plugin.saveResource(C.configFilename, false); // plugin.saveResource(C.configFilename, false);
throw Exception(C.WARN.noConfigWarning) throw Exception(C.WARN.noConfigWarning)
} }
val pluginConfig = plugin.getConfig() val pluginConfig = plugin.config
pluginConfig.load(cfgFile) pluginConfig.load(cfgFile)
pluginConfig.getString("minecraftMessageFormat")?.let { pluginConfig.getString("minecraftMessageFormat")?.let {

View File

@ -18,8 +18,8 @@ create table if not exists user (
class IgnAuth( class IgnAuth(
fileName: String, fileName: String,
val plugin: Plugin, private val plugin: Plugin,
var conn: Connection? = null, private var conn: Connection? = null,
) { ) {
init { init {
plugin.launch { plugin.launch {
@ -27,7 +27,7 @@ class IgnAuth(
} }
} }
suspend fun initializeConnection(fileName: String) = try { private fun initializeConnection(fileName: String) = try {
DriverManager.getConnection("jdbc:sqlite:$fileName").apply { DriverManager.getConnection("jdbc:sqlite:$fileName").apply {
createStatement().execute(INIT_DB_QUERY) createStatement().execute(INIT_DB_QUERY)
}.also { }.also {
@ -37,11 +37,11 @@ class IgnAuth(
plugin.logger.info(e.message) plugin.logger.info(e.message)
} }
suspend fun close() = conn?.run { fun close() = conn?.run {
close() close()
} }
suspend fun linkUser( fun linkUser(
tgId: Long, tgId: Long,
tgUsername: String? = null, tgUsername: String? = null,
tgFirstName: String, tgFirstName: String,
@ -70,21 +70,21 @@ class IgnAuth(
execute() execute()
} ?: false } ?: false
suspend fun getLinkedUserByIgn(ign: String) = fun getLinkedUserByIgn(ign: String) =
conn?.stmt("select * from user where mc_uuid = ?", ign)?.first { conn?.stmt("select * from user where mc_uuid = ?", ign)?.first {
toLinkedUser() toLinkedUser()
} }
suspend fun getLinkedUserByTgId(id: Long) = fun getLinkedUserByTgId(id: Long) =
conn?.stmt("select * from user where tg_id = ?", id)?.first { conn?.stmt("select * from user where tg_id = ?", id)?.first {
toLinkedUser() toLinkedUser()
} }
suspend fun unlinkUserByTgId(id: Long) = fun unlinkUserByTgId(id: Long) =
conn?.stmt("delete from user where tg_id = ?", id)?.run { conn?.stmt("delete from user where tg_id = ?", id)?.run {
executeUpdate() > 0 executeUpdate() > 0
} }
suspend fun getAllLinkedUsers() = fun getAllLinkedUsers() =
conn?.stmt("select * from user")?.map { toLinkedUser() } conn?.stmt("select * from user")?.map { toLinkedUser() }
} }

View File

@ -1,45 +1,55 @@
package org.kraftwerk28.spigot_tg_bridge package org.kraftwerk28.spigot_tg_bridge
import kotlinx.coroutines.delay
import org.bukkit.event.HandlerList import org.bukkit.event.HandlerList
import java.lang.Exception import java.lang.Exception
import kotlin.system.measureTimeMillis
import org.kraftwerk28.spigot_tg_bridge.Constants as C import org.kraftwerk28.spigot_tg_bridge.Constants as C
class Plugin : AsyncJavaPlugin() { class Plugin : AsyncJavaPlugin() {
var tgBot: TgBot? = null private var tgBot: TgBot? = null
private var eventHandler: EventHandler? = null private var eventHandler: EventHandler? = null
var config: Configuration? = null private var config: Configuration? = null
var ignAuth: IgnAuth? = null var ignAuth: IgnAuth? = null
override suspend fun onEnableAsync() = try { override suspend fun onEnableAsync() {
config = Configuration(this).also { config -> try {
if (!config.isEnabled) return launch {
config = Configuration(this).also {
if (config.enableIgnAuth) { initializeWithConfig(it)
val dbFilePath = dataFolder.resolve("spigot-tg-bridge.sqlite")
ignAuth = IgnAuth(
fileName = dbFilePath.absolutePath,
plugin = this,
)
}
tgBot?.run { stop() }
tgBot = TgBot(this, config).also { bot ->
bot.startPolling()
eventHandler = EventHandler(this, config, bot).also {
server.pluginManager.registerEvents(it, this)
} }
} }
} catch (e: Exception) {
// Configuration file is missing or incomplete
logger.warning(e.message)
}
}
getCommand(C.COMMANDS.PLUGIN_RELOAD)?.run { private suspend fun initializeWithConfig(config: Configuration) {
setExecutor(CommandHandler(this@Plugin)) if (!config.isEnabled) return
}
config.serverStartMessage?.let { if (config.enableIgnAuth) {
tgBot?.sendMessageToTelegram(it) val dbFilePath = dataFolder.resolve("spigot-tg-bridge.sqlite")
ignAuth = IgnAuth(
fileName = dbFilePath.absolutePath,
plugin = this,
)
}
tgBot?.run { stop() }
tgBot = TgBot(this, config).also { bot ->
bot.startPolling()
eventHandler = EventHandler(this, config, bot).also {
server.pluginManager.registerEvents(it, this)
} }
} }
} catch (e: Exception) {
// Configuration file is missing or incomplete getCommand(C.COMMANDS.PLUGIN_RELOAD)?.run {
logger.warning(e.message) setExecutor(CommandHandler(this@Plugin))
}
config.serverStartMessage?.let {
tgBot?.sendMessageToTelegram(it)
}
} }
override suspend fun onDisableAsync() { override suspend fun onDisableAsync() {
@ -52,6 +62,7 @@ class Plugin : AsyncJavaPlugin() {
eventHandler?.let { HandlerList.unregisterAll(it) } eventHandler?.let { HandlerList.unregisterAll(it) }
tgBot?.run { stop() } tgBot?.run { stop() }
tgBot = null tgBot = null
ignAuth?.close()
} }
} }

View File

@ -5,30 +5,35 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import java.time.Duration import java.time.Duration
import org.kraftwerk28.spigot_tg_bridge.Constants as C import org.kraftwerk28.spigot_tg_bridge.Constants as C
typealias UpdateRequest = Call<TgResponse<List<Update>>>?
typealias CmdHandler = suspend (HandlerContext) -> Unit typealias CmdHandler = suspend (HandlerContext) -> Unit
data class HandlerContext( data class HandlerContext(
val update: Update, val update: Update,
val message: Message?, val message: Message?,
val chat: Chat?, val chat: Chat?,
val commandArgs: List<String>, val commandArgs: List<String> = listOf(),
) )
class TgBot( class TgBot(
private val plugin: Plugin, private val plugin: Plugin,
private val config: Configuration, private val config: Configuration,
) { ) {
private val api: TgApiService private val client: OkHttpClient = OkHttpClient
private val client: OkHttpClient .Builder()
.readTimeout(Duration.ZERO)
.build()
private val api = Retrofit.Builder()
.baseUrl("https://api.telegram.org/bot${config.botToken}/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TgApiService::class.java)
private val updateChan = Channel<Update>() private val updateChan = Channel<Update>()
private var pollJob: Job? = null private var pollJob: Job? = null
private var handlerJob: Job? = null private var handlerJob: Job? = null
@ -46,24 +51,11 @@ class TgBot(
) )
} }
init {
client = OkHttpClient
.Builder()
.readTimeout(Duration.ZERO)
.build()
api = Retrofit.Builder()
.baseUrl("https://api.telegram.org/bot${config.botToken}/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TgApiService::class.java)
}
private suspend fun initialize() { private suspend fun initialize() {
me = api.getMe().result!! me = api.getMe().result!!
// I intentionally don't put optional @username in regex // I intentionally don't put optional @username in regex
// since bot is only used in group chats // since bot is only used in group chats
commandRegex = """^\/(\w+)(?:@${me!!.username})(?:\s+(.+))?$""".toRegex() commandRegex = """^/(\w+)@${me!!.username}(?:\s+(.+))?$""".toRegex()
val commands = config.commands.run { listOf(time, online, chatID) } val commands = config.commands.run { listOf(time, online, chatID) }
.zip( .zip(
C.COMMAND_DESC.run { C.COMMAND_DESC.run {
@ -88,13 +80,13 @@ class TgBot(
} }
private fun initPolling() = plugin.launch { private fun initPolling() = plugin.launch {
loop@ while (true) { loop@while (true) {
try { try {
api.getUpdates( api.getUpdates(
offset = currentOffset, offset = currentOffset,
timeout = config.pollTimeout, timeout = config.pollTimeout,
).result?.let { updates -> ).result?.let { updates ->
if (!updates.isEmpty()) { if (updates.isNotEmpty()) {
updates.forEach { updateChan.send(it) } updates.forEach { updateChan.send(it) }
currentOffset = updates.last().updateId + 1 currentOffset = updates.last().updateId + 1
} }
@ -122,20 +114,19 @@ class TgBot(
} }
} }
suspend fun handleUpdate(update: Update) { private suspend fun handleUpdate(update: Update) {
// Ignore PM or channel // Ignore private message or channel post
if (listOf("private", "channel").contains(update.message?.chat?.type)) if (listOf("private", "channel").contains(update.message?.chat?.type))
return return
var ctx = HandlerContext( val ctx = HandlerContext(
update, update,
update.message, update.message,
update.message?.chat, update.message?.chat,
listOf(),
) )
update.message?.text?.let { update.message?.text?.let {
commandRegex?.matchEntire(it)?.groupValues?.let { commandRegex?.matchEntire(it)?.groupValues?.let { matchList ->
commandMap.get(it[1])?.run { commandMap[matchList[1]]?.run {
val args = it[2].split("\\s+".toRegex()) val args = matchList[2].split("\\s+".toRegex())
this(ctx.copy(commandArgs = args)) this(ctx.copy(commandArgs = args))
} }
} ?: run { } ?: run {
@ -204,7 +195,7 @@ class TgBot(
private suspend fun linkIgnHandler(ctx: HandlerContext) { private suspend fun linkIgnHandler(ctx: HandlerContext) {
val tgUser = ctx.message!!.from!! val tgUser = ctx.message!!.from!!
val mcUuid = getMinecraftUuidByUsername(ctx.message.text!!) val mcUuid = getMinecraftUuidByUsername(ctx.message.text!!)
if (mcUuid == null || ctx.commandArgs.size < 1) { if (mcUuid == null || ctx.commandArgs.isEmpty()) {
// Respond... // Respond...
return return
} }
@ -236,7 +227,7 @@ class TgBot(
} }
} }
private suspend fun onTextHandler( private fun onTextHandler(
@Suppress("unused_parameter") ctx: HandlerContext @Suppress("unused_parameter") ctx: HandlerContext
) { ) {
val msg = ctx.message!! val msg = ctx.message!!
@ -258,10 +249,5 @@ class TgBot(
config.allowedChats.forEach { chatId -> config.allowedChats.forEach { chatId ->
api.sendMessage(chatId, formatted) api.sendMessage(chatId, formatted)
} }
// plugin.launch {
// config.allowedChats.forEach { chatId ->
// api.sendMessage(chatId, formatted)
// }
// }
} }
} }