Skip to content
This repository was archived by the owner on Sep 23, 2024. It is now read-only.

Commit ad9eed0

Browse files
author
DaRacci
committedAug 25, 2022
feat(DataService): Complete rework.
1 parent cb06a93 commit ad9eed0

20 files changed

+596
-215
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package dev.racci.minix.api.data
2+
3+
import dev.racci.minix.api.plugin.logger.MinixLogger
4+
import dev.racci.minix.api.utils.UtilObject
5+
import org.spongepowered.configurate.objectmapping.meta.Constraint
6+
7+
object ConfigConstraints : UtilObject by UtilObject {
8+
private const val SCOPE = "config.constraints"
9+
10+
object Minix : Constraint<MinixConfig<*>.Minix> {
11+
12+
override fun validate(value: MinixConfig<*>.Minix?) {
13+
if (value == null) return
14+
15+
val upper = value.loggingLevel.uppercase()
16+
if (value.loggingLevel != upper) {
17+
value.loggingLevel = upper
18+
}
19+
20+
val enum = enumValues<MinixLogger.LoggingLevel>().find { it.name == value.loggingLevel } ?: return value.plugin.log.warn(scope = SCOPE) { "Invalid logging level '${value.loggingLevel}', using '${MinixLogger.LoggingLevel.INFO.name}' instead." }
21+
value.plugin.log.setLevel(enum)
22+
}
23+
}
24+
}

‎Minix-API/src/main/kotlin/dev/racci/minix/api/data/IConfig.kt

-21
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package dev.racci.minix.api.data
2+
3+
import dev.racci.minix.api.plugin.MinixPlugin
4+
import dev.racci.minix.api.utils.PropertyFinder
5+
import dev.racci.minix.api.utils.adventure.PartialComponent
6+
import dev.racci.minix.api.utils.safeCast
7+
import dev.racci.minix.api.utils.unsafeCast
8+
import net.kyori.adventure.text.Component
9+
import net.kyori.adventure.text.minimessage.MiniMessage
10+
import org.spongepowered.configurate.objectmapping.ConfigSerializable
11+
import kotlin.reflect.KProperty1
12+
import kotlin.reflect.full.declaredMemberProperties
13+
import kotlin.reflect.full.isSubtypeOf
14+
import kotlin.reflect.typeOf
15+
16+
@ConfigSerializable
17+
abstract class LangConfig<P : MinixPlugin> : MinixConfig<P>() {
18+
19+
open val prefixes: Map<String, String> = mapOf()
20+
21+
override fun load() {
22+
val map = prefixes.mapKeys {
23+
if (!it.key.matches(prefixRegex)) "<prefix_${it.key}>" else it.key
24+
}
25+
26+
val initialNested = getNested(this)
27+
val queue = ArrayDeque(initialNested)
28+
while (queue.isNotEmpty()) {
29+
val (instance, property) = queue.removeFirst()
30+
31+
val propInstance = try {
32+
property.get(instance)
33+
} catch (e: ClassCastException) {
34+
continue
35+
}
36+
37+
val nested = getNested(propInstance)
38+
if (nested.isNotEmpty()) {
39+
queue.addAll(nested)
40+
}
41+
42+
propInstance::class.declaredMemberProperties
43+
.filterIsInstance<KProperty1<PropertyFinder<PartialComponent>, PartialComponent>>()
44+
.forEach {
45+
try {
46+
it.get(propInstance).formatRaw(map)
47+
} catch (e: ClassCastException) {
48+
return@forEach
49+
}
50+
}
51+
}
52+
53+
super.handleLoad()
54+
}
55+
56+
operator fun get(key: String, vararg placeholder: Pair<String, () -> Any>): Component {
57+
val keys = key.split(".")
58+
if (keys.size <= 1) return MiniMessage.miniMessage().deserialize("Invalid key: $key")
59+
60+
val prop = LangConfig::class.declaredMemberProperties.find { it.name == keys[0] } ?: return MiniMessage.miniMessage().deserialize("No Property found for $key")
61+
val value = prop.get(this).safeCast<PropertyFinder<PartialComponent>>() ?: return MiniMessage.miniMessage().deserialize("$key's return type is not a property finder class.")
62+
63+
return value[key.substringAfter('.')].get(*placeholder)
64+
}
65+
66+
private fun <T : Any> getNested(instance: T): List<Pair<Any, KProperty1<Any, PropertyFinder<PartialComponent>>>> {
67+
return instance::class.declaredMemberProperties
68+
.filter { it.returnType.isSubtypeOf(typeOf<PropertyFinder<*>>()) }
69+
.filterIsInstance<KProperty1<T, PropertyFinder<PartialComponent>>>()
70+
.map { instance to it }.unsafeCast()
71+
}
72+
73+
companion object {
74+
private val prefixRegex = Regex("<prefix_(.*)>")
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package dev.racci.minix.api.data
2+
3+
import dev.racci.minix.api.annotations.MappedConfig
4+
import dev.racci.minix.api.annotations.MinixInternal
5+
import dev.racci.minix.api.extensions.WithPlugin
6+
import dev.racci.minix.api.extensions.log
7+
import dev.racci.minix.api.plugin.MinixPlugin
8+
import dev.racci.minix.api.utils.kotlin.doesOverride
9+
import io.papermc.paper.configuration.constraint.Constraint
10+
import org.spongepowered.configurate.objectmapping.ConfigSerializable
11+
import org.spongepowered.configurate.objectmapping.meta.Comment
12+
import org.spongepowered.configurate.transformation.ConfigurationTransformation
13+
import kotlin.reflect.KProperty
14+
import kotlin.reflect.full.findAnnotation
15+
16+
@OptIn(MinixInternal::class)
17+
@ConfigSerializable
18+
abstract class MinixConfig<P : MinixPlugin> : WithPlugin<P> {
19+
20+
@Transient
21+
@set:MinixInternal
22+
override lateinit var plugin: P
23+
24+
@Transient
25+
open val version: Int = 1
26+
27+
@Transient
28+
open val versionTransformations: Map<Int, ConfigurationTransformation> = emptyMap()
29+
30+
@Constraint(ConfigConstraints.Minix::class)
31+
val minix: Minix = Minix()
32+
33+
@ConfigSerializable
34+
inner class Minix : InnerConfig() {
35+
@Comment("What LoggingLevel to use. Default is INFO [FATAL, ERROR, WARN, INFO, DEBUG, TRACE]")
36+
var loggingLevel: String = "INFO"
37+
}
38+
39+
// TODO: Find a way to make this work
40+
/**
41+
* Called when a value is updated.
42+
*
43+
* @param kPop The property that was updated.
44+
* @param value The previous value.
45+
*/
46+
open fun updateCallback(kPop: KProperty<*>, value: Any?) = Unit
47+
48+
/** Called when the config is initially loaded. */
49+
open fun handleLoad() = Unit
50+
51+
/** Called when the config is being saved and disposed of. */
52+
open fun handleUnload() = Unit
53+
54+
/** If overridden make sure to call super. */
55+
open fun load() {
56+
if (this::class.doesOverride(MinixConfig<P>::plugin)) {
57+
return log.debug { "Plugin is overriding plugin property" }
58+
}
59+
60+
val annotation = this::class.findAnnotation<MappedConfig>() ?: throw IllegalStateException("${this::class.qualifiedName} is not annotated with @MappedConfig")
61+
val parentKClass = annotation.parent
62+
val parent = getKoin().get<P>(parentKClass)
63+
plugin = parent
64+
65+
handleLoad()
66+
}
67+
68+
abstract inner class InnerConfig {
69+
val plugin: P get() = this@MinixConfig.plugin
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
package dev.racci.minix.api.exceptions
22

3-
class MissingAnnotationException(message: String) : Exception(message)
3+
import kotlin.reflect.KClass
4+
5+
class MissingAnnotationException(
6+
kClass: KClass<*>,
7+
annotation: KClass<Annotation>
8+
) : RuntimeException("Missing annotation ${annotation.simpleName} on ${kClass.qualifiedName}")

‎Minix-API/src/main/kotlin/dev/racci/minix/api/extension/Extension.kt

+21-39
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,19 @@ package dev.racci.minix.api.extension
22

33
import dev.racci.minix.api.annotations.MappedExtension
44
import dev.racci.minix.api.annotations.MinixInternal
5-
import dev.racci.minix.api.extensions.SimpleKListener
6-
import dev.racci.minix.api.extensions.WithPlugin
7-
import dev.racci.minix.api.plugin.Minix
5+
import dev.racci.minix.api.extensions.KListener
86
import dev.racci.minix.api.plugin.MinixPlugin
97
import dev.racci.minix.api.services.DataService
108
import dev.racci.minix.api.services.PluginService
119
import dev.racci.minix.api.utils.getKoin
1210
import dev.racci.minix.api.utils.kotlin.companionParent
1311
import dev.racci.minix.api.utils.now
1412
import dev.racci.minix.api.utils.unsafeCast
15-
import kotlinx.collections.immutable.ImmutableList
16-
import kotlinx.collections.immutable.toImmutableList
13+
import kotlinx.collections.immutable.toImmutableSet
1714
import kotlinx.coroutines.CoroutineScope
1815
import kotlinx.coroutines.SupervisorJob
1916
import kotlinx.datetime.Instant
20-
import org.koin.core.component.KoinComponent
2117
import org.koin.core.component.inject
22-
import org.koin.core.qualifier.Qualifier
2318
import kotlin.reflect.KClass
2419
import kotlin.reflect.KProperty
2520
import kotlin.reflect.full.findAnnotation
@@ -32,48 +27,35 @@ import kotlin.time.Duration.Companion.seconds
3227
* @param P The owning plugin.
3328
* @see DataService
3429
*/
35-
abstract class Extension<P : MinixPlugin> : KoinComponent, Qualifier, WithPlugin<P> {
30+
@OptIn(MinixInternal::class)
31+
abstract class Extension<P : MinixPlugin> : ExtensionSkeleton<P> {
3632
private val annotation by lazy { this::class.findAnnotation<MappedExtension>() }
3733
private val pluginService by inject<PluginService>()
38-
@MinixInternal val eventListener by lazy { SimpleKListener(plugin) }
39-
@MinixInternal val supervisor by lazy { CoroutineScope(SupervisorJob()) }
4034

41-
open val name: String get() = annotation?.name ?: this::class.simpleName ?: throw RuntimeException("Extension name is not defined")
42-
43-
open val bindToKClass: KClass<*>? get() = annotation?.bindToKClass.takeIf { it != Extension::class }
44-
45-
open val minix by inject<Minix>()
46-
47-
open val log get() = plugin.log
48-
49-
open val dependencies: ImmutableList<KClass<out Extension<*>>> get() = annotation?.dependencies?.filterIsInstance<KClass<Extension<*>>>().orEmpty().toImmutableList()
50-
51-
open var state: ExtensionState = ExtensionState.UNLOADED
52-
53-
open val loaded: Boolean get() = state == ExtensionState.LOADED || state == ExtensionState.ENABLED
54-
55-
override val value by lazy(::name)
56-
57-
@MinixInternal
58-
var bound: Boolean = false
59-
60-
/** Called when the plugin loading and not yet enabled. */
61-
open suspend fun handleLoad() {}
35+
final override val name get() = annotation?.name ?: this::class.simpleName ?: throw RuntimeException("Extension name is not defined")
36+
final override val log get() = plugin.log
37+
final override val bindToKClass get() = annotation?.bindToKClass.takeIf { it != Extension::class }
38+
final override val value by lazy { "${plugin.name}:$name" }
39+
final override val supervisor by lazy { CoroutineScope(SupervisorJob()) }
40+
final override val dependencies get() = annotation?.dependencies?.filterIsInstance<KClass<Extension<*>>>().orEmpty().toImmutableSet()
41+
final override var bound = false
42+
final override var state = ExtensionState.UNLOADED
43+
final override val loaded get() = state == ExtensionState.LOADED || state == ExtensionState.ENABLED
44+
final override val eventListener = object : KListener<P> {
45+
override val plugin: P get() = this@Extension.plugin
46+
}
6247

63-
/** Called when the plugin has finished loading and is enabled. */
64-
open suspend fun handleEnable() {}
48+
override suspend fun handleLoad() = Unit
49+
override suspend fun handleEnable() = Unit
6550

66-
/** Called when the plugin is being disabled. */
67-
open suspend fun handleUnload() {}
51+
override suspend fun handleUnload() = Unit
6852

69-
open suspend fun setState(state: ExtensionState) {
53+
suspend fun setState(state: ExtensionState) {
7054
send(plugin, ExtensionStateEvent(this, state))
7155
this.state = state
7256
}
7357

74-
final override fun toString(): String {
75-
return "${plugin.name}:$value"
76-
}
58+
final override fun toString(): String = "${plugin.name}:$value"
7759

7860
/**
7961
* Designed to be applied to a companion object of a class that extends [Extension].
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package dev.racci.minix.api.extension
2+
3+
import dev.racci.minix.api.annotations.MinixInternal
4+
import dev.racci.minix.api.extensions.KListener
5+
import dev.racci.minix.api.extensions.WithPlugin
6+
import dev.racci.minix.api.plugin.MinixPlugin
7+
import dev.racci.minix.api.plugin.logger.MinixLogger
8+
import kotlinx.collections.immutable.ImmutableSet
9+
import kotlinx.coroutines.CoroutineScope
10+
import org.koin.core.qualifier.Qualifier
11+
import kotlin.reflect.KClass
12+
13+
interface ExtensionSkeleton<P : MinixPlugin> : WithPlugin<P>, Qualifier {
14+
/** The Listener, which is used to register events in the extension. */
15+
@MinixInternal
16+
val eventListener: KListener<P>
17+
18+
/** The supervisor scope, which is used to launch coroutines in the extension. */
19+
@MinixInternal
20+
val supervisor: CoroutineScope
21+
22+
/** The required Extensions for this Extension to load. */
23+
@MinixInternal
24+
val dependencies: ImmutableSet<KClass<out Extension<*>>>
25+
26+
/** If the extension has been bound in koin. */
27+
@MinixInternal
28+
var bound: Boolean
29+
30+
/** An external Class to bind to in koin. */
31+
@MinixInternal
32+
val bindToKClass: KClass<*>?
33+
34+
/** The name of the extension. */
35+
val name: String
36+
37+
/** The MinixLogger instance from the plugin. */
38+
@Deprecated("Use the WithPlugin extension instead.", ReplaceWith("WithPlugin<*>.log", "dev.racci.minix.api.extensions.ExPlugin"))
39+
val log: MinixLogger
40+
41+
/** The current state of the extension. */
42+
val state: ExtensionState
43+
44+
/** If the extension is loaded. */
45+
val loaded: Boolean
46+
47+
/** Called when the plugin loading and not yet enabled. */
48+
suspend fun handleLoad()
49+
50+
/** Called when the plugin has finished loading and is enabled. */
51+
suspend fun handleEnable()
52+
53+
/** Called when the plugin is being disabled. */
54+
suspend fun handleUnload()
55+
}

‎Minix-API/src/main/kotlin/dev/racci/minix/api/extensions/ExAdventure.kt

+38
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,27 @@
22

33
package dev.racci.minix.api.extensions
44

5+
import dev.racci.minix.api.utils.adventure.LazyComponentReplacement
6+
import dev.racci.minix.api.utils.adventure.LazyStringReplacement
7+
import dev.racci.minix.api.utils.unsafeCast
8+
import kotlinx.collections.immutable.persistentListOf
59
import net.kyori.adventure.text.Component
610
import net.kyori.adventure.text.format.TextDecoration
11+
import net.kyori.adventure.text.minimessage.MiniMessage
12+
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver
13+
14+
// This is so we don't have to worry about shading etc.
15+
private val components by lazy {
16+
val parent = Component::class.qualifiedName!!.split(".").dropLast(1).joinToString(".")
17+
val path = "() -> $parent"
18+
persistentListOf(
19+
"$path.Component",
20+
"$path.MiniMessage",
21+
"$path.TextComponent",
22+
"$path.KeybindComponent",
23+
"$path.TranslatableComponent"
24+
)
25+
}
726

827
// private val adventure by getKoin().inject<Minix>().value.adventure
928

@@ -12,6 +31,25 @@ import net.kyori.adventure.text.format.TextDecoration
1231
*/
1332
inline fun <reified T : Component> T.noItalic() = decoration(TextDecoration.ITALIC, false) as T
1433

34+
fun MiniMessage.lazyPlaceholder(
35+
input: String,
36+
template: Array<out Pair<String, () -> Any>>
37+
) = deserialize(
38+
input,
39+
TagResolver.resolver(
40+
template.map {
41+
val str = it.second.toString()
42+
TagResolver.resolver(
43+
it.first,
44+
when (str) {
45+
in components -> LazyComponentReplacement { it.second().unsafeCast() }
46+
else -> LazyStringReplacement { it.second().toString() }
47+
}
48+
)
49+
}
50+
)
51+
)
52+
1553
/**
1654
* Gets this player as an audience.
1755
*/

‎Minix-API/src/main/kotlin/dev/racci/minix/api/extensions/ExPlugin.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import dev.racci.minix.api.coroutine.launch
88
import dev.racci.minix.api.coroutine.minecraftDispatcher
99
import dev.racci.minix.api.extension.Extension
1010
import dev.racci.minix.api.plugin.MinixPlugin
11+
import dev.racci.minix.api.plugin.logger.MinixLogger
1112
import dev.racci.minix.api.utils.safeCast
1213
import kotlinx.coroutines.CompletableDeferred
1314
import kotlinx.coroutines.CoroutineScope
1415
import kotlinx.coroutines.Deferred
1516
import kotlinx.coroutines.Job
1617
import org.bukkit.event.Listener
1718
import org.bukkit.plugin.Plugin
19+
import org.koin.core.component.KoinComponent
1820
import java.util.concurrent.CompletableFuture
1921
import kotlin.coroutines.CoroutineContext
2022

@@ -78,7 +80,9 @@ fun WithPlugin<*>.launch(
7880
return plugin.launch(dispatcher, parent, block)
7981
}
8082

81-
interface WithPlugin<T : MinixPlugin> {
83+
val WithPlugin<*>.log: MinixLogger get() = plugin.log
84+
85+
interface WithPlugin<T : MinixPlugin> : KoinComponent {
8286

8387
val plugin: T
8488
}

‎Minix-API/src/main/kotlin/dev/racci/minix/api/plugin/PluginData.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.racci.minix.api.plugin
22

3+
import dev.racci.minix.api.data.MinixConfig
34
import dev.racci.minix.api.extension.Extension
45
import dev.racci.minix.api.extension.ExtensionStateEvent
56
import dev.racci.minix.api.plugin.logger.PluginDependentMinixLogger
@@ -32,7 +33,7 @@ class PluginData<P : MinixPlugin>(val plugin: P) {
3233

3334
val log by lazy { PluginDependentMinixLogger(plugin) }
3435

35-
val configurations by lazy { mutableListOf<KClass<*>>() }
36+
val configurations by lazy { mutableListOf<KClass<MinixConfig<P>>>() }
3637

3738
var metrics: Metrics? = null
3839
}
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,22 @@
11
package dev.racci.minix.api.services
22

3-
import com.github.benmanes.caffeine.cache.LoadingCache
4-
import dev.racci.minix.api.annotations.MappedConfig
5-
import dev.racci.minix.api.exceptions.MissingAnnotationException
3+
import dev.racci.minix.api.data.MinixConfig
64
import dev.racci.minix.api.extension.Extension
75
import dev.racci.minix.api.plugin.Minix
86
import dev.racci.minix.api.plugin.MinixPlugin
9-
import dev.racci.minix.api.utils.safeCast
10-
import dev.racci.minix.api.utils.unsafeCast
11-
import org.spongepowered.configurate.CommentedConfigurationNode
12-
import org.spongepowered.configurate.hocon.HoconConfigurationLoader
13-
import org.spongepowered.configurate.objectmapping.ConfigSerializable
14-
import java.io.File
157
import kotlin.reflect.KClass
168

179
abstract class DataService : Extension<Minix>() {
1810

19-
/**
20-
* Holds and generates new [HoconConfigurationLoader] for Classes annotated with [MappedConfig].
21-
*
22-
* @throws MissingAnnotationException if the class is not annotated with [MappedConfig]
23-
* @throws MissingAnnotationException if the class is not a annotated with [ConfigSerializable]
24-
* @throws IllegalArgumentException if the class is not a subtype of [MinixPlugin]
25-
*/
26-
@get:Throws(MissingAnnotationException::class, IllegalArgumentException::class)
27-
abstract val configurateLoaders: LoadingCache<KClass<*>, HoconConfigurationLoader>
11+
abstract fun <P : MinixPlugin, T : MinixConfig<P>> getConfig(kClass: KClass<T>): T?
2812

29-
/**
30-
* Holds and loads the configurations for Classes annotated with [MappedConfig].
31-
*/
32-
abstract val configurations: LoadingCache<KClass<*>, Pair<Any, CommentedConfigurationNode>>
13+
inline fun <P : MinixPlugin, reified T : MinixConfig<P>> get(): T = this.getConfig(T::class)!!
3314

34-
inline fun <reified T> get(): T = configurations[T::class].first.unsafeCast()
15+
inline fun <P : MinixPlugin, reified T : MinixConfig<P>> getOrNull(): T? = this.getConfig(T::class)
3516

36-
inline fun <reified T : Any> getOrNull(): T? = configurations[T::class].first.safeCast()
37-
38-
inline fun <reified T : Any> inject(): Lazy<T> = lazy(::get)
39-
40-
abstract suspend fun <T : Any> getConfigurateLoader(clazz: KClass<T>, file: File): HoconConfigurationLoader
17+
inline fun <P : MinixPlugin, reified T : MinixConfig<P>> inject(): Lazy<T> = lazy(::get)
4118

4219
companion object : ExtensionCompanion<DataService>() {
43-
inline fun <reified T> Lazy<DataService>.inject(): Lazy<T> = lazy(value::get)
20+
inline fun <P : MinixPlugin, reified T : MinixConfig<P>> Lazy<DataService>.inject(): Lazy<T> = lazy(value::get)
4421
}
4522
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package dev.racci.minix.api.utils
2+
3+
import kotlinx.collections.immutable.PersistentMap
4+
import kotlinx.collections.immutable.toPersistentMap
5+
import kotlin.reflect.KProperty1
6+
import kotlin.reflect.full.declaredMemberProperties
7+
8+
abstract class PropertyFinder<R> {
9+
@Transient
10+
@kotlinx.serialization.Transient
11+
private val propertyMap: PersistentMap<String, KProperty1<Any, R>>
12+
13+
operator fun get(key: String): R = propertyMap[key]?.get(this) ?: throw IllegalArgumentException("No property found for $key")
14+
15+
init {
16+
val properties = this::class.declaredMemberProperties.filterIsInstance<KProperty1<Any, R>>()
17+
propertyMap = properties.associateBy { property ->
18+
buildString {
19+
for ((index, char) in property.name.withIndex()) {
20+
if (index == 0 || char.isLowerCase()) {
21+
append(char)
22+
continue
23+
}
24+
25+
append('.').append(char.lowercaseChar())
26+
}
27+
}
28+
}.toPersistentMap()
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dev.racci.minix.api.utils.adventure
2+
3+
import net.kyori.adventure.text.Component
4+
import net.kyori.adventure.text.minimessage.tag.Inserting
5+
import net.kyori.adventure.text.minimessage.tag.Tag
6+
7+
class LazyComponentReplacement(private val value: () -> Component) : Tag, Inserting {
8+
override fun value() = value.invoke()
9+
10+
override fun allowsChildren() = false
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package dev.racci.minix.api.utils.adventure
2+
3+
import net.kyori.adventure.text.minimessage.tag.PreProcess
4+
import net.kyori.adventure.text.minimessage.tag.Tag
5+
6+
class LazyStringReplacement(private val value: () -> String) : Tag, PreProcess {
7+
override fun value() = value.invoke()
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package dev.racci.minix.api.utils.adventure
2+
3+
import dev.racci.minix.api.extensions.lazyPlaceholder
4+
import dev.racci.minix.api.extensions.msg
5+
import net.kyori.adventure.text.Component
6+
import net.kyori.adventure.text.minimessage.MiniMessage
7+
import org.bukkit.command.CommandSender
8+
import org.spongepowered.configurate.ConfigurationNode
9+
import org.spongepowered.configurate.kotlin.extensions.get
10+
import org.spongepowered.configurate.serialize.SerializationException
11+
import org.spongepowered.configurate.serialize.TypeSerializer
12+
import java.lang.reflect.Type
13+
14+
class PartialComponent private constructor(private var raw: String) {
15+
private var _value = raw
16+
private var dirty = true
17+
private var cache: Component? = null
18+
19+
val value: Component
20+
get() {
21+
if (dirty) {
22+
cache = MiniMessage.miniMessage().deserialize(_value)
23+
dirty = false
24+
}
25+
return cache!!
26+
}
27+
28+
operator fun get(vararg placeholder: Pair<String, () -> Any>): Component = if (placeholder.isEmpty()) {
29+
value
30+
} else MiniMessage.miniMessage().lazyPlaceholder(_value, placeholder)
31+
32+
fun formatRaw(placeholders: Map<String, String>) {
33+
var tmp = raw
34+
placeholders.forEach { (placeholder, prefix) ->
35+
tmp = tmp.replaceFirst(placeholder, prefix)
36+
}
37+
_value = tmp
38+
dirty = true
39+
cache = null
40+
}
41+
42+
companion object {
43+
44+
fun of(raw: String): PartialComponent {
45+
return PartialComponent(raw)
46+
}
47+
48+
infix fun PartialComponent.message(recipient: CommandSender) = recipient.msg(this.get())
49+
}
50+
51+
object Serializer : TypeSerializer<PartialComponent> {
52+
53+
override fun deserialize(
54+
type: Type,
55+
node: ConfigurationNode
56+
): PartialComponent = node.get<String>()?.let(PartialComponent::of) ?: throw SerializationException(type, "Null Partial Component: ${node.path()}")
57+
58+
override fun serialize(
59+
type: Type,
60+
obj: PartialComponent?,
61+
node: ConfigurationNode
62+
) {
63+
if (obj == null) { node.raw(null); return }
64+
node.set(obj.raw)
65+
}
66+
}
67+
}

‎Minix-API/src/main/kotlin/dev/racci/minix/api/utils/collections/CollectionUtils.kt

+17
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ object CollectionUtils : UtilObject by UtilObject {
5757
def: () -> T
5858
): T = elementAtOrNull(index).safeCast() ?: def()
5959

60+
/**
61+
* Find the first element that matches the name given.
62+
*
63+
* @param name the name to match.
64+
* @param ignoreCase true if the name should be matched ignoring case.
65+
* @return the first element that matches the name.
66+
*/
67+
fun Collection<String>.find(
68+
name: String,
69+
ignoreCase: Boolean = false
70+
): String? = find { it.equals(name, ignoreCase) }
71+
6072
/**
6173
* Checks if the array contains the [String] by IgnoreCase.
6274
*
@@ -104,6 +116,11 @@ object CollectionUtils : UtilObject by UtilObject {
104116
def: () -> T
105117
): T = elementAtOrNull(index).safeCast() ?: def()
106118

119+
fun Array<String>.find(
120+
name: String,
121+
ignoreCase: Boolean = false
122+
): String? = find { it.equals(name, ignoreCase) }
123+
107124
/**
108125
* Checks if the map contains the [String] as a key by IgnoreCase.
109126
*

‎Minix-API/src/main/kotlin/dev/racci/minix/api/utils/kotlin/KotlinUtils.kt

+21-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ package dev.racci.minix.api.utils.kotlin
44

55
import dev.racci.minix.api.exceptions.LevelConversionException
66
import kotlin.reflect.KClass
7+
import kotlin.reflect.KFunction
8+
import kotlin.reflect.KProperty1
9+
import kotlin.reflect.full.declaredFunctions
10+
import kotlin.reflect.full.functions
11+
import kotlin.reflect.full.memberProperties
712

813
inline fun <reified T : Throwable, reified U : Any> catch(
914
err: (T) -> U,
@@ -52,8 +57,22 @@ inline fun <reified T : Throwable> booleanCatch(
5257
if (t is T) errorCallback(t) else throw t
5358
}
5459

55-
infix fun KClass<*>.doesOverride(methodName: String): Boolean {
56-
return this.java.methods.find { it.name == methodName } in this.java.declaredMethods
60+
infix fun KClass<*>.doesOverride(functionName: String): Boolean {
61+
val function = this.functions.find { it.name == functionName }
62+
if (function != null) return this.doesOverride(function)
63+
64+
val property = this.memberProperties.find { it.name == functionName }
65+
if (property != null) return this.doesOverride(property)
66+
67+
return false
68+
}
69+
70+
infix fun KClass<*>.doesOverride(function: KFunction<*>): Boolean {
71+
return this.functions.find { it == function } in declaredFunctions
72+
}
73+
74+
infix fun KClass<*>.doesOverride(property: KProperty1<*, *>): Boolean {
75+
return this.memberProperties.find { it == property } in memberProperties
5776
}
5877

5978
/**

‎Minix-Core/src/main/kotlin/dev/racci/minix/core/services/DataServiceImpl.kt

+124-112
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,23 @@ import com.zaxxer.hikari.HikariConfig
77
import com.zaxxer.hikari.HikariDataSource
88
import dev.racci.minix.api.annotations.MappedConfig
99
import dev.racci.minix.api.annotations.MappedExtension
10-
import dev.racci.minix.api.data.IConfig
10+
import dev.racci.minix.api.data.MinixConfig
1111
import dev.racci.minix.api.exceptions.MissingAnnotationException
12+
import dev.racci.minix.api.exceptions.MissingPluginException
1213
import dev.racci.minix.api.plugin.Minix
1314
import dev.racci.minix.api.plugin.MinixPlugin
15+
import dev.racci.minix.api.plugin.logger.MinixLogger
1416
import dev.racci.minix.api.serializables.Serializer
1517
import dev.racci.minix.api.services.DataService
1618
import dev.racci.minix.api.updater.providers.UpdateProvider
19+
import dev.racci.minix.api.utils.Closeable
1720
import dev.racci.minix.api.utils.getKoin
1821
import dev.racci.minix.api.utils.kotlin.ifInitialized
19-
import dev.racci.minix.api.utils.kotlin.ifTrue
2022
import dev.racci.minix.api.utils.safeCast
2123
import dev.racci.minix.api.utils.unsafeCast
22-
import io.leangen.geantyref.TypeToken
23-
import kotlinx.coroutines.Dispatchers
24-
import kotlinx.coroutines.runBlocking
25-
import kotlinx.coroutines.withContext
24+
import kotlinx.coroutines.DelicateCoroutinesApi
25+
import kotlinx.coroutines.ExecutorCoroutineDispatcher
26+
import kotlinx.coroutines.newSingleThreadContext
2627
import net.kyori.adventure.serializer.configurate4.ConfigurateComponentSerializer
2728
import org.bukkit.plugin.Plugin
2829
import org.jetbrains.exposed.dao.Entity
@@ -35,44 +36,39 @@ import org.koin.core.component.KoinComponent
3536
import org.spongepowered.configurate.CommentedConfigurationNode
3637
import org.spongepowered.configurate.ConfigurateException
3738
import org.spongepowered.configurate.hocon.HoconConfigurationLoader
39+
import org.spongepowered.configurate.kotlin.extensions.get
40+
import org.spongepowered.configurate.kotlin.extensions.set
3841
import org.spongepowered.configurate.kotlin.objectMapperFactory
3942
import org.spongepowered.configurate.objectmapping.ConfigSerializable
4043
import org.spongepowered.configurate.serialize.TypeSerializer
4144
import org.spongepowered.configurate.serialize.TypeSerializerCollection
45+
import org.spongepowered.configurate.transformation.ConfigurationTransformation
4246
import java.io.File
43-
import java.io.IOException
4447
import kotlin.reflect.KClass
4548
import kotlin.reflect.full.createInstance
4649
import kotlin.reflect.full.findAnnotation
47-
import kotlin.reflect.full.superclasses
50+
import kotlin.reflect.full.hasAnnotation
4851

4952
@MappedExtension(Minix::class, "Data Service", bindToKClass = DataService::class)
5053
class DataServiceImpl(override val plugin: Minix) : DataService() {
51-
private val configClasses: LoadingCache<KClass<*>, ConfigClass> = Caffeine.newBuilder().build(::ConfigClass)
52-
53-
override val configurateLoaders: LoadingCache<KClass<*>, HoconConfigurationLoader> = Caffeine.newBuilder()
54-
.build() {
55-
val config = configClasses[it]
56-
runBlocking { getConfigurateLoader(it, config.file) }
57-
}
54+
@OptIn(DelicateCoroutinesApi::class)
55+
private val threadContext = object : Closeable<ExecutorCoroutineDispatcher>() {
56+
override fun create() = newSingleThreadContext("Data Service Thread")
57+
override fun onClose() { value.value?.close() }
58+
}
5859

59-
override val configurations: LoadingCache<KClass<*>, Pair<Any, CommentedConfigurationNode>> = Caffeine.newBuilder()
60-
.removalListener<KClass<*>, Pair<Any, CommentedConfigurationNode>> { key, value, cause ->
60+
val configDataHolder: LoadingCache<KClass<MinixConfig<MinixPlugin>>, ConfigData<MinixPlugin, MinixConfig<MinixPlugin>>> = Caffeine.newBuilder()
61+
.executor(threadContext.get().executor)
62+
.removalListener<KClass<*>, ConfigData<*, *>> { key, value, cause ->
6163
if (key == null || value == null || cause == RemovalCause.REPLACED) return@removalListener
62-
log.info { "Saving and disposing configurate class ${key.simpleName}" }
63-
64-
val (config, node) = value
65-
val loader = configurateLoaders[key]
66-
config.safeCast<IConfig>()?.unloadCallback()
67-
if (loader.canSave()) {
68-
node.set(key.java, config)
69-
loader.save(node)
70-
}
64+
log.info(scope = SCOPE) { "Saving and disposing configurate class ${key.simpleName}" }
7165

72-
configurateLoaders.invalidate(key)
73-
configClasses.invalidate(key)
66+
value.configInstance.handleUnload()
67+
if (value.configLoader.canSave()) {
68+
value.save()
69+
}
7470
}
75-
.build { clazz -> runBlocking { loadFrom(ConfigClass(clazz), clazz) } }
71+
.build(::ConfigData)
7672

7773
private val dataSource = lazy {
7874
HikariConfig().apply {
@@ -87,78 +83,73 @@ class DataServiceImpl(override val plugin: Minix) : DataService() {
8783

8884
override suspend fun handleLoad() {
8985
if (!plugin.dataFolder.exists() && !plugin.dataFolder.mkdirs()) {
90-
log.error { "Failed to create data folder!" }
86+
log.error(scope = SCOPE) { "Failed to create data folder!" }
9187
}
9288
}
9389

9490
override suspend fun handleUnload() {
9591
dataSource.ifInitialized(HikariDataSource::close)
96-
configurations.invalidateAll()
92+
configDataHolder.invalidateAll()
9793
}
9894

99-
class ConfigClass(kClass: KClass<*>) {
100-
val mappedConfig: MappedConfig
101-
val plugin: MinixPlugin
102-
val file: File
95+
override fun <P : MinixPlugin, T : MinixConfig<P>> getConfig(kClass: KClass<T>): T? = configDataHolder[kClass.unsafeCast()].configInstance as? T
10396

104-
init {
105-
val annotations = kClass.annotations
106-
mappedConfig = annotations.filterIsInstance<MappedConfig>().firstOrNull() ?: throw MissingAnnotationException("Class ${kClass.qualifiedName} is not annotated with @MappedConfig")
107-
annotations.all { it !is ConfigSerializable }.ifTrue { throw MissingAnnotationException("Class ${kClass.qualifiedName} is not annotated with @ConfigSerializable") }
97+
class ConfigData<P : MinixPlugin, T : MinixConfig<P>>(val kClass: KClass<T>) {
98+
val mappedConfig: MappedConfig = this.kClass.findAnnotation() ?: throw MissingAnnotationException(this.kClass, MappedConfig::class.unsafeCast())
99+
val configInstance: T
100+
val file: File
101+
val node: CommentedConfigurationNode
102+
val configLoader: HoconConfigurationLoader
108103

109-
if (MinixPlugin::class !in mappedConfig.parent.superclasses) {
110-
throw IllegalArgumentException("Class ${mappedConfig.parent.qualifiedName} is not subclass of MinixPlugin")
111-
}
112-
plugin = getKoin().getOrNull<MinixPlugin>(mappedConfig.parent) ?: throw IllegalStateException("Could not find plugin instance for ${mappedConfig.parent}")
113-
file = plugin.dataFolder.resolve(mappedConfig.file)
104+
fun save() {
105+
this.node.set(this.kClass, this.configInstance)
106+
this.configLoader.save(updateNode())
114107
}
115-
}
116-
117-
object PluginData : IdTable<String>("plugin") {
118-
119-
override val id: Column<EntityID<String>> = text("name").entityId()
120-
var newVersion = text("new_version")
121-
var oldVersion = text("old_version")
122-
}
123-
124-
class DataHolder(plugin: EntityID<String>) : Entity<String>(plugin) {
125108

126-
companion object : EntityClass<String, DataHolder>(PluginData), KoinComponent {
109+
private fun updateNode(): CommentedConfigurationNode {
110+
if (!node.virtual()) { // we only want to migrate existing data
111+
val trans = createVersionBuilder()
112+
val startVersion = trans.version(node)
127113

128-
fun getOrNull(id: String): DataHolder? = find { PluginData.id eq id }.firstOrNull()
114+
trans.apply(node)
129115

130-
fun getOrNull(plugin: Plugin): DataHolder? = getOrNull(plugin.name)
116+
val endVersion = trans.version(node)
117+
if (startVersion != endVersion) { // we might not have made any changes
118+
getKoin().get<MinixLogger>().info { "Updated config schema from $startVersion to $endVersion" }
119+
}
120+
}
131121

132-
operator fun get(plugin: Plugin): DataHolder = get(plugin.name)
122+
return node
133123
}
134124

135-
var newVersion by PluginData.newVersion
136-
var oldVersion by PluginData.oldVersion
137-
}
138-
139-
override suspend fun <T : Any> getConfigurateLoader(
140-
clazz: KClass<T>,
141-
file: File
142-
): HoconConfigurationLoader = HoconConfigurationLoader.builder()
143-
.file(file)
144-
.prettyPrinting(true)
145-
.defaultOptions { options ->
146-
options.acceptsType(clazz.java)
147-
options.shouldCopyDefaults(true)
148-
options.serializers { serializerBuilder ->
149-
serializerBuilder.registerAnnotatedObjects(objectMapperFactory())
150-
.registerAll(TypeSerializerCollection.defaults())
151-
.registerAll(ConfigurateComponentSerializer.builder().build().serializers())
152-
.registerAll(UpdateProvider.UpdateProviderSerializer.serializers)
153-
.registerAll(Serializer.serializers)
154-
.also { getSerializerCollection(clazz)?.let(it::registerAll) } // User defined serializers
125+
private fun createVersionBuilder(): ConfigurationTransformation.Versioned {
126+
val builder = ConfigurationTransformation.versionedBuilder()
127+
for ((version, transformation) in configInstance.versionTransformations) {
128+
builder.versionKey()
129+
builder.addVersion(version, transformation)
155130
}
156-
}.build()
157131

158-
private fun getSerializerCollection(clazz: KClass<*>): TypeSerializerCollection? {
159-
val annotation = clazz.findAnnotation<MappedConfig>()
160-
return if (annotation != null) {
161-
val extraSerializers = annotation.serializers.asList().listIterator()
132+
return builder.build()
133+
}
134+
135+
private fun buildConfigLoader() = HoconConfigurationLoader.builder()
136+
.file(file)
137+
.prettyPrinting(true)
138+
.defaultOptions { options ->
139+
options.acceptsType(kClass.java)
140+
options.shouldCopyDefaults(true)
141+
options.serializers { serializerBuilder ->
142+
serializerBuilder.registerAnnotatedObjects(objectMapperFactory())
143+
.registerAll(TypeSerializerCollection.defaults())
144+
.registerAll(ConfigurateComponentSerializer.builder().build().serializers())
145+
.registerAll(UpdateProvider.UpdateProviderSerializer.serializers)
146+
.registerAll(Serializer.serializers)
147+
.also { getSerializerCollection()?.let(it::registerAll) } // User defined serializers
148+
}
149+
}.build()
150+
151+
private fun getSerializerCollection(): TypeSerializerCollection? {
152+
val extraSerializers = mappedConfig.serializers.asList().listIterator()
162153
val collection = TypeSerializerCollection.builder()
163154
while (extraSerializers.hasNext()) {
164155
val nextClazz = extraSerializers.next()
@@ -169,45 +160,66 @@ class DataServiceImpl(override val plugin: Minix) : DataService() {
169160
}.getOrNull() ?: continue
170161
collection.register(nextClazz.java, serializer.safeCast())
171162
}
172-
collection.build()
173-
} else null
174-
}
175163

176-
@Suppress("kotlin:S6307")
177-
@Throws(IOException::class, MissingAnnotationException::class, IllegalArgumentException::class) // uwu dangerous
178-
suspend inline fun <reified T : Any> loadFrom(config: ConfigClass = ConfigClass(T::class)): T? = loadFrom<T>(config, T::class)?.first
164+
return collection.build()
165+
}
179166

180-
@Throws(IOException::class, MissingAnnotationException::class, IllegalArgumentException::class) // uwu dangerous
181-
suspend fun <T> loadFrom(config: ConfigClass, clazz: KClass<*>): Pair<T, CommentedConfigurationNode>? = withContext(Dispatchers.IO) {
182-
if (!config.plugin.dataFolder.exists() && !config.plugin.dataFolder.mkdirs()) {
183-
config.plugin.log.warn { "Failed to create directory: ${config.plugin.dataFolder.absolutePath}" }
184-
return@withContext null
167+
private fun ensureDirectory() {
168+
if (!configInstance.plugin.dataFolder.exists() && !configInstance.plugin.dataFolder.mkdirs()) {
169+
getKoin().get<MinixLogger>().warn { "Failed to create directory: ${configInstance.plugin.dataFolder.absolutePath}" }
170+
}
185171
}
186172

187-
val loader = configurateLoaders[clazz]
173+
init {
174+
println("Building new config on thread: " + Thread.currentThread().name)
175+
176+
if (!this.kClass.hasAnnotation<ConfigSerializable>()) throw MissingAnnotationException(this.kClass, ConfigSerializable::class.unsafeCast())
177+
178+
val plugin = getKoin().getOrNull<MinixPlugin>(this.mappedConfig.parent) ?: throw MissingPluginException("Could not find plugin instance for ${this.mappedConfig.parent}")
179+
this.file = plugin.dataFolder.resolve(this.mappedConfig.file)
180+
181+
ensureDirectory()
182+
this.configLoader = buildConfigLoader()
183+
184+
try {
185+
this.node = this.configLoader.load()
186+
this.configInstance = this.node.get(kClass) ?: throw RuntimeException("Could not load configurate class ${this.kClass.simpleName}")
188187

189-
return@withContext try {
190-
val node = loader.load()
191-
val configNode = node.get(TypeToken.get(clazz.java))
192-
if (!config.file.exists()) {
193-
node.set(clazz.java, configNode)
194-
loader.save(node)
188+
if (!this.file.exists()) {
189+
this.save()
190+
}
191+
192+
this.configInstance.load()
193+
} catch (e: ConfigurateException) {
194+
getKoin().get<MinixLogger>().error(e) { "Failed to load configurate file ${this.file.name}" }
195+
throw e
195196
}
196-
configNode.safeCast<IConfig>()?.loadCallback()
197-
configNode.unsafeCast<T>() to node
198-
} catch (e: ConfigurateException) {
199-
config.plugin.log.error(e) { "Failed to load configurate file ${config.file.name}" }
200-
null
201197
}
202198
}
203199

204-
private inline fun <reified T : Any> save(clazz: KClass<T> = T::class) {
205-
configurateLoaders[clazz].let { loader ->
206-
val (data, node) = configurations[clazz]
207-
node.set(clazz.java, data)
208-
loader.save(node)
200+
object PluginData : IdTable<String>("plugin") {
201+
202+
override val id: Column<EntityID<String>> = text("name").entityId()
203+
var newVersion = text("new_version")
204+
var oldVersion = text("old_version")
205+
}
206+
207+
class DataHolder(plugin: EntityID<String>) : Entity<String>(plugin) {
208+
209+
companion object : EntityClass<String, DataHolder>(PluginData), KoinComponent {
210+
211+
fun getOrNull(id: String): DataHolder? = find { PluginData.id eq id }.firstOrNull()
212+
213+
fun getOrNull(plugin: Plugin): DataHolder? = getOrNull(plugin.name)
214+
215+
operator fun get(plugin: Plugin): DataHolder = get(plugin.name)
209216
}
217+
218+
var newVersion by PluginData.newVersion
219+
var oldVersion by PluginData.oldVersion
210220
}
211221

212-
companion object : ExtensionCompanion<DataServiceImpl>()
222+
companion object : ExtensionCompanion<DataServiceImpl>() {
223+
const val SCOPE = "data"
224+
}
213225
}

‎Minix-Core/src/main/kotlin/dev/racci/minix/core/services/PluginServiceImpl.kt

+13-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import dev.racci.minix.api.plugin.MinixPlugin
1717
import dev.racci.minix.api.plugin.PluginData
1818
import dev.racci.minix.api.plugin.SusPlugin
1919
import dev.racci.minix.api.scheduler.CoroutineScheduler
20-
import dev.racci.minix.api.services.DataService
2120
import dev.racci.minix.api.services.PluginService
2221
import dev.racci.minix.api.utils.kotlin.ifNotEmpty
2322
import dev.racci.minix.api.utils.kotlin.invokeIfNotNull
@@ -62,7 +61,7 @@ import kotlin.reflect.jvm.isAccessible
6261
import kotlin.time.Duration.Companion.seconds
6362

6463
class PluginServiceImpl(val minix: Minix) : PluginService, KoinComponent {
65-
private val dataService by inject<DataService>()
64+
private val dataService by inject<DataServiceImpl>()
6665

6766
override val loadedPlugins by lazy { mutableMapOf<KClass<out MinixPlugin>, MinixPlugin>() }
6867
override val pluginCache: LoadingCache<MinixPlugin, PluginData<MinixPlugin>> = Caffeine.newBuilder().build(::PluginData)
@@ -168,7 +167,7 @@ class PluginServiceImpl(val minix: Minix) : PluginService, KoinComponent {
168167

169168
cache?.configurations?.takeIf(MutableList<*>::isNotEmpty)?.let { configs ->
170169
plugin.log.debug { "Unloading ${configs.size} configurations for ${plugin.name}" }
171-
dataService.configurations.invalidateAll(configs)
170+
dataService.configDataHolder.invalidateAll(configs)
172171
}
173172

174173
plugin.log.debug { "Disabling the coroutine session for ${plugin.name}" }
@@ -248,10 +247,15 @@ class PluginServiceImpl(val minix: Minix) : PluginService, KoinComponent {
248247
classGraph.getClassesWithAnnotation(MappedConfig::class.java)
249248
.filter { matchingAnnotation<MappedConfig>(this, it, "configuration") }
250249
.forEach {
251-
log.debug { "Found MappedConfig [${it.simpleName}] from ${this.name}" }
250+
log.trace(scope = SCOPE) { "Found MappedConfig [${it.simpleName}] from ${this.name}" }
252251
try {
253-
get<DataService>().configurations[it.loadClass().kotlin] // Call the cache so we load can have it loaded.
254-
} catch (ignored: NoBeanDefFoundException) {} // This is so i can auto-magic load the data service.
252+
dataService.configDataHolder[it.loadClass().kotlin.unsafeCast()] // Call the cache so we load can have it loaded.
253+
} catch (ignored: NoBeanDefFoundException) {
254+
// This is so I can auto-magic load the data service.
255+
} catch (e: ClassCastException) {
256+
log.error(e) { "Failed to create configuration ${it.simpleName} for ${this.name}" }
257+
throw e
258+
}
255259
}
256260
}
257261

@@ -461,7 +465,7 @@ class PluginServiceImpl(val minix: Minix) : PluginService, KoinComponent {
461465
}
462466

463467
// TODO: Why oh why is this not working? Please somehow figure out how to get the dependencies of dependencies and so on.
464-
private suspend fun Extension<MinixPlugin>.extensions(
468+
/*private suspend fun Extension<MinixPlugin>.extensions(
465469
extensions: MutableList<Extension<MinixPlugin>>,
466470
dependents: MutableList<Extension<MinixPlugin>>
467471
): MutableList<Extension<MinixPlugin>> {
@@ -475,7 +479,7 @@ class PluginServiceImpl(val minix: Minix) : PluginService, KoinComponent {
475479
extension.setState(ExtensionState.FAILED_DEPENDENCIES)
476480
}
477481
return dependents
478-
}
482+
}*/
479483

480484
private suspend inline fun <reified P : MinixPlugin> P.shutdownInOrder() {
481485
val cache = pluginCache[this]
@@ -510,6 +514,7 @@ class PluginServiceImpl(val minix: Minix) : PluginService, KoinComponent {
510514
}
511515

512516
companion object {
517+
const val SCOPE = "pluginService"
513518

514519
fun Extension<*>.dependsOn(other: Extension<*>): Boolean {
515520
if (this.dependencies.isEmpty()) return false

‎gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# suppress inspection "UnusedProperty" for whole file
22
group=dev.racci
3-
version=3.2.3
3+
version=3.2.4-SNAPSHOT
44
addRunNumber=false
55
kotlinVersion=1.7.10
66
minixVersion=0.7.230

0 commit comments

Comments
 (0)
This repository has been archived.