From 294bf04a5050d2fde43c079f893c1b5d38604496 Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Wed, 12 Jun 2024 19:52:58 +0900 Subject: [PATCH] add ping command, chzzk Connector.kt --- build.gradle.kts | 6 ++- inc.env | 4 +- src/main/kotlin/space/mori/chzzk_bot/Main.kt | 3 ++ .../space/mori/chzzk_bot/chzzk/Connector.kt | 14 +++++++ .../space/mori/chzzk_bot/discord/Commands.kt | 35 ++++++++++++++++ .../space/mori/chzzk_bot/discord/Discord.kt | 36 ++++++++++------ .../mori/chzzk_bot/discord/commands/Ping.kt | 17 ++++++++ .../META-INF/native-image/reflect-config.json | 42 +++++++++++++++++++ .../native-image/resource-config.json | 6 +++ 9 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/space/mori/chzzk_bot/chzzk/Connector.kt create mode 100644 src/main/kotlin/space/mori/chzzk_bot/discord/Commands.kt create mode 100644 src/main/kotlin/space/mori/chzzk_bot/discord/commands/Ping.kt diff --git a/build.gradle.kts b/build.gradle.kts index 551e7c6..90c8074 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -69,14 +69,16 @@ dependencies { // https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-kotlin-datetime runtimeOnly("org.jetbrains.exposed:exposed-kotlin-datetime:0.51.1") - - // https://mvnrepository.com/artifact/com.zaxxer/HikariCP implementation("com.zaxxer:HikariCP:5.1.0") + // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC") // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-reflect implementation("org.jetbrains.kotlin:kotlin-reflect:2.0.0") + // https://mvnrepository.com/artifact/org.reflections/reflections + implementation("org.reflections:reflections:0.10.2") + // https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client implementation("org.mariadb.jdbc:mariadb-java-client:3.4.0") diff --git a/inc.env b/inc.env index c8c2959..0c7848a 100644 --- a/inc.env +++ b/inc.env @@ -3,4 +3,6 @@ GUILD_ID= DB_URL=jdbc:mariadb://localhost:3306/chzzk DB_USER=chzzk DB_PASS=chzzk -RUN_AGENT=false \ No newline at end of file +RUN_AGENT=false +NID_AUT= +NID_SES= \ No newline at end of file diff --git a/src/main/kotlin/space/mori/chzzk_bot/Main.kt b/src/main/kotlin/space/mori/chzzk_bot/Main.kt index 6b2bb36..da597a0 100644 --- a/src/main/kotlin/space/mori/chzzk_bot/Main.kt +++ b/src/main/kotlin/space/mori/chzzk_bot/Main.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.runBlocking import org.slf4j.Logger import org.slf4j.LoggerFactory import space.mori.chzzk_bot.discord.Discord +import space.mori.chzzk_bot.chzzk.Connector as ChzzkConnector import java.util.concurrent.TimeUnit val dotenv = dotenv() @@ -15,6 +16,8 @@ fun main(args: Array) { val discord = Discord() Connector + ChzzkConnector + discord.enable() if(dotenv.get("RUN_AGENT", "false").toBoolean()) { diff --git a/src/main/kotlin/space/mori/chzzk_bot/chzzk/Connector.kt b/src/main/kotlin/space/mori/chzzk_bot/chzzk/Connector.kt new file mode 100644 index 0000000..84b54a2 --- /dev/null +++ b/src/main/kotlin/space/mori/chzzk_bot/chzzk/Connector.kt @@ -0,0 +1,14 @@ +package space.mori.chzzk_bot.chzzk + +import io.github.cdimascio.dotenv.dotenv +import xyz.r2turntrue.chzzk4j.Chzzk +import xyz.r2turntrue.chzzk4j.ChzzkBuilder + +object Connector { + private val dotenv = dotenv() + val chzzk: Chzzk = ChzzkBuilder() + .withAuthorization(dotenv["NID_AUT"], dotenv["NID_SES"]) + .build() + + fun getChannel(channelId: String) = chzzk.getChannel(channelId) +} \ No newline at end of file diff --git a/src/main/kotlin/space/mori/chzzk_bot/discord/Commands.kt b/src/main/kotlin/space/mori/chzzk_bot/discord/Commands.kt new file mode 100644 index 0000000..59a28c0 --- /dev/null +++ b/src/main/kotlin/space/mori/chzzk_bot/discord/Commands.kt @@ -0,0 +1,35 @@ +package space.mori.chzzk_bot.discord + +import net.dv8tion.jda.api.JDA +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.build.CommandData +import org.reflections.Reflections + +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class Command + +interface CommandInterface { + val name: String + fun run(event: SlashCommandInteractionEvent, bot: JDA): Unit + val command: CommandData +} + +fun getCommands(): List { + val commandList = mutableListOf() + + val packageName = "space.mori.chzzk_bot.discord.commands" + val reflections = Reflections(packageName) + val annotatedClasses = reflections.getTypesAnnotatedWith(Command::class.java) + + for(clazz in annotatedClasses) { + val obj = clazz.kotlin.objectInstance + if(obj is CommandInterface) { + commandList.add(obj) + } else { + throw IllegalStateException("${clazz.name} is not a CommandInterface") + } + } + + return commandList.toList() +} \ No newline at end of file diff --git a/src/main/kotlin/space/mori/chzzk_bot/discord/Discord.kt b/src/main/kotlin/space/mori/chzzk_bot/discord/Discord.kt index 1e6776a..5780f59 100644 --- a/src/main/kotlin/space/mori/chzzk_bot/discord/Discord.kt +++ b/src/main/kotlin/space/mori/chzzk_bot/discord/Discord.kt @@ -4,37 +4,49 @@ import net.dv8tion.jda.api.JDA import net.dv8tion.jda.api.JDABuilder import net.dv8tion.jda.api.entities.Activity import net.dv8tion.jda.api.entities.Guild -import net.dv8tion.jda.api.interactions.commands.build.Commands +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.hooks.ListenerAdapter import space.mori.chzzk_bot.dotenv import space.mori.chzzk_bot.logger import kotlin.concurrent.thread -class Discord { - lateinit var bot: JDA - var guild: Guild? = null +class Discord: ListenerAdapter() { + private lateinit var bot: JDA + private var guild: Guild? = null + + private val commands = getCommands() + + override fun onSlashCommandInteraction(event: SlashCommandInteractionEvent) { + event.deferReply().queue() + commands.find { it.name == event.name }?.run(event, bot) + } internal fun enable() { - try { - val thread = thread { + val thread = Thread { + try { bot = JDABuilder.createDefault(dotenv["DISCORD_TOKEN"]) .setActivity(Activity.playing("치지직 보는중")) + .addEventListeners(this) .build().awaitReady() guild = bot.getGuildById(dotenv["GUILD_ID"]) - bot.updateCommands().addCommands( - Commands.slash("ping", "Pong!") - ).queue() + bot.updateCommands() + .addCommands(* commands.map { it.command }.toTypedArray()) + .onSuccess { logger.info("Command update success!") } + .queue() + if (guild == null) { logger.info("No guild found!") this.disable() } + } catch (e: Exception) { + logger.info("Could not enable Discord!") + logger.debug(e.stackTraceToString()) } - } catch(e: Exception) { - logger.info("Could not enable Discord!") - logger.debug(e.stackTraceToString()) } + thread.start() } internal fun disable() { diff --git a/src/main/kotlin/space/mori/chzzk_bot/discord/commands/Ping.kt b/src/main/kotlin/space/mori/chzzk_bot/discord/commands/Ping.kt new file mode 100644 index 0000000..81b7c43 --- /dev/null +++ b/src/main/kotlin/space/mori/chzzk_bot/discord/commands/Ping.kt @@ -0,0 +1,17 @@ +package space.mori.chzzk_bot.discord.commands + +import net.dv8tion.jda.api.JDA +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.build.Commands +import space.mori.chzzk_bot.discord.Command +import space.mori.chzzk_bot.discord.CommandInterface + +@Command() +object Ping: CommandInterface { + override val command = Commands.slash("ping", "봇이 살아있을까요?") + override val name = "ping" + + override fun run(event: SlashCommandInteractionEvent, bot: JDA) { + event.hook.sendMessage("${event.user.asMention} Pong!").queue() + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/native-image/reflect-config.json b/src/main/resources/META-INF/native-image/reflect-config.json index c37d028..bf310b1 100644 --- a/src/main/resources/META-INF/native-image/reflect-config.json +++ b/src/main/resources/META-INF/native-image/reflect-config.json @@ -120,16 +120,25 @@ { "name":"java.lang.ClassValue" }, +{ + "name":"java.lang.Module" +}, { "name":"java.lang.RuntimePermission" }, { "name":"java.lang.String" }, +{ + "name":"java.lang.StringBuilder" +}, { "name":"java.lang.Thread", "fields":[{"name":"threadLocalRandomProbe"}] }, +{ + "name":"java.lang.invoke.CallSite" +}, { "name":"java.net.NetPermission" }, @@ -170,9 +179,20 @@ { "name":"java.security.interfaces.RSAPublicKey" }, +{ + "name":"java.sql.Date" +}, { "name":"java.util.Date" }, +{ + "name":"java.util.List", + "methods":[{"name":"copyOf","parameterTypes":["java.util.Collection"] }] +}, +{ + "name":"java.util.Optional", + "methods":[{"name":"isEmpty","parameterTypes":[] }] +}, { "name":"java.util.PropertyPermission" }, @@ -192,6 +212,12 @@ "name":"java.util.concurrent.atomic.Striped64", "fields":[{"name":"base"}, {"name":"cellsBusy"}] }, +{ + "name":"java.util.function.Function" +}, +{ + "name":"java.util.zip.DeflaterInputStream" +}, { "name":"javax.net.ssl.SNIHostName", "methods":[{"name":"","parameterTypes":["java.lang.String"] }] @@ -211,6 +237,11 @@ { "name":"jdk.internal.misc.Unsafe" }, +{ + "name":"kotlin.Metadata", + "queryAllDeclaredMethods":true, + "methods":[{"name":"bv","parameterTypes":[] }, {"name":"d1","parameterTypes":[] }, {"name":"d2","parameterTypes":[] }, {"name":"k","parameterTypes":[] }, {"name":"mv","parameterTypes":[] }, {"name":"pn","parameterTypes":[] }, {"name":"xi","parameterTypes":[] }, {"name":"xs","parameterTypes":[] }] +}, { "name":"kotlin.SafePublicationLazyImpl", "fields":[{"name":"_value"}] @@ -262,6 +293,10 @@ "name":"kotlinx.coroutines.scheduling.CoroutineScheduler", "fields":[{"name":"_isTerminated$volatile"}, {"name":"controlState$volatile"}, {"name":"parkedWorkersStack$volatile"}] }, +{ + "name":"net.dv8tion.jda.api.hooks.ListenerAdapter", + "methods":[{"name":"onGatewayPing","parameterTypes":["net.dv8tion.jda.api.events.GatewayPingEvent"] }, {"name":"onGenericGuild","parameterTypes":["net.dv8tion.jda.api.events.guild.GenericGuildEvent"] }, {"name":"onGenericSession","parameterTypes":["net.dv8tion.jda.api.events.session.GenericSessionEvent"] }, {"name":"onGuildReady","parameterTypes":["net.dv8tion.jda.api.events.guild.GuildReadyEvent"] }, {"name":"onHttpRequest","parameterTypes":["net.dv8tion.jda.api.events.http.HttpRequestEvent"] }, {"name":"onReady","parameterTypes":["net.dv8tion.jda.api.events.session.ReadyEvent"] }, {"name":"onShutdown","parameterTypes":["net.dv8tion.jda.api.events.session.ShutdownEvent"] }, {"name":"onStatusChange","parameterTypes":["net.dv8tion.jda.api.events.StatusChangeEvent"] }] +}, { "name":"net.dv8tion.jda.internal.utils.FallbackLogger", "methods":[{"name":"","parameterTypes":["java.lang.String"] }] @@ -284,6 +319,13 @@ { "name":"org.slf4j.spi.SLF4JServiceProvider" }, +{ + "name":"space.mori.chzzk_bot.discord.CommandInterface" +}, +{ + "name":"space.mori.chzzk_bot.discord.commands.Ping", + "fields":[{"name":"INSTANCE"}] +}, { "name":"sun.security.pkcs12.PKCS12KeyStore", "methods":[{"name":"","parameterTypes":[] }] diff --git a/src/main/resources/META-INF/native-image/resource-config.json b/src/main/resources/META-INF/native-image/resource-config.json index 910aed8..7d430cd 100644 --- a/src/main/resources/META-INF/native-image/resource-config.json +++ b/src/main/resources/META-INF/native-image/resource-config.json @@ -12,6 +12,10 @@ "pattern":"\\QMETA-INF/services/java.sql.Driver\\E" }, { "pattern":"\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E" + }, { + "pattern":"\\QMETA-INF/services/kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition\\E" + }, { + "pattern":"\\QMETA-INF/services/kotlin.reflect.jvm.internal.impl.util.ModuleVisibilityHelper\\E" }, { "pattern":"\\QMETA-INF/services/org.jetbrains.exposed.sql.DatabaseConnectionAutoRegistration\\E" }, { @@ -30,6 +34,8 @@ "pattern":"\\Qlogback.xml\\E" }, { "pattern":"\\Qmariadb.properties\\E" + }, { + "pattern":"\\Qspace/mori/chzzk_bot/discord/commands\\E" }, { "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt72b/nfc.nrm\\E" }, {