From 26e5ba9e85b840da02c68227ed6656d73fb7fb8f Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Sat, 24 May 2025 08:38:26 +0700 Subject: [PATCH] feat: Koin integration --- .../github/null2264/tsukumogami/bot/Main.kt | 4 - .../github/null2264/tsukumogami/core/Bot.kt | 11 +-- .../null2264/tsukumogami/core/BotBuilder.kt | 30 +++++++- .../core/commands/EmptyArguments.kt | 3 +- .../tsukumogami/core/ext/KoinExtensions.kt | 17 +++++ .../core/koin/TsukumogamiKoinComponent.kt | 8 ++ .../core/koin/TsukumogamiKoinContext.kt | 75 +++++++++++++++++++ 7 files changed, 131 insertions(+), 17 deletions(-) create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/KoinExtensions.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinComponent.kt create mode 100644 core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinContext.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 1b52e0b..0b1b878 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 @@ -8,10 +8,6 @@ import org.koin.core.context.GlobalContext.startKoin suspend fun main() { - startKoin { - modules(appModule) - } - bot { Logger.setTag("Tsukumogami") diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt index a68e8f0..82c03b8 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/Bot.kt @@ -14,12 +14,14 @@ import io.github.null2264.tsukumogami.core.exceptions.CommandNotFound import io.github.null2264.tsukumogami.core.module.BotModule import io.github.null2264.tsukumogami.core.commands.IGroup import io.github.null2264.tsukumogami.core.ext.parseCommandAndArguments +import io.github.null2264.tsukumogami.core.koin.TsukumogamiKoinComponent import kotlin.reflect.full.callSuspend import kotlinx.coroutines.runBlocking +import org.koin.core.component.inject -open class Bot internal constructor(): IGroup { +open class Bot internal constructor(): IGroup, TsukumogamiKoinComponent { - lateinit var client: Kord + val client: Kord by inject() private val modules = mutableMapOf() private val _prefixes = mutableListOf() val prefixes: List get() = _prefixes.toList() @@ -59,11 +61,6 @@ open class Bot internal constructor(): IGroup { } open suspend fun start() { - client = Kord(token).apply { - on { onReady() } - on { onMessage(this.message, this) } - } - client.login { @OptIn(PrivilegedIntent::class) intents += Intent.MessageContent diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotBuilder.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotBuilder.kt index be9cbb6..51fc4f7 100644 --- a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotBuilder.kt +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/BotBuilder.kt @@ -1,17 +1,28 @@ package io.github.null2264.tsukumogami.core +import dev.kord.core.Kord +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.on +import io.github.null2264.tsukumogami.core.ext.loadModule +import io.github.null2264.tsukumogami.core.koin.TsukumogamiKoinContext import io.github.null2264.tsukumogami.core.module.BotModule import kotlin.reflect.KFunction +import kotlinx.coroutines.runBlocking +import org.koin.dsl.bind class BotBuilder internal constructor( val bot: Bot ) { - var token: String - get() = bot.token - set(value) { - bot.token = value + var token: String = "" + + var kordBuilder: suspend (String) -> Kord = { token -> + Kord(token).apply { + on { bot.onReady() } + on { bot.onMessage(this.message, this) } } + } fun modules(vararg modules: BotModule) { modules.forEach(bot::addModule) @@ -23,8 +34,19 @@ class BotBuilder internal constructor( } fun bot(clazz: KFunction = ::Bot, declaration: BotBuilder.() -> Unit): Bot { + if (TsukumogamiKoinContext.getOrNull() == null) + TsukumogamiKoinContext.startKoin { + } + val bot = clazz.call() val holder = BotBuilder(bot) declaration(holder) + + val kord = runBlocking { + holder.kordBuilder(holder.token) + } + loadModule { single { kord } bind Kord::class } + loadModule { single { bot } bind Bot::class } + return holder.bot } 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 index 7c0d70c..92140a3 100644 --- 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 @@ -1,4 +1,3 @@ package io.github.null2264.tsukumogami.core.commands -class EmptyArguments : Arguments() { -} +class EmptyArguments : Arguments() diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/KoinExtensions.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/KoinExtensions.kt new file mode 100644 index 0000000..b509a2b --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/ext/KoinExtensions.kt @@ -0,0 +1,17 @@ +package io.github.null2264.tsukumogami.core.ext + +import io.github.null2264.tsukumogami.core.koin.TsukumogamiKoinContext +import org.koin.core.module.Module +import org.koin.dsl.ModuleDeclaration +import org.koin.dsl.module + +fun loadModule( + createdAtStart: Boolean = false, + moduleDeclaration: ModuleDeclaration, +): Module { + val moduleObj = module(createdAtStart, moduleDeclaration) + + TsukumogamiKoinContext.loadKoinModules(moduleObj) + + return moduleObj +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinComponent.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinComponent.kt new file mode 100644 index 0000000..525d75c --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinComponent.kt @@ -0,0 +1,8 @@ +package io.github.null2264.tsukumogami.core.koin + +import org.koin.core.Koin +import org.koin.core.component.KoinComponent + +interface TsukumogamiKoinComponent : KoinComponent { + override fun getKoin(): Koin = TsukumogamiKoinContext.get() +} diff --git a/core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinContext.kt b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinContext.kt new file mode 100644 index 0000000..4ff3ad1 --- /dev/null +++ b/core/src/main/kotlin/io/github/null2264/tsukumogami/core/koin/TsukumogamiKoinContext.kt @@ -0,0 +1,75 @@ +package io.github.null2264.tsukumogami.core.koin + +import org.koin.core.Koin +import org.koin.core.KoinApplication +import org.koin.core.context.KoinContext +import org.koin.core.error.KoinApplicationAlreadyStartedException +import org.koin.core.module.Module +import org.koin.dsl.KoinAppDeclaration + +/** + * The [KoinContext] for Tsukumogami. + * + * To use this context, implement [TsukumogamiKoinComponent]. + * + * @see org.koin.core.context.GlobalContext + */ +object TsukumogamiKoinContext : KoinContext { + /** The current [Koin] instance. */ + private var koin: Koin? = null + + /** The current [KoinApplication]. */ + private var koinApp: KoinApplication? = null + + override fun get(): Koin = koin ?: error("KoinApplication has not been started") + override fun getOrNull(): Koin? = koin + public fun getKoinApplicationOrNull(): KoinApplication? = koinApp + + private fun register(koinApplication: KoinApplication) { + if (koin != null) { + throw KoinApplicationAlreadyStartedException("KoinApplication has already been started") + } + + koinApp = koinApplication + koin = koinApplication.koin + } + + override fun loadKoinModules(module: Module, createEagerInstances: Boolean) { + get().loadModules(listOf(module), createEagerInstances = createEagerInstances) + } + + override fun loadKoinModules(modules: List, createEagerInstances: Boolean) { + get().loadModules(modules, createEagerInstances = createEagerInstances) + } + + override fun startKoin(koinApplication: KoinApplication): KoinApplication = synchronized(this) { + register(koinApplication) + koinApplication.createEagerInstances() + koinApplication.allowOverride(true) + + return koinApplication + } + + override fun startKoin(appDeclaration: KoinAppDeclaration): KoinApplication = synchronized(this) { + val koinApplication = KoinApplication.init() + + register(koinApplication) + appDeclaration(koinApplication) + koinApplication.createEagerInstances() + + return koinApplication + } + + override fun stopKoin() { + koin?.close() + koin = null + } + + override fun unloadKoinModules(module: Module) { + get().unloadModules(listOf(module)) + } + + override fun unloadKoinModules(modules: List) { + get().unloadModules(modules) + } +}