Skip to content

Commit ed84925

Browse files
committed
refactor: Simplified system
1 parent 11d73ae commit ed84925

File tree

23 files changed

+578
-394
lines changed

23 files changed

+578
-394
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ kotlin {
2525
sourceSets {
2626
commonMain.dependencies {
2727
implementation(idofrontLibs.kotlinx.serialization.json)
28-
implementation(idofrontLibs.koin.core)
28+
implementation(libs.kodein.di)
29+
implementation(idofrontLibs.kermit)
2930
}
3031
commonTest.dependencies {
3132
implementation(kotlin("test"))
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.mineinabyss.features
2+
3+
import org.kodein.di.DI
4+
import org.kodein.di.DirectDI
5+
import kotlin.reflect.KClass
6+
7+
8+
data class Feature<T : Any>(
9+
val name: String,
10+
val type: KClass<T>, //TODO remove when updating geary, handled by extract now but needed for interop
11+
val dependencies: FeatureDependencies,
12+
val subFeatures: Set<Feature<*>>,
13+
val diBuilder: DI.Builder.() -> Unit,
14+
val extract: DirectDI.() -> T,
15+
val onLoad: DirectDI.() -> Unit,
16+
) {
17+
fun overrideScope(block: DI.Builder.() -> Unit): Feature<T> {
18+
return copy(diBuilder = {
19+
diBuilder()
20+
block()
21+
})
22+
}
23+
24+
override fun toString(): String = name
25+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.mineinabyss.features
2+
3+
import org.kodein.di.DI
4+
import org.kodein.di.DirectDI
5+
import kotlin.reflect.KClass
6+
7+
data class LoadPredicate(val reason: String, val predicate: DirectDI.() -> Boolean)
8+
9+
class FeatureBuilder(
10+
val name: String,
11+
val type: KClass<out Any>,
12+
) : FeatureDSL {
13+
private var dependencies = FeatureDependencies(listOf(), listOf())
14+
private var diBuilder: DI.Builder.() -> Unit = {}
15+
private var onEnable: MutableList<FeatureDI.() -> Unit> = mutableListOf()
16+
private val onLoad: MutableList<DirectDI.() -> Unit> = mutableListOf()
17+
private val subFeatures = mutableSetOf<Feature<*>>()
18+
19+
fun dependencies(block: DI.Builder.() -> Unit) {
20+
diBuilder = block
21+
}
22+
23+
fun onLoad(block: DirectDI.() -> Unit) {
24+
onLoad += block
25+
}
26+
27+
class FeatureDependenciesBuilder {
28+
private val features = mutableListOf<Feature<*>>()
29+
private val plugins = mutableListOf<String>()
30+
private val conditions = mutableListOf<LoadPredicate>()
31+
32+
fun features(vararg feature: Feature<*>) {
33+
features += feature
34+
}
35+
36+
fun plugins(vararg plugins: String) {
37+
this.plugins += plugins
38+
}
39+
40+
fun condition(
41+
reason: String = "Conditions not met",
42+
predicate: DirectDI.() -> Boolean,
43+
) {
44+
conditions += LoadPredicate(reason, predicate)
45+
}
46+
47+
fun build() = FeatureDependencies(
48+
features = features.toList(),
49+
conditions = conditions.toList(),
50+
)
51+
}
52+
53+
fun dependsOn(block: FeatureDependenciesBuilder.() -> Unit) {
54+
dependencies = FeatureDependenciesBuilder().apply(block).build()
55+
}
56+
57+
fun install(vararg features: Feature<*>) {
58+
subFeatures += features
59+
}
60+
61+
62+
//TODO disabling feature should close any AutoCloseable scoped entries
63+
// fun scopedModule(block: ScopeDSL.() -> Unit) {
64+
// scopedModule = block
65+
// }
66+
//
67+
// fun commands(block: context(DICommandContext) RootIdoCommands.() -> Unit) {
68+
// onLoad {
69+
// val context = DICommandContext(get(), get())
70+
// get<Plugin>().commands {
71+
// block(context, this)
72+
// }
73+
// }
74+
// }
75+
//
76+
// fun mainCommand(block: context(DICommandContext) IdoRootCommand.() -> Unit) {
77+
// onLoad {
78+
// get<MainCommand>().subcommand(block)
79+
// }
80+
// }
81+
82+
83+
fun onEnable(block: FeatureDI.() -> Unit) {
84+
onEnable += block
85+
}
86+
87+
fun <T : Any> build(extract: DirectDI.() -> T): Feature<T> {
88+
val onEnable = onEnable.toList()
89+
val onLoad = onLoad.toList()
90+
91+
return Feature(
92+
name = name,
93+
type = type as KClass<T>,
94+
dependencies = dependencies,
95+
subFeatures = subFeatures.toSet(),
96+
diBuilder = {
97+
diBuilder()
98+
99+
// Call onEnable when ready
100+
onReady {
101+
val featureDI = object : DirectDI by this, FeatureDI {}
102+
onEnable.forEach { it(featureDI) }
103+
}
104+
},
105+
extract = extract,
106+
onLoad = { onLoad.forEach { it() } },
107+
)
108+
}
109+
}
110+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.mineinabyss.features
2+
3+
import org.kodein.di.DirectDI
4+
import org.kodein.di.instance
5+
import kotlin.jvm.JvmName
6+
7+
@DslMarker
8+
annotation class FeatureDSLMarker
9+
10+
@FeatureDSLMarker
11+
interface FeatureDSL
12+
13+
interface FeatureDI : DirectDI
14+
15+
fun FeatureDI.addCloseable(block: AutoCloseable) {
16+
instance<FeatureContext>().onClose.add(block)
17+
}
18+
19+
fun FeatureDI.addCloseables(vararg closeable: AutoCloseable) {
20+
closeable.forEach { instance<FeatureContext>().onClose.add(it) }
21+
}
22+
23+
context(di: DirectDI)
24+
inline fun <reified T : Any> get() = di.instance<T>()
25+
26+
fun feature(name: String, block: FeatureBuilder.() -> Unit): Feature<Unit> {
27+
return FeatureBuilder(name, Unit::class).apply(block).build(extract = { })
28+
}
29+
30+
@JvmName("featureWithType")
31+
inline fun <reified T : Any> feature(name: String, block: FeatureBuilder.() -> Unit): Feature<T> {
32+
return FeatureBuilder(name, T::class).apply(block).build(extract = { instance<T>() })
33+
}
34+
35+
data class DICommandContext(val manager: FeatureManager, val feature: Feature<*>)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.mineinabyss.features
2+
3+
data class FeatureDependencies(
4+
val features: List<Feature<*>>,
5+
val conditions: List<LoadPredicate>,
6+
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.mineinabyss.features
2+
3+
import org.kodein.di.DI
4+
import org.kodein.di.instance
5+
6+
class FeatureInstance(
7+
val di: DI,
8+
) {
9+
val context by di.instance<FeatureContext>()
10+
11+
fun close() {
12+
context.onClose.reversed().forEach { it.close() }
13+
}
14+
}
15+
16+
class FeatureContext {
17+
val onClose: MutableList<AutoCloseable> = mutableListOf()
18+
}

0 commit comments

Comments
 (0)