From a83ee86340f3bb219770937751fb11b05472792b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 25 Dec 2022 10:26:44 +0600 Subject: [PATCH] improvements in startup launcher --- CHANGELOG.md | 4 + .../launcher/src/commonMain/kotlin/Start.kt | 20 +---- .../commonMain/kotlin/StartLauncherPlugin.kt | 89 ++++++++++++++++--- .../kotlin/StartupLaunchingTests.kt | 6 +- .../src/jsMain/kotlin/PluginsStarter.kt | 14 +-- startup/launcher/src/jvmMain/kotlin/Main.kt | 2 +- 6 files changed, 91 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a43808a05..f7a0965a517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.16.3 +* `Startup`: + * `Launcher`: + * All starting API have been moved into `StartLauncherPlugin` and do not require serialize/deserialize cycle for now + ## 0.16.2 * `Versions`: diff --git a/startup/launcher/src/commonMain/kotlin/Start.kt b/startup/launcher/src/commonMain/kotlin/Start.kt index fa22995d9dd..3c3c715f50d 100644 --- a/startup/launcher/src/commonMain/kotlin/Start.kt +++ b/startup/launcher/src/commonMain/kotlin/Start.kt @@ -1,10 +1,8 @@ package dev.inmo.micro_utils.startup.launcher -import dev.inmo.kslog.common.i +import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.setupDI import kotlinx.serialization.json.JsonObject import org.koin.core.KoinApplication -import org.koin.core.context.startKoin -import org.koin.dsl.module /** * Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base @@ -13,19 +11,7 @@ import org.koin.dsl.module * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will * deserialize it in its [StartLauncherPlugin.setupDI] */ +@Deprecated("Fully replaced with StartLauncherPlugin#start", ReplaceWith("StartLauncherPlugin.start(rawConfig)", "dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin")) suspend fun start(rawConfig: JsonObject) { - with(StartLauncherPlugin) { - logger.i("Start initialization") - val koinApp = KoinApplication.init() - koinApp.modules( - module { - setupDI(rawConfig) - } - ) - logger.i("Modules loaded") - startKoin(koinApp) - logger.i("Koin started") - startPlugin(koinApp.koin) - logger.i("App has been setup") - } + StartLauncherPlugin.start(rawConfig) } diff --git a/startup/launcher/src/commonMain/kotlin/StartLauncherPlugin.kt b/startup/launcher/src/commonMain/kotlin/StartLauncherPlugin.kt index fb4b21260d0..f9ca4fe2b8f 100644 --- a/startup/launcher/src/commonMain/kotlin/StartLauncherPlugin.kt +++ b/startup/launcher/src/commonMain/kotlin/StartLauncherPlugin.kt @@ -4,6 +4,8 @@ import dev.inmo.kslog.common.i import dev.inmo.kslog.common.taggedLogger import dev.inmo.kslog.common.w import dev.inmo.micro_utils.coroutines.runCatchingSafely +import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.setupDI +import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.startPlugin import dev.inmo.micro_utils.startup.plugin.StartPlugin import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -12,7 +14,10 @@ import kotlinx.coroutines.launch import kotlinx.serialization.SerialFormat import kotlinx.serialization.StringFormat import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonObject import org.koin.core.Koin +import org.koin.core.KoinApplication +import org.koin.core.context.startKoin import org.koin.core.module.Module import org.koin.dsl.binds import org.koin.dsl.module @@ -23,26 +28,20 @@ import org.koin.dsl.module object StartLauncherPlugin : StartPlugin { internal val logger = taggedLogger(this) - /** - * Will deserialize [Config] from [config], register it in receiver [Module] (as well as [CoroutineScope] and - * [kotlinx.serialization.json.Json]) - * - * Besides, in this method will be called [StartPlugin.setupDI] on each plugin from [Config.plugins]. In case when - * some plugin will not be loaded correctly it will be reported throw the [logger] - */ - override fun Module.setupDI(config: JsonObject) { - val pluginsConfig = defaultJson.decodeFromJsonElement(Config.serializer(), config) + fun Module.setupDI(config: Config, rawJsonObject: JsonObject? = null) { + val rawJsonObject = rawJsonObject ?: defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject - single { pluginsConfig } + single { rawJsonObject } + single { config } single { CoroutineScope(Dispatchers.Default) } single { defaultJson } binds arrayOf(StringFormat::class, SerialFormat::class) includes( - pluginsConfig.plugins.mapNotNull { + config.plugins.mapNotNull { runCatching { module { with(it) { - setupDI(config) + setupDI(rawJsonObject) } } }.onFailure { e -> @@ -52,11 +51,28 @@ object StartLauncherPlugin : StartPlugin { ) } + /** + * Will deserialize [Config] from [config], register it in receiver [Module] (as well as [CoroutineScope] and + * [kotlinx.serialization.json.Json]) + * + * Besides, in this method will be called [StartPlugin.setupDI] on each plugin from [Config.plugins]. In case when + * some plugin will not be loaded correctly it will be reported throw the [logger] + */ + override fun Module.setupDI(config: JsonObject) { + logger.i("Koin for current module has started setup") + setupDI( + defaultJson.decodeFromJsonElement(Config.serializer(), config), + config + ) + logger.i("Koin for current module has been setup") + } + /** * Takes [CoroutineScope] and [Config] from the [koin], and call starting of each plugin from [Config.plugins] * ASYNCHRONOUSLY. Just like in [setupDI], in case of fail in some plugin it will be reported using [logger] */ override suspend fun startPlugin(koin: Koin) { + logger.i("Start starting of subplugins") val scope = koin.get() koin.get().plugins.map { plugin -> scope.launch { @@ -72,5 +88,54 @@ object StartLauncherPlugin : StartPlugin { } } }.joinAll() + logger.i("Complete subplugins start") + } + + /** + * Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base + * plugin + * + * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will + * deserialize it in its [StartLauncherPlugin.setupDI] + */ + suspend fun start(rawConfig: JsonObject) { + + logger.i("Start initialization") + val koinApp = KoinApplication.init() + koinApp.modules( + module { + setupDI(rawConfig) + } + ) + logger.i("Modules loaded") + startKoin(koinApp) + logger.i("Koin started") + startPlugin(koinApp.koin) + logger.i("App has been setup") + + } + + /** + * Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base + * plugin + * + * @param config In difference with other [start] method here config is already deserialized and this config will + * be converted to [JsonObject] as raw config. That means that all plugins from [config] will receive + * serialized version of [config] in [StartPlugin.setupDI] method + */ + suspend fun start(config: Config) { + + logger.i("Start initialization") + val koinApp = KoinApplication.init() + logger.i("Koin app created") + koinApp.modules( + module { + setupDI(config) + } + ) + startKoin(koinApp) + logger.i("Koin started") + startPlugin(koinApp.koin) + } } diff --git a/startup/launcher/src/commonTest/kotlin/StartupLaunchingTests.kt b/startup/launcher/src/commonTest/kotlin/StartupLaunchingTests.kt index 1da5c79224c..fa96f715471 100644 --- a/startup/launcher/src/commonTest/kotlin/StartupLaunchingTests.kt +++ b/startup/launcher/src/commonTest/kotlin/StartupLaunchingTests.kt @@ -1,7 +1,7 @@ import dev.inmo.micro_utils.startup.launcher.Config import dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin +import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin import dev.inmo.micro_utils.startup.launcher.defaultJson -import dev.inmo.micro_utils.startup.launcher.start import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import kotlinx.serialization.json.jsonObject @@ -23,7 +23,7 @@ class StartupLaunchingTests { runTest { val job = launch { - start(emptyJson) + StartLauncherPlugin.start(emptyJson) } job.join() } @@ -37,7 +37,7 @@ class StartupLaunchingTests { runTest { val job = launch { - start(emptyJson) + StartLauncherPlugin.start(emptyJson) } job.join() } diff --git a/startup/launcher/src/jsMain/kotlin/PluginsStarter.kt b/startup/launcher/src/jsMain/kotlin/PluginsStarter.kt index 37bb2e6f1a8..c0a9944becf 100644 --- a/startup/launcher/src/jsMain/kotlin/PluginsStarter.kt +++ b/startup/launcher/src/jsMain/kotlin/PluginsStarter.kt @@ -5,6 +5,7 @@ import dev.inmo.kslog.common.i import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonObject +@Deprecated("Useless due to including of the same functionality in StrtLauncherPlugin") object PluginsStarter { init { KSLog.default = KSLog("Launcher") @@ -15,19 +16,10 @@ object PluginsStarter { * app inside of [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer] using its * [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer.registerPlugin] method */ - suspend fun startPlugins(json: JsonObject) { - start(json) - } + suspend fun startPlugins(json: JsonObject) = StartLauncherPlugin.start(json) /** * Will convert [config] to [JsonObject] with auto registration of [dev.inmo.micro_utils.startup.plugin.StartPlugin]s * in [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer] */ - suspend fun startPlugins(config: Config) { - - KSLog.i("Start convert config to JSON") - val json = defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject - KSLog.i("Config has been read") - - start(json) - } + suspend fun startPlugins(config: Config) = StartLauncherPlugin.start(config) } diff --git a/startup/launcher/src/jvmMain/kotlin/Main.kt b/startup/launcher/src/jvmMain/kotlin/Main.kt index 3d1f475f366..d49fe5d99d7 100644 --- a/startup/launcher/src/jvmMain/kotlin/Main.kt +++ b/startup/launcher/src/jvmMain/kotlin/Main.kt @@ -33,5 +33,5 @@ suspend fun main(args: Array) { val json = defaultJson.parseToJsonElement(file.readText()).jsonObject KSLog.i("Config has been read") - start(json) + StartLauncherPlugin.start(json) }