aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/gui/config/storage/FirstLevelSplitJsonFolder.kt
blob: b92488ab149f14528ee0b3eb30e3bb5b7a30ac59 (plain)
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
		}
	}
}