1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
@file:OptIn(ExperimentalSerializationApi::class)
package moe.nea.firmament.gui.config.storage
import java.nio.file.Path
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteExisting
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.nameWithoutExtension
import kotlin.io.path.outputStream
import moe.nea.firmament.Firmament
// TODO: make this class write / read async
class FirstLevelSplitJsonFolder(
val context: ConfigLoadContext,
val folder: Path
) {
var hasCreatedBackup = false
fun backup(cause: String) {
if (hasCreatedBackup) return
hasCreatedBackup = true
context.createBackup(folder, cause)
}
fun load(): JsonObject {
context.logInfo("Loading FLSJF from $folder")
if (!folder.exists())
return JsonObject(mapOf())
return try {
folder.listDirectoryEntries("*.json")
.mapNotNull(::loadIndividualFile)
.toMap()
.let(::JsonObject)
.also { context.logInfo("FLSJF from $folder - Voller Erfolg!") }
} catch (ex: Exception) {
context.logError("Could not load files from $folder", ex)
backup("failed-load")
JsonObject(mapOf())
}
}
fun loadIndividualFile(path: Path): Pair<String, JsonElement>? {
context.logDebug("Loading partial file from $path")
return try {
path.inputStream().use {
path.nameWithoutExtension to Firmament.json.decodeFromStream(JsonElement.serializer(), it)
}
} catch (ex: Exception) {
context.logError("Could not load file from $path", ex)
backup("failed-load")
null
}
}
fun save(value: JsonObject) {
context.logInfo("Saving FLSJF to $folder")
context.logDebug("Current value:\n$value")
if (!folder.exists()) {
context.logInfo("Creating folder $folder")
folder.createDirectories()
}
val entries = folder.listDirectoryEntries("*.json")
.toMutableList()
for ((name, element) in value) {
val path = saveIndividualFile(name, element)
if (path != null) {
entries.remove(path)
}
}
if (entries.isNotEmpty()) {
context.logInfo("Deleting additional files.")
for (path in entries) {
context.logInfo("Deleting $path")
backup("save-deletion")
try {
path.deleteExisting()
} catch (ex: Exception) {
context.logError("Could not delete $path", ex)
}
}
}
context.logInfo("FLSJF to $folder - Voller Erfolg!")
}
fun saveIndividualFile(name: String, element: JsonElement): Path? {
try {
context.logDebug("Saving partial file with name $name")
val path = folder.resolve("$name.json")
context.ensureWritable(path)
path.outputStream().use {
Firmament.json.encodeToStream(JsonElement.serializer(), element, it)
}
return path
} catch (ex: Exception) {
context.logError("Could not save $name with value $element", ex)
backup("failed-save")
return null
}
}
}
|