signal-cli/src/main/java/org/asamk/signal/ConfigLoader.java

82 lines
2.9 KiB
Java

package org.asamk.signal;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.asamk.signal.commands.exceptions.UserErrorException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Loads and merges configuration files. Merge order (later files override earlier):
* - /etc/signal-cli/config.json
* - file pointed to by SIGNAL_CLI_CONFIG (if set)
* - $XDG_CONFIG_HOME/signal-cli/config.json or $HOME/.config/signal-cli/config.json
*/
public final class ConfigLoader {
private ConfigLoader() {
}
public static GlobalConfig load() throws UserErrorException {
final ObjectMapper mapper = new ObjectMapper();
final ObjectNode merged = mapper.createObjectNode();
// System config
addIfExists(merged, mapper, Paths.get("/etc/signal-cli/config.json"));
// User config via env (if set) else XDG or ~/.config
final String env = System.getenv("SIGNAL_CLI_CONFIG");
if (env != null && !env.isEmpty()) {
addIfExists(merged, mapper, Paths.get(env));
} else {
final String xdg = System.getenv("XDG_CONFIG_HOME");
if (xdg != null && !xdg.isEmpty()) {
addIfExists(merged, mapper, Paths.get(xdg, "signal-cli", "config.json"));
} else {
addIfExists(merged,
mapper,
Paths.get(System.getProperty("user.home"), ".config", "signal-cli", "config.json"));
}
}
try {
if (merged.isEmpty()) {
return GlobalConfig.DEFAULT;
}
return mapper.treeToValue(merged, GlobalConfig.class);
} catch (Exception e) {
throw new UserErrorException("Failed to parse configuration file(s): " + e.getMessage(), e);
}
}
private static void addIfExists(ObjectNode merged, ObjectMapper mapper, Path p) throws UserErrorException {
if (p == null) return;
try {
if (Files.exists(p)) {
final JsonNode node = mapper.readTree(p.toFile());
merge(merged, node);
}
} catch (IOException e) {
throw new UserErrorException("Failed to load config from " + p + ": " + e.getMessage(), e);
}
}
private static void merge(ObjectNode target, JsonNode source) {
source.properties().forEach(entry -> {
final String name = entry.getKey();
final JsonNode value = entry.getValue();
final JsonNode existing = target.get(name);
if (existing != null && existing.isObject() && value.isObject()) {
merge((ObjectNode) existing, value);
} else {
target.set(name, value);
}
});
}
}