From d8e098193624a2bef336daf962aba1ab698be049 Mon Sep 17 00:00:00 2001 From: vie10 Date: Thu, 10 Feb 2022 22:10:41 +0200 Subject: [PATCH] Module interface and BaseModule implementation Added some logging utils --- .../ru/foxesworld/foxxey/logging/Logging.kt | 101 ++++++++++++++++++ .../foxesworld/foxxey/modules/BaseModule.kt | 61 +++++++++++ .../ru/foxesworld/foxxey/modules/Module.kt | 62 +++++++++++ 3 files changed, 224 insertions(+) create mode 100644 src/main/kotlin/ru/foxesworld/foxxey/logging/Logging.kt create mode 100644 src/main/kotlin/ru/foxesworld/foxxey/modules/BaseModule.kt create mode 100644 src/main/kotlin/ru/foxesworld/foxxey/modules/Module.kt diff --git a/src/main/kotlin/ru/foxesworld/foxxey/logging/Logging.kt b/src/main/kotlin/ru/foxesworld/foxxey/logging/Logging.kt new file mode 100644 index 0000000..f859ed0 --- /dev/null +++ b/src/main/kotlin/ru/foxesworld/foxxey/logging/Logging.kt @@ -0,0 +1,101 @@ +package ru.foxesworld.foxxey.logging + +import kotlinx.coroutines.runBlocking +import mu.KLogger +import mu.KotlinLogging +import kotlin.system.measureTimeMillis + +/** + * @author vie10 + **/ + +private val log = KotlinLogging.logger { } + +fun main() { + runBlocking { + log.wrappedRunWithoutResult("module", "start") { + + } + } +} + +fun KLogger.debugExceptionAndInfoMessage(exception: Throwable, msg: () -> Any) { + info(msg) + debug(exception, msg) +} + +suspend fun KLogger.wrappedRunWithoutResult( + target: Any, + verb: String, + startEnd: String = "ing", + failureEnd: String = "ing", + successEnd: String = "ed", + block: suspend () -> Unit +) { + wrappedRunWithoutResult( + logging = { + onStart = { + info { "${verb.replaceFirstChar { it.uppercase() }}$startEnd $target.." } + } + onFailure = { + debugExceptionAndInfoMessage(it) { "${verb}$failureEnd $target failed." } + } + onSuccess = { measuredMillis, _ -> + info { + "${ + target.toString().replaceFirstChar { it.uppercase() } + } ${verb}$successEnd in $measuredMillis millis." + } + } + }, + block + ) +} + +suspend fun wrappedRunWithoutResult( + logging: (LoggingBlock.() -> Unit)? = null, + block: suspend () -> Unit +) { + val loggingBlock = if (logging != null) LoggingBlock().apply(logging) else null + loggingBlock?.onStart?.invoke() + val result: Result + val measuredMillis = measureTimeMillis { + result = runCatching { + block() + } + } + + result.onSuccess { + loggingBlock?.onSuccess?.invoke(measuredMillis, it) + }.onFailure { + loggingBlock?.onFailure?.invoke(it) + } +} + +suspend fun wrappedRun( + logging: (LoggingBlock.() -> Unit)? = null, + block: suspend () -> T +): Result { + val loggingBlock = if (logging != null) LoggingBlock().apply(logging) else null + loggingBlock?.onStart?.invoke() + val result: Result + val measuredMillis = measureTimeMillis { + result = runCatching { + block() + } + } + + result.onSuccess { + loggingBlock?.onSuccess?.invoke(measuredMillis, it) + }.onFailure { + loggingBlock?.onFailure?.invoke(it) + } + + return result +} + +class LoggingBlock( + var onStart: (() -> Unit)? = null, + var onSuccess: ((measuredMillis: Long, result: T) -> Unit)? = null, + var onFailure: ((exception: Throwable) -> Unit)? = null +) diff --git a/src/main/kotlin/ru/foxesworld/foxxey/modules/BaseModule.kt b/src/main/kotlin/ru/foxesworld/foxxey/modules/BaseModule.kt new file mode 100644 index 0000000..ece9ef6 --- /dev/null +++ b/src/main/kotlin/ru/foxesworld/foxxey/modules/BaseModule.kt @@ -0,0 +1,61 @@ +package ru.foxesworld.foxxey.modules + +import mu.KotlinLogging +import org.koin.dsl.module +import ru.foxesworld.foxxey.commands.Command +import ru.foxesworld.foxxey.logging.wrappedRunWithoutResult +import ru.foxesworld.foxxey.modules.Module.Info +import ru.foxesworld.foxxey.modules.Module.State +import org.koin.core.module.Module as KoinModule + +private val log = KotlinLogging.logger { } + +/** + * @author vie10 + **/ +abstract class BaseModule( + override val info: Info, + module: (KoinModule.() -> Unit)? = null, + commands: (ArrayList.() -> Unit)? = null +) : Module { + + private val module: KoinModule = module { + module?.run { this() } + } + override val commands: List = arrayListOf().apply { + commands?.run { this() } + } + override val state: State + get() = _state + private var _state: State = State.Unloaded + + final override suspend fun start() = log.wrappedRunWithoutResult( + target = "module $info", + verb = "start" + ) { + onStart() + _state = State.Started + } + + protected abstract fun onStart() + + final override suspend fun stop() = log.wrappedRunWithoutResult( + target = "module $module", + verb = "stop" + ) { + onStop() + _state = State.Stopped + } + + protected abstract fun onStop() + + final override suspend fun load() { + getKoin().loadModules(listOf(module)) + _state = State.Loaded + } + + final override suspend fun unload() { + getKoin().unloadModules(listOf(module)) + _state = State.Unloaded + } +} diff --git a/src/main/kotlin/ru/foxesworld/foxxey/modules/Module.kt b/src/main/kotlin/ru/foxesworld/foxxey/modules/Module.kt new file mode 100644 index 0000000..f1a1e20 --- /dev/null +++ b/src/main/kotlin/ru/foxesworld/foxxey/modules/Module.kt @@ -0,0 +1,62 @@ +package ru.foxesworld.foxxey.modules + +import kotlinx.serialization.SerialName +import org.koin.core.component.KoinComponent +import ru.foxesworld.foxxey.commands.Command +import ru.foxesworld.foxxey.config.ConfigInfo + +/** + * @author vie10 + **/ +interface Module : KoinComponent { + + val info: Info + val state: State + val commands: List + + suspend fun start() + + suspend fun stop() + + suspend fun load() + + suspend fun unload() + + data class Info( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("version-code") + val versionCode: String, + @SerialName("version") + val version: String, + @SerialName("dependencies") + val dependencies: Set, + @SerialName("config") + val config: Set + ) { + + data class Dependency( + @SerialName("id") + val id: String, + @SerialName("version-code") + val versionCode: VersionCode + ) { + + data class VersionCode( + @SerialName("from") + val from: Int, + @SerialName("to") + val to: Int + ) + } + } + + enum class State { + Unloaded, + Loaded, + Stopped, + Started + } +}