Skip to content

Commit a8aa799

Browse files
authored
Merge pull request #21 from kraftwerk28/ign-auth
Basic IGNAuth implementation (still not ready) + stability fixes
2 parents d6404d3 + 6660b25 commit a8aa799

14 files changed

+434
-148
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.kraftwerk28.spigot_tg_bridge
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.Dispatchers
5+
import kotlinx.coroutines.cancel
6+
import kotlinx.coroutines.launch
7+
import kotlinx.coroutines.runBlocking
8+
import kotlinx.coroutines.Job
9+
import kotlinx.coroutines.cancelAndJoin
10+
import org.bukkit.plugin.java.JavaPlugin
11+
12+
open class AsyncJavaPlugin : JavaPlugin() {
13+
private val scope = CoroutineScope(Dispatchers.Default)
14+
15+
override fun onEnable() {
16+
runBlocking { onEnableAsync() }
17+
}
18+
19+
override fun onDisable() {
20+
runBlocking {
21+
onDisableAsync()
22+
scope.coroutineContext[Job]?.cancelAndJoin()
23+
}
24+
}
25+
26+
open suspend fun onEnableAsync() = Unit
27+
28+
open suspend fun onDisableAsync() = Unit
29+
30+
fun <T> launch(f: suspend () -> T) = scope.launch { f() }
31+
}

src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/BotCommands.kt

+4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ class BotCommands(cfg: FileConfiguration) {
66
val time: String?
77
val online: String?
88
val chatID: String?
9+
val linkIgn: String?
10+
val getAllLinked: String?
911

1012
init {
1113
cfg.run {
1214
time = getString("commands.time")
1315
online = getString("commands.online")
1416
chatID = getString("commands.chat_id")
17+
linkIgn = getString("commands.link_ign")
18+
getAllLinked = getString("commands.list_linked")
1519
}
1620
}
1721
}

src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/CommandHandler.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class CommandHandler(private val plugin: Plugin) : CommandExecutor {
1616
if (sender !is ConsoleCommandSender) return false
1717
return when (label) {
1818
C.COMMANDS.PLUGIN_RELOAD -> {
19-
plugin.reload()
19+
plugin.launch { plugin.reload() }
2020
true
2121
}
2222
else -> false

src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Configuration.kt

+6
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ class Configuration(plugin: Plugin) {
1717
val logPlayerAsleep: Boolean
1818
val onlineString: String
1919
val nobodyOnlineString: String
20+
val enableIgnAuth: Boolean
2021

2122
// Telegram bot stuff
2223
val botToken: String
2324
val allowedChats: List<Long>
2425
val logFromTGtoMC: Boolean
2526
val allowWebhook: Boolean
2627
val webhookConfig: Map<String, Any>?
28+
val pollTimeout: Int
2729

2830
var commands: BotCommands
2931

@@ -78,10 +80,14 @@ class Configuration(plugin: Plugin) {
7880
)!!
7981
// isEnabled = getBoolean("enable", true)
8082
allowedChats = getLongList("chats")
83+
enableIgnAuth = getBoolean("enableIgnAuth", false)
84+
8185
botToken = getString("botToken") ?: throw Exception(C.WARN.noToken)
8286
allowWebhook = getBoolean("useWebhook", false)
8387
@Suppress("unchecked_cast")
8488
webhookConfig = get("webhookConfig") as Map<String, Any>?
89+
pollTimeout = getInt("pollTimeout", 30)
90+
8591
logJoinLeave = getBoolean("logJoinLeave", false)
8692
onlineString = getString("strings.online", "Online")!!
8793
nobodyOnlineString = getString(

src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/Constants.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ object Constants {
88
const val noUsername = "Bot username must be defined."
99
}
1010
object INFO {
11-
const val reloading = "Reloading plugin... This may take some time."
11+
const val reloading = "Reloading..."
1212
const val reloadComplete = "Reload completed."
1313
}
1414
object TIMES_OF_DAY {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.kraftwerk28.spigot_tg_bridge
2+
3+
import java.sql.Date
4+
import com.google.gson.annotations.SerializedName as Name
5+
6+
data class TgResponse<T>(
7+
val ok: Boolean,
8+
val result: T?,
9+
val description: String?,
10+
)
11+
12+
data class WebhookOptions(val drop_pending_updates: Boolean)
13+
14+
data class User(
15+
@Name("id") val id: Long,
16+
@Name("is_bot") val isBot: Boolean,
17+
@Name("first_name") val firstName: String,
18+
@Name("last_name") val lastName: String? = null,
19+
@Name("username") val username: String? = null,
20+
@Name("language_code") val languageCode: String? = null,
21+
)
22+
23+
data class Chat(
24+
val id: Long,
25+
val type: String,
26+
val title: String? = null,
27+
val username: String? = null,
28+
@Name("first_name") val firstName: String? = null,
29+
@Name("last_name") val lastName: String? = null,
30+
)
31+
32+
data class Message(
33+
@Name("message_id") val messageId: Long,
34+
val from: User? = null,
35+
@Name("sender_chat") val senderChat: Chat? = null,
36+
val date: Long,
37+
val chat: Chat,
38+
@Name("reply_to_message") val replyToMessage: Message? = null,
39+
val text: String? = null,
40+
)
41+
42+
data class Update(
43+
@Name("update_id") val updateId: Long,
44+
val message: Message? = null,
45+
)
46+
47+
data class BotCommand(val command: String, val description: String)
48+
49+
data class SetMyCommands(val commands: List<BotCommand>)
50+
51+
data class DbLinkedUser(
52+
val tgId: Long,
53+
val tgFirstName: String,
54+
val tgLastName: String?,
55+
val tgUsername: String?,
56+
val minecraftUuid: String,
57+
val minecraftUsername: String,
58+
val createdTimestamp: Date,
59+
)

src/main/kotlin/org/kraftwerk28/spigot_tg_bridge/EventHandler.kt

+13-6
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ import org.bukkit.event.player.PlayerJoinEvent
99
import org.bukkit.event.player.PlayerQuitEvent
1010

1111
class EventHandler(
12+
private val plugin: Plugin,
13+
private val config: Configuration,
1214
private val tgBot: TgBot,
13-
private val config: Configuration
1415
) : Listener {
1516

1617
@EventHandler
1718
fun onPlayerChat(event: AsyncPlayerChatEvent) {
1819
if (!config.logFromMCtoTG) return
1920
event.run {
20-
tgBot.sendMessageToTelegram(message, player.displayName)
21+
sendMessage(message, player.displayName)
2122
}
2223
}
2324

@@ -26,15 +27,15 @@ class EventHandler(
2627
if (!config.logJoinLeave) return
2728
val username = event.player.displayName.fullEscape()
2829
val text = config.joinString.replace("%username%", username)
29-
tgBot.sendMessageToTelegram(text)
30+
sendMessage(text)
3031
}
3132

3233
@EventHandler
3334
fun onPlayerLeave(event: PlayerQuitEvent) {
3435
if (!config.logJoinLeave) return
3536
val username = event.player.displayName.fullEscape()
3637
val text = config.leaveString.replace("%username%", username)
37-
tgBot.sendMessageToTelegram(text)
38+
sendMessage(text)
3839
}
3940

4041
@EventHandler
@@ -43,7 +44,7 @@ class EventHandler(
4344
event.deathMessage?.let {
4445
val username = event.entity.displayName.fullEscape()
4546
val text = it.replace(username, "<i>$username</i>")
46-
tgBot.sendMessageToTelegram(text)
47+
sendMessage(text)
4748
}
4849
}
4950

@@ -53,6 +54,12 @@ class EventHandler(
5354
if (event.bedEnterResult != PlayerBedEnterEvent.BedEnterResult.OK)
5455
return
5556
val text = "<i>${event.player.displayName}</i> fell asleep."
56-
tgBot.sendMessageToTelegram(text)
57+
sendMessage(text)
58+
}
59+
60+
private fun sendMessage(text: String, username: String? = null) {
61+
plugin.launch {
62+
tgBot.sendMessageToTelegram(text, username)
63+
}
5764
}
5865
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.kraftwerk28.spigot_tg_bridge
2+
3+
import java.sql.Connection
4+
import java.sql.DriverManager
5+
import java.sql.SQLException
6+
7+
const val INIT_DB_QUERY = """
8+
create table if not exists user (
9+
tg_id bigint not null primary key,
10+
tg_username varchar,
11+
tg_first_name varchar not null,
12+
tg_last_name varchar,
13+
mc_username varchar,
14+
mc_uuid varchar,
15+
linked_timestamp datetime default current_timestamp
16+
);
17+
"""
18+
19+
class IgnAuth(
20+
fileName: String,
21+
val plugin: Plugin,
22+
var conn: Connection? = null,
23+
) {
24+
init {
25+
plugin.launch {
26+
initializeConnection(fileName)
27+
}
28+
}
29+
30+
suspend fun initializeConnection(fileName: String) = try {
31+
DriverManager.getConnection("jdbc:sqlite:$fileName").apply {
32+
createStatement().execute(INIT_DB_QUERY)
33+
}.also {
34+
conn = it
35+
}
36+
} catch (e: SQLException) {
37+
plugin.logger.info(e.message)
38+
}
39+
40+
suspend fun close() = conn?.run {
41+
close()
42+
}
43+
44+
suspend fun linkUser(
45+
tgId: Long,
46+
tgUsername: String? = null,
47+
tgFirstName: String,
48+
tgLastName: String? = null,
49+
minecraftUsername: String?,
50+
minecraftUuid: String,
51+
): Boolean = conn?.stmt(
52+
"""
53+
insert into user (
54+
tg_id,
55+
tg_username,
56+
tg_first_name,
57+
tg_last_name,
58+
mc_uuid,
59+
mc_username,
60+
)
61+
values (?, ?, ?, ?, ?, ?)
62+
""",
63+
tgId,
64+
tgUsername,
65+
tgFirstName,
66+
tgLastName,
67+
minecraftUuid,
68+
minecraftUsername,
69+
)?.run {
70+
execute()
71+
} ?: false
72+
73+
suspend fun getLinkedUserByIgn(ign: String) =
74+
conn?.stmt("select * from user where mc_uuid = ?", ign)?.first {
75+
toLinkedUser()
76+
}
77+
78+
suspend fun getLinkedUserByTgId(id: Long) =
79+
conn?.stmt("select * from user where tg_id = ?", id)?.first {
80+
toLinkedUser()
81+
}
82+
83+
suspend fun unlinkUserByTgId(id: Long) =
84+
conn?.stmt("delete from user where tg_id = ?", id)?.run {
85+
executeUpdate() > 0
86+
}
87+
88+
suspend fun getAllLinkedUsers() =
89+
conn?.stmt("select * from user")?.map { toLinkedUser() }
90+
}

0 commit comments

Comments
 (0)