mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
save selected profile
This commit is contained in:
parent
0ff5430ac4
commit
0fe5b949ad
@ -45,8 +45,10 @@ object ProfileIOManager {
|
|||||||
|
|
||||||
|
|
||||||
lock.unlock()
|
lock.unlock()
|
||||||
notify.awaitOrChange()
|
while (notify.count == 0) {
|
||||||
Thread.sleep(50L) // sometimes changes happen very quickly, we don't want to save 10 times while in change
|
notify.awaitOrChange()
|
||||||
|
Thread.sleep(50L) // sometimes changes happen very quickly, we don't want to save 10 times while in change
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableSet<FileStorage>.work(worker: (Profile, FileStorage, StorageProfileManager<Profile>) -> Unit) {
|
private fun MutableSet<FileStorage>.work(worker: (Profile, FileStorage, StorageProfileManager<Profile>) -> Unit) {
|
||||||
|
@ -21,11 +21,14 @@ import de.bixilon.kutil.cast.CastUtil.unsafeNull
|
|||||||
import de.bixilon.kutil.collections.CollectionUtil.mutableBiMapOf
|
import de.bixilon.kutil.collections.CollectionUtil.mutableBiMapOf
|
||||||
import de.bixilon.kutil.collections.map.bi.AbstractMutableBiMap
|
import de.bixilon.kutil.collections.map.bi.AbstractMutableBiMap
|
||||||
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
|
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
|
||||||
|
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
|
||||||
import de.bixilon.kutil.exception.Broken
|
import de.bixilon.kutil.exception.Broken
|
||||||
import de.bixilon.kutil.file.watcher.FileWatcherService
|
import de.bixilon.kutil.file.watcher.FileWatcherService
|
||||||
|
import de.bixilon.kutil.observer.DataObserver.Companion.observe
|
||||||
import de.bixilon.kutil.observer.DataObserver.Companion.observed
|
import de.bixilon.kutil.observer.DataObserver.Companion.observed
|
||||||
import de.bixilon.kutil.observer.map.bi.BiMapObserver.Companion.observedBiMap
|
import de.bixilon.kutil.observer.map.bi.BiMapObserver.Companion.observedBiMap
|
||||||
import de.bixilon.minosoft.assets.util.FileUtil.mkdirParent
|
import de.bixilon.minosoft.assets.util.FileUtil.mkdirParent
|
||||||
|
import de.bixilon.minosoft.assets.util.InputStreamUtil.readAsString
|
||||||
import de.bixilon.minosoft.config.profile.ProfileType
|
import de.bixilon.minosoft.config.profile.ProfileType
|
||||||
import de.bixilon.minosoft.config.profile.profiles.Profile
|
import de.bixilon.minosoft.config.profile.profiles.Profile
|
||||||
import de.bixilon.minosoft.config.profile.storage.ProfileIOUtil.isValidName
|
import de.bixilon.minosoft.config.profile.storage.ProfileIOUtil.isValidName
|
||||||
@ -62,7 +65,7 @@ abstract class StorageProfileManager<P : Profile> : Iterable<P>, Identified {
|
|||||||
|
|
||||||
open fun migrate(version: Int, data: ObjectNode) = Unit
|
open fun migrate(version: Int, data: ObjectNode) = Unit
|
||||||
open fun migrate(data: ObjectNode): Int {
|
open fun migrate(data: ObjectNode): Int {
|
||||||
val version = data["version"]?.intValue() ?: throw IllegalArgumentException("Data has no version set!")
|
val version = data[VERSION]?.intValue() ?: throw IllegalArgumentException("Data has no version set!")
|
||||||
when {
|
when {
|
||||||
version == latestVersion -> return -1
|
version == latestVersion -> return -1
|
||||||
version > latestVersion -> throw IllegalArgumentException("Profile was created with a newer version!")
|
version > latestVersion -> throw IllegalArgumentException("Profile was created with a newer version!")
|
||||||
@ -82,27 +85,46 @@ abstract class StorageProfileManager<P : Profile> : Iterable<P>, Identified {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun load(name: String, path: File): P {
|
private fun load(name: String, path: File): P {
|
||||||
|
Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Loading profile from $path" }
|
||||||
val stream = FileInputStream(path)
|
val stream = FileInputStream(path)
|
||||||
val content = Jackson.MAPPER.readTree(stream).unsafeCast<ObjectNode>()
|
val content = Jackson.MAPPER.readTree(stream).unsafeCast<ObjectNode>()
|
||||||
stream.close()
|
stream.close()
|
||||||
val storage = FileStorage(name, this, path)
|
val storage = FileStorage(name, this, path)
|
||||||
Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Loading profile from $path" }
|
|
||||||
return load(storage, content)
|
return load(storage, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadSelected(root: File): String? {
|
||||||
|
val file = root.resolve(SELECTED)
|
||||||
|
if (!file.isFile) return null
|
||||||
|
val stream = FileInputStream(file)
|
||||||
|
return stream.readAsString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveSelected(root: File, name: String) {
|
||||||
|
val file = root.resolve(SELECTED)
|
||||||
|
file.mkdirParent()
|
||||||
|
val stream = FileOutputStream(file)
|
||||||
|
stream.write(name.encodeNetwork())
|
||||||
|
stream.close()
|
||||||
|
}
|
||||||
|
|
||||||
open fun load() {
|
open fun load() {
|
||||||
val root = RunConfiguration.CONFIG_DIRECTORY.resolve(identifier.namespace).resolve(identifier.path).toFile()
|
val root = RunConfiguration.CONFIG_DIRECTORY.resolve(identifier.namespace).resolve(identifier.path).toFile()
|
||||||
if (!root.exists()) {
|
if (!root.exists()) {
|
||||||
root.mkdirs()
|
root.mkdirs()
|
||||||
return createDefault()
|
return createDefault()
|
||||||
}
|
}
|
||||||
var selected = DEFAULT_NAME // root.resolve("selected") TODO
|
var selected = loadSelected(root)
|
||||||
|
if (selected == null) {
|
||||||
|
selected = DEFAULT_NAME
|
||||||
|
saveSelected(root, selected)
|
||||||
|
}
|
||||||
if (!selected.isValidName()) selected = DEFAULT_NAME
|
if (!selected.isValidName()) selected = DEFAULT_NAME
|
||||||
val files = root.listFiles() ?: return createDefault()
|
val files = root.listFiles() ?: return createDefault()
|
||||||
|
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
if (!file.name.endsWith(".json")) continue
|
if (!file.name.endsWith(FILE_SUFFIX)) continue
|
||||||
val name = file.name.removeSuffix(".json")
|
val name = file.name.removeSuffix(FILE_SUFFIX)
|
||||||
if (!name.isValidName()) {
|
if (!name.isValidName()) {
|
||||||
Log.log(LogMessageType.PROFILES, LogLevels.WARN) { "Not loading $file: Invalid name!" }
|
Log.log(LogMessageType.PROFILES, LogLevels.WARN) { "Not loading $file: Invalid name!" }
|
||||||
continue
|
continue
|
||||||
@ -120,6 +142,14 @@ abstract class StorageProfileManager<P : Profile> : Iterable<P>, Identified {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.selected = this[selected] ?: create(selected)
|
this.selected = this[selected] ?: create(selected)
|
||||||
|
this::selected.observe(this) {
|
||||||
|
val name = it.storage.unsafeCast<FileStorage>().name
|
||||||
|
DefaultThreadPool += {
|
||||||
|
this.lock.acquire()
|
||||||
|
saveSelected(root, name)
|
||||||
|
this.lock.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
observe(root.toPath())
|
observe(root.toPath())
|
||||||
}
|
}
|
||||||
@ -127,8 +157,8 @@ abstract class StorageProfileManager<P : Profile> : Iterable<P>, Identified {
|
|||||||
private fun observe(root: Path) {
|
private fun observe(root: Path) {
|
||||||
FileWatcherService.watchAsync(root, setOf(ENTRY_MODIFY, ENTRY_CREATE)) { _, path ->
|
FileWatcherService.watchAsync(root, setOf(ENTRY_MODIFY, ENTRY_CREATE)) { _, path ->
|
||||||
val filename = path.fileName.toString()
|
val filename = path.fileName.toString()
|
||||||
if (!filename.endsWith(".json")) return@watchAsync
|
if (!filename.endsWith(FILE_SUFFIX)) return@watchAsync
|
||||||
val profile = this[filename.removeSuffix(".json")] ?: return@watchAsync
|
val profile = this[filename.removeSuffix(FILE_SUFFIX)] ?: return@watchAsync
|
||||||
val storage = profile.storage?.nullCast<FileStorage>() ?: return@watchAsync
|
val storage = profile.storage?.nullCast<FileStorage>() ?: return@watchAsync
|
||||||
if (storage.path.toPath() != path) return@watchAsync
|
if (storage.path.toPath() != path) return@watchAsync
|
||||||
ProfileIOManager.reload(storage)
|
ProfileIOManager.reload(storage)
|
||||||
@ -187,7 +217,7 @@ abstract class StorageProfileManager<P : Profile> : Iterable<P>, Identified {
|
|||||||
profile.lock.acquire()
|
profile.lock.acquire()
|
||||||
storage.saved++
|
storage.saved++
|
||||||
val node = Jackson.MAPPER.valueToTree<ObjectNode>(profile) // TODO: cache jacksonType
|
val node = Jackson.MAPPER.valueToTree<ObjectNode>(profile) // TODO: cache jacksonType
|
||||||
node.put("version", latestVersion)
|
node.put(VERSION, latestVersion)
|
||||||
val string = Jackson.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(node)
|
val string = Jackson.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(node)
|
||||||
val stream = FileOutputStream(path)
|
val stream = FileOutputStream(path)
|
||||||
stream.write(string.encodeNetwork())
|
stream.write(string.encodeNetwork())
|
||||||
@ -228,5 +258,8 @@ abstract class StorageProfileManager<P : Profile> : Iterable<P>, Identified {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val DEFAULT_NAME = "Default"
|
const val DEFAULT_NAME = "Default"
|
||||||
|
const val SELECTED = "selected"
|
||||||
|
const val VERSION = "version"
|
||||||
|
const val FILE_SUFFIX = ".json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user