improvements in startup launcher

This commit is contained in:
InsanusMokrassar 2022-12-25 10:26:44 +06:00
parent ee56e9543a
commit a83ee86340
6 changed files with 91 additions and 44 deletions

View File

@ -2,6 +2,10 @@
## 0.16.3 ## 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 ## 0.16.2
* `Versions`: * `Versions`:

View File

@ -1,10 +1,8 @@
package dev.inmo.micro_utils.startup.launcher 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 kotlinx.serialization.json.JsonObject
import org.koin.core.KoinApplication 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 * 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 * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will
* deserialize it in its [StartLauncherPlugin.setupDI] * 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) { suspend fun start(rawConfig: JsonObject) {
with(StartLauncherPlugin) { StartLauncherPlugin.start(rawConfig)
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")
}
} }

View File

@ -4,6 +4,8 @@ import dev.inmo.kslog.common.i
import dev.inmo.kslog.common.taggedLogger import dev.inmo.kslog.common.taggedLogger
import dev.inmo.kslog.common.w import dev.inmo.kslog.common.w
import dev.inmo.micro_utils.coroutines.runCatchingSafely 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 dev.inmo.micro_utils.startup.plugin.StartPlugin
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -12,7 +14,10 @@ import kotlinx.coroutines.launch
import kotlinx.serialization.SerialFormat import kotlinx.serialization.SerialFormat
import kotlinx.serialization.StringFormat import kotlinx.serialization.StringFormat
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import org.koin.core.Koin 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.core.module.Module
import org.koin.dsl.binds import org.koin.dsl.binds
import org.koin.dsl.module import org.koin.dsl.module
@ -23,26 +28,20 @@ import org.koin.dsl.module
object StartLauncherPlugin : StartPlugin { object StartLauncherPlugin : StartPlugin {
internal val logger = taggedLogger(this) internal val logger = taggedLogger(this)
/** fun Module.setupDI(config: Config, rawJsonObject: JsonObject? = null) {
* Will deserialize [Config] from [config], register it in receiver [Module] (as well as [CoroutineScope] and val rawJsonObject = rawJsonObject ?: defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject
* [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)
single { pluginsConfig } single { rawJsonObject }
single { config }
single { CoroutineScope(Dispatchers.Default) } single { CoroutineScope(Dispatchers.Default) }
single { defaultJson } binds arrayOf(StringFormat::class, SerialFormat::class) single { defaultJson } binds arrayOf(StringFormat::class, SerialFormat::class)
includes( includes(
pluginsConfig.plugins.mapNotNull { config.plugins.mapNotNull {
runCatching { runCatching {
module { module {
with(it) { with(it) {
setupDI(config) setupDI(rawJsonObject)
} }
} }
}.onFailure { e -> }.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] * 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] * ASYNCHRONOUSLY. Just like in [setupDI], in case of fail in some plugin it will be reported using [logger]
*/ */
override suspend fun startPlugin(koin: Koin) { override suspend fun startPlugin(koin: Koin) {
logger.i("Start starting of subplugins")
val scope = koin.get<CoroutineScope>() val scope = koin.get<CoroutineScope>()
koin.get<Config>().plugins.map { plugin -> koin.get<Config>().plugins.map { plugin ->
scope.launch { scope.launch {
@ -72,5 +88,54 @@ object StartLauncherPlugin : StartPlugin {
} }
} }
}.joinAll() }.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)
} }
} }

View File

@ -1,7 +1,7 @@
import dev.inmo.micro_utils.startup.launcher.Config import dev.inmo.micro_utils.startup.launcher.Config
import dev.inmo.micro_utils.startup.launcher.HelloWorldPlugin 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.defaultJson
import dev.inmo.micro_utils.startup.launcher.start
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
@ -23,7 +23,7 @@ class StartupLaunchingTests {
runTest { runTest {
val job = launch { val job = launch {
start(emptyJson) StartLauncherPlugin.start(emptyJson)
} }
job.join() job.join()
} }
@ -37,7 +37,7 @@ class StartupLaunchingTests {
runTest { runTest {
val job = launch { val job = launch {
start(emptyJson) StartLauncherPlugin.start(emptyJson)
} }
job.join() job.join()
} }

View File

@ -5,6 +5,7 @@ import dev.inmo.kslog.common.i
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
@Deprecated("Useless due to including of the same functionality in StrtLauncherPlugin")
object PluginsStarter { object PluginsStarter {
init { init {
KSLog.default = KSLog("Launcher") KSLog.default = KSLog("Launcher")
@ -15,19 +16,10 @@ object PluginsStarter {
* app inside of [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer] using its * app inside of [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer] using its
* [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer.registerPlugin] method * [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer.registerPlugin] method
*/ */
suspend fun startPlugins(json: JsonObject) { suspend fun startPlugins(json: JsonObject) = StartLauncherPlugin.start(json)
start(json)
}
/** /**
* Will convert [config] to [JsonObject] with auto registration of [dev.inmo.micro_utils.startup.plugin.StartPlugin]s * 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] * in [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer]
*/ */
suspend fun startPlugins(config: Config) { suspend fun startPlugins(config: Config) = StartLauncherPlugin.start(config)
KSLog.i("Start convert config to JSON")
val json = defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject
KSLog.i("Config has been read")
start(json)
}
} }

View File

@ -33,5 +33,5 @@ suspend fun main(args: Array<String>) {
val json = defaultJson.parseToJsonElement(file.readText()).jsonObject val json = defaultJson.parseToJsonElement(file.readText()).jsonObject
KSLog.i("Config has been read") KSLog.i("Config has been read")
start(json) StartLauncherPlugin.start(json)
} }