From 411e183e04c6b7a5436ad3067a77367301c20e07 Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Thu, 22 May 2025 16:13:06 +0700 Subject: [PATCH] refactor: Completely changed the API and a working argument --- .../github/null2264/tsukumogami/bot/Main.kt | 9 ++- .../null2264/tsukumogami/bot/core/Bot.kt | 6 -- .../bot/core/module/DeveloperModule.kt | 26 ++++---- .../bot/core/module/GeneralModule.kt | 19 +++--- .../core/{AbstractBot.kt => Bot.kt} | 65 ++++++++++--------- .../tsukumogami/core/BotConfigurator.kt | 32 --------- .../null2264/tsukumogami/core/BotHolder.kt | 32 +++++++++ .../null2264/tsukumogami/core/Context.kt | 20 ++++-- .../core/annotation/TsukumogamiAnnotations.kt | 13 ++++ .../tsukumogami/core/commands/Arguments.kt | 8 ++- .../tsukumogami/core/commands/Command.kt | 20 ++++++ .../core/commands/CommandHolder.kt | 13 ---- .../core/commands/EmptyArguments.kt | 4 ++ .../tsukumogami/core/commands/Group.kt | 26 ++++++++ .../tsukumogami/core/commands/IGroup.kt | 45 +++++++++++++ .../core/{utils => ext}/StringExtensions.kt | 2 +- .../tsukumogami/core/module/BotModule.kt | 52 ++++----------- .../core/module/api/BotModuleApi.kt | 11 ++++ .../core/module/internal/Modules.kt | 40 ------------ 19 files changed, 244 insertions(+), 199 deletions(-) delete mode 100644 bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/Bot.kt rename core/src/main/kotlin/io/github/null2264/tsukumogami/core/{AbstractBot.kt => Bot.kt} (58%) delete mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotConfigurator.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotHolder.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/annotation/TsukumogamiAnnotations.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Command.kt delete mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/CommandHolder.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/EmptyArguments.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Group.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/IGroup.kt rename core/src/main/kotlin/io/github/null2264/tsukumogami/core/{utils => ext}/StringExtensions.kt (97%) create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/api/BotModuleApi.kt delete mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/internal/Modules.kt diff --git a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/Main.kt b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/Main.kt index d0518a5..1b52e0b 100644 --- a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/Main.kt +++ b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/Main.kt @@ -2,9 +2,8 @@ package io.github.null2264.tsukumogami.bot import co.touchlab.kermit.Logger import io.github.null2264.tsukumogami.bot.core.di.appModule -import io.github.null2264.tsukumogami.bot.core.module.DeveloperModule -import io.github.null2264.tsukumogami.bot.core.module.GeneralModule -import io.github.null2264.tsukumogami.bot.core.Bot +import io.github.null2264.tsukumogami.bot.core.module.generalModule +import io.github.null2264.tsukumogami.core.bot import org.koin.core.context.GlobalContext.startKoin suspend fun main() { @@ -13,13 +12,13 @@ suspend fun main() { modules(appModule) } - Bot { + bot { Logger.setTag("Tsukumogami") token = System.getenv("DISCORD_TOKEN") prefixes("src!", "mm!") // mm! for backwards compatibility - extensions(::DeveloperModule, ::GeneralModule) + modules(generalModule) }.start() } diff --git a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/Bot.kt b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/Bot.kt deleted file mode 100644 index 0645b7a..0000000 --- a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/Bot.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.null2264.tsukumogami.bot.core - -import io.github.null2264.tsukumogami.core.AbstractBot -import io.github.null2264.tsukumogami.core.BotConfigurator - -class Bot(block: BotConfigurator.() -> Unit = {}) : AbstractBot(block) diff --git a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/DeveloperModule.kt b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/DeveloperModule.kt index 17a07d9..b8952fd 100644 --- a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/DeveloperModule.kt +++ b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/DeveloperModule.kt @@ -1,17 +1,13 @@ package io.github.null2264.tsukumogami.bot.core.module -import io.github.null2264.tsukumogami.core.commands.annotation.Command -import io.github.null2264.tsukumogami.core.Context -import io.github.null2264.tsukumogami.core.module.BotModule - -class DeveloperModule : BotModule("Developer", "Only for developers") { - - @Command( - name="poweroff", - description="Turn the bot off", - ) - private suspend fun shutdown(ctx: Context) { - ctx.reply("Shutting Down...", mentionsAuthor = true) - bot?.stop() - } -} +//class DeveloperModule : BotModule("Developer", "Only for developers") { +// +// @Command( +// name="poweroff", +// description="Turn the bot off", +// ) +// private suspend fun shutdown(ctx: Context) { +// ctx.reply("Shutting Down...", mentionsAuthor = true) +// bot?.stop() +// } +//} diff --git a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/GeneralModule.kt b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/GeneralModule.kt index b3adb11..f96494d 100644 --- a/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/GeneralModule.kt +++ b/bot/src/main/kotlin/io/github/null2264/tsukumogami/bot/core/module/GeneralModule.kt @@ -1,23 +1,20 @@ package io.github.null2264.tsukumogami.bot.core.module -import dev.kord.core.entity.effectiveName -import io.github.null2264.tsukumogami.core.commands.annotation.Command -import io.github.null2264.tsukumogami.core.Context -import io.github.null2264.tsukumogami.core.module.BotModule +import io.github.null2264.tsukumogami.bot.core.module.arguments.TestArguments +import io.github.null2264.tsukumogami.core.module.api.botModules import kotlinx.datetime.Clock -class GeneralModule : BotModule("General", "idk") { - - @Command(description = "Ping the bot!") - private suspend fun ping(ctx: Context) { +val generalModule = botModules("General") { + commands("ping", description = "Ping the bot!") { ctx -> val startTime = Clock.System.now() ctx.typing() val endTime = Clock.System.now() ctx.send("Pong! ${endTime.toEpochMilliseconds() - startTime.toEpochMilliseconds()}ms") } - @Command("test") - private suspend fun differentName(ctx: Context) { - ctx.send("Hello World! ${ctx.author?.effectiveName}") + groups("group") { + commands("test", arguments = ::TestArguments) { ctx, args -> ctx.send("Hello world ${args.test}") } } + + commands("test", arguments = ::TestArguments) { ctx, args -> ctx.send("Hello world ${args.test}") } } diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/AbstractBot.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt similarity index 58% rename from core/src/main/kotlin/io/github/null2264/tsukumogami/core/AbstractBot.kt rename to core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt index e04126f..86c7832 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/AbstractBot.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt @@ -8,45 +8,52 @@ import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.on import dev.kord.gateway.Intent import dev.kord.gateway.PrivilegedIntent +import io.github.null2264.tsukumogami.core.commands.Command import io.github.null2264.tsukumogami.core.exceptions.CommandException import io.github.null2264.tsukumogami.core.exceptions.CommandNotFound import io.github.null2264.tsukumogami.core.module.BotModule -import io.github.null2264.tsukumogami.core.commands.CommandHolder -import io.github.null2264.tsukumogami.core.utils.parseCommandAndArguments +import io.github.null2264.tsukumogami.core.commands.IGroup +import io.github.null2264.tsukumogami.core.ext.parseCommandAndArguments import kotlin.reflect.full.callSuspend import kotlinx.coroutines.runBlocking -abstract class AbstractBot(configurator: BotConfigurator.() -> Unit) { +open class Bot internal constructor(): IGroup { - private val commands: Map - private val extensions: Map - private val prefixes: List - private val client: Kord + lateinit var client: Kord + private val modules = mutableMapOf() + private val _prefixes = mutableListOf() + val prefixes: List get() = _prefixes.toList() + internal lateinit var token: String + override val allCommands: MutableMap = mutableMapOf() - // TODO: Bind Bot and Kord to Koin - init { - val currentConfig = BotConfigurator() - currentConfig.apply(configurator) + fun addModule(module: BotModule) { + modules[module.name] = module.install(this) + } - extensions = mutableMapOf() - currentConfig.extensions.forEach { module -> - module.setup() - module.install(this, currentConfig) - extensions[module.name] = module + fun addPrefix(prefix: String) { + _prefixes.add(prefix) + } + + fun addCommand(command: Command) { + if (allCommands.containsKey(command.name)) { + throw IllegalStateException("Duplicate command: '${command.name}'") } - commands = currentConfig.commands - prefixes = currentConfig.prefixes + allCommands[command.name] = command + } - client = runBlocking { - Kord(currentConfig.token).apply { - on { onReady() } - - on { onMessage(this.message, this) } - } + fun removeCommand(command: Command) { + if (!allCommands.containsKey(command.name)) { + throw IllegalStateException("Command not found: '${command.name}'") } + allCommands.remove(command.name) } open suspend fun start() { + client = Kord(token).apply { + on { onReady() } + on { onMessage(this.message, this) } + } + client.login { @OptIn(PrivilegedIntent::class) intents += Intent.MessageContent @@ -57,11 +64,13 @@ abstract class AbstractBot(configurator: BotConfigurator.() -> Unit) { client.shutdown() } - fun getCommand(name: String) = commands[name] + fun getCommand(name: String?) = allCommands[name] private fun getContext(message: Message): Context { val candidate = message.content.parsePrefixCommandAndArguments() - return Context(this, message, candidate?.first, candidate?.second) + val context = Context(this, message, candidate?.first, candidate?.second) + context.command = getCommand(candidate?.second?.get(0)) + return context } open suspend fun onCommandError(context: Context, error: CommandException) { @@ -72,9 +81,7 @@ abstract class AbstractBot(configurator: BotConfigurator.() -> Unit) { val ctx = getContext(message) try { - ctx.command?.let { - it.callback.callSuspend(extensions[it.extension], ctx) - } ?: throw CommandNotFound() + ctx.command?.invoke(ctx) ?: throw CommandNotFound() } catch (e: CommandException) { onCommandError(ctx, e) } catch (e: Exception) { diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotConfigurator.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotConfigurator.kt deleted file mode 100644 index ce46057..0000000 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotConfigurator.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.null2264.tsukumogami.core - -import io.github.null2264.tsukumogami.core.module.internal.Modules -import io.github.null2264.tsukumogami.core.module.BotModule -import io.github.null2264.tsukumogami.core.commands.CommandHolder -import kotlin.reflect.KFunction - -class BotConfigurator internal constructor() { - - internal val commands = mutableMapOf() - internal val extensions = Modules() - internal val prefixes = mutableListOf() - var token: String = "" - - internal fun isExists(name: String?) = this.commands.containsKey(name) - - internal fun commands(command: CommandHolder, name: String? = null) { - this.commands[if (name.isNullOrEmpty()) command.name else name] = command - } - - fun extensions(vararg extensions: KFunction) { - this.extensions.initializeAndAddAll(extensions.toList()) - } - - fun prefixes(vararg prefixes: String) { - prefixes(prefixes.toList()) - } - - fun prefixes(prefixes: List) { - this.prefixes.addAll(prefixes) - } -} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotHolder.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotHolder.kt new file mode 100644 index 0000000..33c755c --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotHolder.kt @@ -0,0 +1,32 @@ +package io.github.null2264.tsukumogami.core + +import dev.kord.core.Kord +import io.github.null2264.tsukumogami.core.module.BotModule +import kotlin.reflect.KFunction + +class BotHolder internal constructor( + val bot: Bot +) { + + internal val prefixes = mutableListOf() + var token: String + get() = bot.token + set(value) { + bot.token = value + } + + fun modules(vararg modules: BotModule) { + modules.forEach(bot::addModule) + } + + fun prefixes(vararg prefixes: String) { + prefixes.forEach(bot::addPrefix) + } +} + +fun bot(clazz: KFunction = ::Bot, declaration: BotHolder.() -> Unit): Bot { + val bot = clazz.call() + val holder = BotHolder(bot) + declaration(holder) + return holder.bot +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Context.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Context.kt index 2c878e6..9dfe7ed 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Context.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Context.kt @@ -4,18 +4,26 @@ import dev.kord.core.behavior.channel.createMessage import dev.kord.core.entity.Message import dev.kord.rest.builder.message.AllowedMentionsBuilder import dev.kord.rest.builder.message.allowedMentions -import io.github.null2264.tsukumogami.core.commands.CommandHolder +import io.github.null2264.tsukumogami.core.commands.Command class Context( - private val bot: AbstractBot, + private val bot: Bot, private val message: Message, + /** + * The prefix that used to invoke the command + */ val prefix: String?, - commandAndArguments: List?, + /** + * Potential command name and/or arguments + */ + val candidate: List?, ) { - val author get() = message.author - val commandAndArguments: MutableList? = commandAndArguments?.toMutableList() - val command: CommandHolder? = this.commandAndArguments?.removeAt(0)?.let { bot.getCommand(it) } + + /** + * The command that currently being invoked + */ + var command: Command? = null suspend fun send(content: String) = message.channel.createMessage(content) diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/annotation/TsukumogamiAnnotations.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/annotation/TsukumogamiAnnotations.kt new file mode 100644 index 0000000..c0b0b38 --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/annotation/TsukumogamiAnnotations.kt @@ -0,0 +1,13 @@ +package io.github.null2264.tsukumogami.core.annotation + +@RequiresOptIn(message = "Intended for internal usage. External usage is strongly discouraged.", level = RequiresOptIn.Level.ERROR) +@Retention(AnnotationRetention.BINARY) +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.TYPEALIAS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.FIELD, + AnnotationTarget.CONSTRUCTOR, +) +annotation class TsukumogamiInternalApi diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Arguments.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Arguments.kt index 686be91..40984d3 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Arguments.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Arguments.kt @@ -2,7 +2,7 @@ package io.github.null2264.tsukumogami.core.commands import io.github.null2264.tsukumogami.core.commands.converters.Converter -open class Arguments { +abstract class Arguments { val args = mutableListOf>() fun args( @@ -13,4 +13,10 @@ open class Arguments { return converter } + + suspend fun parse(value: String) { + args.forEach { arg -> + arg.converter.parse(value) + } + } } diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Command.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Command.kt new file mode 100644 index 0000000..c770818 --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Command.kt @@ -0,0 +1,20 @@ +package io.github.null2264.tsukumogami.core.commands + +import io.github.null2264.tsukumogami.core.Context +import kotlin.reflect.KFunction + +open class Command( + val name: String, + val alias: Set, + val description: String, + private val arguments: KFunction, + private val handler: suspend (Context, Arguments) -> Unit, +) { + + open suspend fun invoke(context: Context) { + val parsedArguments = arguments.call() + // TODO: Don't hardcode this + parsedArguments.parse(context.candidate?.get(1) ?: "test") + handler.invoke(context, parsedArguments) + } +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/CommandHolder.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/CommandHolder.kt deleted file mode 100644 index 25c9a41..0000000 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/CommandHolder.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.null2264.tsukumogami.core.commands - -import kotlin.reflect.KFunction - -/** - * Class holding information about a command - */ -data class CommandHolder internal constructor( - val name: String, - val extension: String, - val description: String? = null, - val callback: KFunction<*>, -) diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/EmptyArguments.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/EmptyArguments.kt new file mode 100644 index 0000000..7c0d70c --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/EmptyArguments.kt @@ -0,0 +1,4 @@ +package io.github.null2264.tsukumogami.core.commands + +class EmptyArguments : Arguments() { +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Group.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Group.kt new file mode 100644 index 0000000..59bdc28 --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/Group.kt @@ -0,0 +1,26 @@ +package io.github.null2264.tsukumogami.core.commands + +import io.github.null2264.tsukumogami.core.Context + +class Group( + name: String, + alias: Set, + description: String, +) : + IGroup, + Command( + name, + alias, + description, + ::EmptyArguments, + { _, _ -> /* No handler for group to match the behaviour of Discord's slash command */ }, + ) { + + override val allCommands: MutableMap = mutableMapOf() + + override suspend fun invoke(context: Context) { + val command = allCommands["TODO"] ?: return + context.command = command + command.invoke(context) + } +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/IGroup.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/IGroup.kt new file mode 100644 index 0000000..42d8f5a --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/commands/IGroup.kt @@ -0,0 +1,45 @@ +package io.github.null2264.tsukumogami.core.commands + +import io.github.null2264.tsukumogami.core.Context +import kotlin.reflect.KFunction + +interface IGroup { + + val allCommands: MutableMap + + private fun addCommand(command: Command) { + allCommands[command.name] = command + command.alias.forEach { allCommands[it] = command } + } + + fun commands( + name: String, + alias: Set = setOf(), + description: String = "", + handler: suspend (Context) -> Unit, + ) { + val command = Command(name, alias, description, ::EmptyArguments) { ctx, _ -> handler(ctx) } + addCommand(command) + } + + fun commands( + name: String, + alias: Set = setOf(), + description: String = "", + arguments: KFunction, + handler: suspend (Context, Args) -> Unit, + ) { + val command = Command(name, alias, description, arguments) { ctx, args -> handler(ctx, args as Args) } + addCommand(command) + } + + fun groups( + name: String, + alias: Set = setOf(), + description: String = "", + declaration: IGroup.() -> Unit, + ) { + val group = Group(name, alias, description) + addCommand(group) + } +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/utils/StringExtensions.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/StringExtensions.kt similarity index 97% rename from core/src/main/kotlin/io/github/null2264/tsukumogami/core/utils/StringExtensions.kt rename to core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/StringExtensions.kt index 0ed11fe..2bc9b79 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/utils/StringExtensions.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/StringExtensions.kt @@ -1,4 +1,4 @@ -package io.github.null2264.tsukumogami.core.utils +package io.github.null2264.tsukumogami.core.ext fun String.parseCommandAndArguments(): List { if (isBlank()) { diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/BotModule.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/BotModule.kt index ef96d0e..2605e3a 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/BotModule.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/BotModule.kt @@ -1,48 +1,20 @@ package io.github.null2264.tsukumogami.core.module -import co.touchlab.kermit.Logger -import io.github.null2264.tsukumogami.core.AbstractBot -import io.github.null2264.tsukumogami.core.commands.annotation.Command -import io.github.null2264.tsukumogami.core.BotConfigurator -import io.github.null2264.tsukumogami.core.commands.CommandHolder -import kotlin.reflect.jvm.isAccessible -import kotlin.reflect.jvm.kotlinFunction +import io.github.null2264.tsukumogami.core.Bot +import io.github.null2264.tsukumogami.core.commands.Command +import io.github.null2264.tsukumogami.core.commands.IGroup -abstract class BotModule(val name: String, val description: String? = null) { +class BotModule internal constructor(val name: String) : IGroup { - var bot: AbstractBot? = null - internal set + override val allCommands: MutableMap = mutableMapOf() - open fun setup() {} + internal fun install(bot: Bot): BotModule { + allCommands.values.forEach(bot::addCommand) + return this + } - internal fun install(bot: AbstractBot, configurator: BotConfigurator) { - this.bot = bot - - val methods = this::class.java.declaredMethods - for (method in methods) { - for (annotation in method.annotations) { - if (annotation !is Command) - continue - - configurator.apply { - val kMethod = method.kotlinFunction - if (isExists(kMethod?.name)) { - Logger.e { "Command already exists" } - return - } - kMethod?.let { - it.isAccessible = true - commands( - CommandHolder( - annotation.name.ifEmpty { it.name }, - name, - annotation.description.ifEmpty { description }, - it, - ) - ) - } - } - } - } + internal fun uninstall(bot: Bot): BotModule { + allCommands.values.forEach(bot::removeCommand) + return this } } diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/api/BotModuleApi.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/api/BotModuleApi.kt new file mode 100644 index 0000000..20f5f4e --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/api/BotModuleApi.kt @@ -0,0 +1,11 @@ +package io.github.null2264.tsukumogami.core.module.api + +import io.github.null2264.tsukumogami.core.module.BotModule + +typealias BotModuleDeclaration = BotModule.() -> Unit + +fun botModules(name: String, declaration: BotModuleDeclaration): BotModule { + val module = BotModule(name) + declaration(module) + return module +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/internal/Modules.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/internal/Modules.kt deleted file mode 100644 index 01ae3e2..0000000 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/module/internal/Modules.kt +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.null2264.tsukumogami.core.module.internal - -import io.github.null2264.tsukumogami.core.module.BotModule -import java.util.function.Consumer -import kotlin.reflect.KClass -import kotlin.reflect.KFunction -import kotlin.reflect.full.isSubclassOf - -class Modules { - - private val list = mutableListOf() - - fun get(index: Int) = list[index] - - private fun KFunction.tryInitialize(): BotModule? { - val kClass = this.returnType.classifier as KClass<*> - if (!kClass.isSubclassOf(BotModule::class)) - return null - - return this.call() - } - - fun initializeAndAddAll(modules: List>) { - addAll(modules.mapNotNull { it.tryInitialize() }) - } - - fun addAll(modules: List) { - list.addAll(modules) - } - - fun add(module: KFunction) { - module.tryInitialize()?.let { add(it) } - } - - fun add(module: BotModule) { - list.add(module) - } - - fun forEach(consumer: Consumer) = list.forEach(consumer) -}