@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 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? { 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 } } }