LibJF/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java

126 lines
5.1 KiB
Java

package io.gitlab.jfronny.libjf.config.impl.dsl;
import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders;
import io.gitlab.jfronny.gson.*;
import io.gitlab.jfronny.gson.stream.*;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.v2.*;
import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe;
import io.gitlab.jfronny.libjf.config.impl.watch.JfConfigWatchService;
import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Consumer;
public class DefaultConfigIO {
public static Consumer<ConfigInstance> loader(String id) {
return c -> c.getFilePath().ifPresent(path -> {
// Actions cannot be cached since entries can change
if (Files.exists(path)) {
try (BufferedReader br = Files.newBufferedReader(path);
JsonReader jr = GsonHolders.CONFIG.getGson().newJsonReader(br)) {
runActions(id, createActions(c), jr);
} catch (Exception e) {
LibJf.LOGGER.error("Could not read config for " + id, e);
}
}
c.write();
});
}
record Action(Consumer<JsonReader> task, boolean required) {
public Action(Consumer<JsonReader> task) {
this(task, true);
}
}
private static void runActions(String id, Map<String, Action> actions, JsonReader reader) {
try {
if (reader.peek() != JsonToken.BEGIN_OBJECT) {
LibJf.LOGGER.error("Invalid config: Not a JSON object for " + id);
return;
}
Set<String> appeared = new HashSet<>();
reader.beginObject();
while (reader.peek() != JsonToken.END_OBJECT) {
String name = reader.nextName();
if (!actions.containsKey(name)) {
LibJf.LOGGER.warn("Unrecognized key in config for " + id + ": " + name);
continue;
}
if (!appeared.add(name)) {
LibJf.LOGGER.warn("Duplicate key in config for " + id + ": " + name);
continue;
}
actions.get(name).task.accept(reader);
}
reader.endObject();
actions.forEach((name, action) -> {
if (action.required && !appeared.contains(name)) {
LibJf.LOGGER.error("Missing entry in config for " + id + ": " + name);
}
});
} catch (IOException e) {
throw new JsonParseException("Could not read config", e);
}
}
private static Map<String, Action> createActions(ConfigCategory category) {
Map<String, Action> actions = new HashMap<>();
category.getEntries().forEach(entry -> actions.putIfAbsent(entry.getName(), new Action(reader -> {
try {
entry.loadFromJson(reader);
} catch (IllegalAccessException | IOException e) {
LibJf.LOGGER.error("Could not set config entry value of " + entry.getName(), e);
}
})));
category.getCategories().forEach((id, cat) -> {
String innerId = category.getId() + "." + id;
var innerActions = createActions(cat);
actions.putIfAbsent(id, new Action(reader -> runActions(innerId, innerActions, reader)));
});
if (category instanceof DslConfigCategory cat) {
cat.migrations.forEach((id, migration) -> {
actions.putIfAbsent(id, new Action(migration, false));
});
}
return Map.copyOf(actions);
}
public static Consumer<ConfigInstance> writer(String id) {
return c -> c.getFilePath().ifPresent(path -> JfConfigWatchService.lock(path, () -> {
try (BufferedWriter bw = Files.newBufferedWriter(path);
JsonWriter jw = GsonHolders.CONFIG.getGson().newJsonWriter(bw)) {
writeTo(jw, c);
} catch (Exception e) {
LibJf.LOGGER.error("Could not write config for " + id, e);
}
}));
}
private static void writeTo(JsonWriter writer, ConfigCategory category) throws IOException {
category.fix();
String commentText;
if ((commentText = JfConfigSafe.TRANSLATION_SUPPLIER.apply(category.getTranslationPrefix() + "tooltip")) != null) {
writer.comment(commentText);
}
writer.beginObject();
String val;
for (EntryInfo<?> entry : category.getEntries()) {
try {
entry.writeTo(writer, category.getTranslationPrefix());
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not write entry", e);
}
}
for (Map.Entry<String, ConfigCategory> entry : category.getCategories().entrySet()) {
if ((val = JfConfigSafe.TRANSLATION_SUPPLIER.apply(category.getTranslationPrefix() + entry.getKey() + ".title")) != null)
writer.comment(val);
writer.name(entry.getKey());
writeTo(writer, entry.getValue());
}
writer.endObject();
}
}