1+ package app.simplecloud.plugin.api.shared.config
2+
3+ import app.simplecloud.plugin.api.shared.repository.GenericEnumSerializer
4+ import kotlinx.coroutines.CoroutineScope
5+ import kotlinx.coroutines.Dispatchers
6+ import kotlinx.coroutines.Job
7+ import kotlinx.coroutines.delay
8+ import kotlinx.coroutines.isActive
9+ import kotlinx.coroutines.launch
10+ import org.spongepowered.configurate.ConfigurationOptions
11+ import org.spongepowered.configurate.kotlin.objectMapperFactory
12+ import org.spongepowered.configurate.kotlin.toNode
13+ import org.spongepowered.configurate.yaml.NodeStyle
14+ import org.spongepowered.configurate.yaml.YamlConfigurationLoader
15+ import java.io.File
16+ import java.nio.file.FileSystems
17+ import java.nio.file.Files
18+ import java.nio.file.Path
19+ import java.nio.file.StandardWatchEventKinds
20+
21+ /* *
22+ * @author Niklas Nieberler
23+ */
24+
25+ class ConfigFactory <E >(
26+ private val file : File ,
27+ private val defaultConfig : E
28+ ) {
29+
30+ private var config = defaultConfig
31+ private val path = file.toPath()
32+
33+ private val configurationLoader = YamlConfigurationLoader .builder()
34+ .path(this .path)
35+ .nodeStyle(NodeStyle .BLOCK )
36+ .defaultOptions { options ->
37+ options.serializers { builder ->
38+ builder.registerAnnotatedObjects(objectMapperFactory())
39+ builder.register(Enum ::class .java, GenericEnumSerializer )
40+ }
41+ }
42+ .build()
43+
44+ fun loadOrCreate () {
45+ registerWatcher()
46+ if (this .file.exists()) {
47+ loadConfig()
48+ return
49+ }
50+ createDefaultConfig()
51+ }
52+
53+ private fun createDefaultConfig () {
54+ this .path.parent?.let { Files .createDirectories(it) }
55+ Files .createFile(this .path)
56+
57+ val configurationNode = this .configurationLoader.load(ConfigurationOptions .defaults())
58+ this .defaultConfig!! .toNode(configurationNode)
59+ this .configurationLoader.save(configurationNode)
60+ }
61+
62+ fun getConfig (): E = this .config
63+
64+ private fun loadConfig () {
65+ val configurationNode = this .configurationLoader.load(ConfigurationOptions .defaults())
66+ this .config = configurationNode.get(this .defaultConfig!! ::class .java)
67+ ? : throw IllegalStateException (" Config could not be loaded" )
68+ }
69+
70+ private fun registerWatcher (): Job {
71+ val watchService = FileSystems .getDefault().newWatchService()
72+ this .path.register(
73+ watchService,
74+ StandardWatchEventKinds .ENTRY_CREATE ,
75+ StandardWatchEventKinds .ENTRY_MODIFY
76+ )
77+
78+ return CoroutineScope (Dispatchers .IO ).launch {
79+ while (isActive) {
80+ val key = watchService.take()
81+
82+ key.pollEvents().forEach { event ->
83+ val path = event.context() as ? Path ? : return @forEach
84+ if (! file.name.contains(path.toString())) return @launch
85+
86+ when (event.kind()) {
87+ StandardWatchEventKinds .ENTRY_CREATE ,
88+ StandardWatchEventKinds .ENTRY_MODIFY -> {
89+ delay(100 )
90+ loadConfig()
91+ }
92+ }
93+ }
94+
95+ key.reset()
96+ }
97+ }
98+ }
99+
100+ }
0 commit comments