diff --git a/px32-bot-api/src/main/kotlin/net/projecttl/p/x32/api/Plugin.kt b/px32-bot-api/src/main/kotlin/net/projecttl/p/x32/api/Plugin.kt index 3d3ecad..9c6929c 100644 --- a/px32-bot-api/src/main/kotlin/net/projecttl/p/x32/api/Plugin.kt +++ b/px32-bot-api/src/main/kotlin/net/projecttl/p/x32/api/Plugin.kt @@ -9,27 +9,24 @@ import org.slf4j.LoggerFactory abstract class Plugin { private val handlerContainer = mutableListOf() - private val config = this.javaClass.getResourceAsStream("/plugin.json")?.let { + val config = this.javaClass.getResourceAsStream("/plugin.json")!!.let { val raw = it.bufferedReader().readText() val obj = Json.decodeFromString(raw) return@let obj } - fun getLogger(): Logger { - return LoggerFactory.getLogger(config?.name) - } + var logger: Logger = LoggerFactory.getLogger(this::class.java) - fun getHandlers(): List { - return handlerContainer - } + val handlers: List + get() = handlerContainer fun addHandler(listener: ListenerAdapter) { - handlerContainer.add(listener) + handlerContainer += listener } fun delHandler(listener: ListenerAdapter) { - handlerContainer.remove(listener) + handlerContainer -= listener } abstract fun onLoad() diff --git a/px32-bot-core/build.gradle.kts b/px32-bot-core/build.gradle.kts index ac23c47..5478c3a 100644 --- a/px32-bot-core/build.gradle.kts +++ b/px32-bot-core/build.gradle.kts @@ -14,7 +14,7 @@ repositories { dependencies { implementation(project(":${rootProject.name}-api")) - implementation(project(":${rootProject.name}-func")) + implementation(project(":px32-bot-module")) testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") } diff --git a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/Px32.kt b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/Px32.kt index 58d506b..23921f1 100644 --- a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/Px32.kt +++ b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/Px32.kt @@ -5,8 +5,6 @@ import net.projecttl.p.x32.command.PluginCommand import net.projecttl.p.x32.command.Reload import net.projecttl.p.x32.config.Config import net.projecttl.p.x32.config.DefaultConfig -import net.projecttl.p.x32.func.loadDefault -import net.projecttl.p.x32.func.handler.Ready import net.projecttl.p.x32.kernel.CoreKernel import org.jetbrains.exposed.sql.Database import org.slf4j.Logger @@ -26,11 +24,9 @@ fun main() { kernel = CoreKernel(Config.token) val handler = kernel.getCommandContainer() - kernel.addHandler(Ready) handler.addCommand(Reload) handler.addCommand(PluginCommand) - loadDefault(handler) jda = kernel.build() } diff --git a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/config/Config.kt b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/config/Config.kt index e9a913e..5cacf94 100644 --- a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/config/Config.kt +++ b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/config/Config.kt @@ -15,6 +15,9 @@ object Config { val token: String by useConfig() val owner: String by useConfig() + private val bundle_func: String by useConfig() + val bundle = if (bundle_func == "1") true else if (bundle_func == "0") false else throw IllegalArgumentException("bundle_func option must be 0 or 1") + val db_driver: String by useConfig() val db_url: String by useConfig() val db_username: String by useConfig() diff --git a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt index 80fbbcf..8fe33b4 100644 --- a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt +++ b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt @@ -1,18 +1,28 @@ package net.projecttl.p.x32.kernel +import kotlinx.serialization.json.Json import net.dv8tion.jda.api.JDA import net.dv8tion.jda.api.JDABuilder import net.dv8tion.jda.api.hooks.ListenerAdapter import net.projecttl.p.x32.api.Plugin import net.projecttl.p.x32.api.command.CommandHandler +import net.projecttl.p.x32.api.model.PluginConfig +import net.projecttl.p.x32.config.Config +import net.projecttl.p.x32.func.General import net.projecttl.p.x32.jda -import net.projecttl.p.x32.logger class CoreKernel(token: String) { private val builder = JDABuilder.createDefault(token) private val handlers = mutableListOf() private val commandContainer = CommandHandler() + private fun include() { + if (Config.bundle) { + val b = General() + PluginLoader.putModule(b.config, b) + } + } + fun getCommandContainer(): CommandHandler { return commandContainer } @@ -30,10 +40,11 @@ class CoreKernel(token: String) { } fun build(): JDA { - PluginLoader.load() + include() + PluginLoader.load() plugins().forEach { plugin -> - plugin.getHandlers().forEach { handler -> + plugin.handlers.forEach { handler -> handlers.add(handler) } } @@ -62,7 +73,7 @@ class CoreKernel(token: String) { val newHandlers = mutableListOf() PluginLoader.destroy() plugins().forEach { plugin -> - plugin.getHandlers().forEach { handler -> + plugin.handlers.forEach { handler -> if (handlers.contains(handler)) { jda.removeEventListener(handler) handlers.remove(handler) @@ -70,10 +81,11 @@ class CoreKernel(token: String) { } } + include() PluginLoader.load() plugins().forEach { plugin -> - plugin.getHandlers().forEach { handler -> + plugin.handlers.forEach { handler -> if (!handlers.contains(handler)) { handlers.add(handler) newHandlers.add(handler) diff --git a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/PluginLoader.kt b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/PluginLoader.kt index 8153f6f..4427b13 100644 --- a/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/PluginLoader.kt +++ b/px32-bot-core/src/main/kotlin/net/projecttl/p/x32/kernel/PluginLoader.kt @@ -22,10 +22,25 @@ object PluginLoader { return plugins.toMap() } + fun putModule(config: PluginConfig, plugin: Plugin) { + try { + logger.info("Load module ${config.name} v${config.version}") + plugin.onLoad() + } catch (ex: Exception) { + ex.printStackTrace() + plugin.destroy() + return + } + + plugins[config] = plugin + } + fun load() { parentDir.listFiles()?.forEach { file -> loadPlugin(file) } + + logger.info("Loaded ${plugins.size} plugins") } fun destroy() { @@ -42,6 +57,10 @@ object PluginLoader { } private fun loadPlugin(file: File) { + if (file.name == "px32-bot-module") { + return + } + if (!file.name.endsWith(".jar")) { return } diff --git a/px32-bot-core/src/main/resources/config.sample.properties b/px32-bot-core/src/main/resources/config.sample.properties index 49eb5ff..a0b5be4 100644 --- a/px32-bot-core/src/main/resources/config.sample.properties +++ b/px32-bot-core/src/main/resources/config.sample.properties @@ -1,6 +1,8 @@ token= owner= +bundle_func=1 + db_driver=org.sqlite.JDBC db_url=jdbc:sqlite:data.db db_username= diff --git a/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/Loader.kt b/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/Loader.kt deleted file mode 100644 index fcce0bd..0000000 --- a/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/Loader.kt +++ /dev/null @@ -1,12 +0,0 @@ -package net.projecttl.p.x32.func - -import net.projecttl.p.x32.api.command.CommandHandler -import net.projecttl.p.x32.func.command.Avatar -import net.projecttl.p.x32.func.command.MsgLength -import net.projecttl.p.x32.func.command.Ping - -fun loadDefault(handler: CommandHandler) = with(handler) { - addCommand(Avatar) - addCommand(MsgLength) - addCommand(Ping) -} diff --git a/px32-bot-func/build.gradle.kts b/px32-bot-module/build.gradle.kts similarity index 63% rename from px32-bot-func/build.gradle.kts rename to px32-bot-module/build.gradle.kts index 6bdf016..8146809 100644 --- a/px32-bot-func/build.gradle.kts +++ b/px32-bot-module/build.gradle.kts @@ -15,6 +15,14 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter") } -tasks.test { - useJUnitPlatform() +tasks { + processResources { + filesMatching("plugin.json") { + expand(project.properties) + } + } + + test { + useJUnitPlatform() + } } \ No newline at end of file diff --git a/px32-bot-module/src/main/kotlin/Conf.kt b/px32-bot-module/src/main/kotlin/Conf.kt new file mode 100644 index 0000000..822657b --- /dev/null +++ b/px32-bot-module/src/main/kotlin/Conf.kt @@ -0,0 +1,25 @@ +import java.io.File +import java.io.FileInputStream +import java.util.* +import kotlin.reflect.KProperty + +object Conf { + private fun useConf(): ConfDel { + return ConfDel() + } + + val owner: String by useConf() +} + +private class ConfDel { + private val props = Properties() + + init { + val file = File("config.properties") + props.load(FileInputStream(file)) + } + + operator fun getValue(thisRef: Any?, property: KProperty<*>): String { + return props.getProperty(property.name).toString() + } +} diff --git a/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/General.kt b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/General.kt new file mode 100644 index 0000000..2575a50 --- /dev/null +++ b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/General.kt @@ -0,0 +1,34 @@ +package net.projecttl.p.x32.func + +import net.dv8tion.jda.api.JDABuilder +import net.projecttl.p.x32.api.Plugin +import net.projecttl.p.x32.api.command.CommandHandler +import net.projecttl.p.x32.func.command.Avatar +import net.projecttl.p.x32.func.command.MsgPurge +import net.projecttl.p.x32.func.command.MsgLength +import net.projecttl.p.x32.func.command.Ping +import net.projecttl.p.x32.func.handler.Ready + + +class General : Plugin() { + override fun onLoad() { + logger.info("Created by Project_IO") + logger.info("Hello! This is Px32's general module!") + + addHandler(Ready) + addHandler(with(CommandHandler()) { + addCommand(Avatar) + addCommand(MsgLength) + addCommand(Ping) + addCommand(MsgPurge) + + this + }) + } + + override fun destroy() { + logger.info("bye!") + } +} + + diff --git a/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/command/Avatar.kt b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/Avatar.kt similarity index 100% rename from px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/command/Avatar.kt rename to px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/Avatar.kt diff --git a/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/command/MsgLength.kt b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/MsgLength.kt similarity index 100% rename from px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/command/MsgLength.kt rename to px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/MsgLength.kt diff --git a/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/MsgPurge.kt b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/MsgPurge.kt new file mode 100644 index 0000000..7d0965e --- /dev/null +++ b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/MsgPurge.kt @@ -0,0 +1,36 @@ +package net.projecttl.p.x32.func.command + +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.CommandData +import net.dv8tion.jda.internal.interactions.CommandDataImpl +import net.projecttl.p.x32.api.command.GlobalCommand + +object MsgPurge : GlobalCommand { + override val data = CommandData.fromData( + CommandDataImpl("purge", "n개의 메시지를 채널에서 삭제해요").apply { + addOption(OptionType.INTEGER, "n", "n개만큼 메시지가 삭제 됩니다", true) + }.toData() + ) + + override suspend fun execute(ev: SlashCommandInteractionEvent) { + val n = ev.getOption("n")!!.asInt + if (n !in 1..100) { + return ev.reply(":warning: 1 부터 100까지 가능해요").setEphemeral(true).queue() + } + + if (ev.user.id != Conf.owner) { + ev.reply(":warning: 이 명령어는 봇 관리자만 사용 가능해요").setEphemeral(true).queue() + return + } + + try { + ev.channel.iterableHistory.takeAsync(n).thenAccept(ev.channel::purgeMessages) + } catch (ex: Exception) { + ex.printStackTrace() + return ev.reply(":warning: 메시지 삭제 도중에 문제가 발생 했어요").queue() + } + + ev.reply(":white_check_mark: `${n}`개의 메시지를 삭제 했어요").queue() + } +} \ No newline at end of file diff --git a/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/command/Ping.kt b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/Ping.kt similarity index 100% rename from px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/command/Ping.kt rename to px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/command/Ping.kt diff --git a/px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/handler/Ready.kt b/px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/handler/Ready.kt similarity index 100% rename from px32-bot-func/src/main/kotlin/net/projecttl/p/x32/func/handler/Ready.kt rename to px32-bot-module/src/main/kotlin/net/projecttl/p/x32/func/handler/Ready.kt diff --git a/px32-bot-module/src/main/resources/plugin.json b/px32-bot-module/src/main/resources/plugin.json new file mode 100644 index 0000000..b32e237 --- /dev/null +++ b/px32-bot-module/src/main/resources/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "${project.name}", + "version": "${project.version}", + "main": "net.projecttl.p.x32.func.General" +} + diff --git a/settings.gradle.kts b/settings.gradle.kts index f4c99ca..be4b761 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,5 @@ rootProject.name = "px32-bot" include("px32-bot-core") include("px32-bot-api") -include("px32-bot-func") +include("px32-bot-module") include("sample-plugin")