aboutsummaryrefslogtreecommitdiff
path: root/mod/src/main/java/moe/ymc/acron/config
diff options
context:
space:
mode:
Diffstat (limited to 'mod/src/main/java/moe/ymc/acron/config')
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/Config.java30
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/ConfigReloadCmd.java41
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/json/Client.java45
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/json/Config.java103
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializationException.java18
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializer.java27
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/json/ConfigJsonObject.java7
-rw-r--r--mod/src/main/java/moe/ymc/acron/config/json/Rule.java35
8 files changed, 306 insertions, 0 deletions
diff --git a/mod/src/main/java/moe/ymc/acron/config/Config.java b/mod/src/main/java/moe/ymc/acron/config/Config.java
new file mode 100644
index 0000000..3749c25
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/Config.java
@@ -0,0 +1,30 @@
+package moe.ymc.acron.config;
+
+import moe.ymc.acron.auth.Client;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
+
+import java.net.InetAddress;
+import java.util.Map;
+
+public record Config(@NotNull InetAddress address,
+ int port,
+ boolean useNativeTransport,
+ @NotNull Map<String, Client> clients) {
+ private static final Logger LOGGER = LogManager.getLogger();
+ private static Config globalConfig;
+
+ @NotNull
+ public static Config getGlobalConfig() {
+ return globalConfig;
+ }
+
+ public static void setGlobalConfig(@NotNull Config globalConfig) {
+ Config.globalConfig = globalConfig;
+ LOGGER.info("Config loaded with {} clients. Listening on {}:{}.",
+ globalConfig.clients.size(),
+ globalConfig.address.toString(),
+ globalConfig.port);
+ }
+} \ No newline at end of file
diff --git a/mod/src/main/java/moe/ymc/acron/config/ConfigReloadCmd.java b/mod/src/main/java/moe/ymc/acron/config/ConfigReloadCmd.java
new file mode 100644
index 0000000..2774c4d
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/ConfigReloadCmd.java
@@ -0,0 +1,41 @@
+package moe.ymc.acron.config;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import moe.ymc.acron.config.json.ConfigDeserializationException;
+import moe.ymc.acron.config.json.ConfigDeserializer;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.server.command.ServerCommandSource;
+import net.minecraft.text.LiteralText;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public class ConfigReloadCmd implements Command<ServerCommandSource> {
+ private static final Logger LOGGER = LogManager.getLogger();
+
+ @Override
+ public int run(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
+ LOGGER.info("Reloading rules.");
+ try {
+ final Path config = FabricLoader
+ .getInstance().getConfigDir()
+ .resolve("acron.json");
+ if (!config.toFile().exists()) {
+ throw new IllegalStateException("Cannot find config/acron.json.");
+ }
+ final Config cfg = ConfigDeserializer.deserialize(config.toFile(), false);
+ Config.setGlobalConfig(cfg);
+ context.getSource().sendFeedback(new LiteralText("Rules reloaded."), true);
+ return 0;
+ } catch (IOException | ConfigDeserializationException e) {
+ LOGGER.error("Cannot reload config.", e);
+ context.getSource().sendError(new LiteralText("Cannot reload rules: " +
+ e.getMessage()));
+ return 1;
+ }
+ }
+}
diff --git a/mod/src/main/java/moe/ymc/acron/config/json/Client.java b/mod/src/main/java/moe/ymc/acron/config/json/Client.java
new file mode 100644
index 0000000..4d31308
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/json/Client.java
@@ -0,0 +1,45 @@
+package moe.ymc.acron.config.json;
+
+import com.google.gson.annotations.SerializedName;
+import moe.ymc.acron.auth.Action;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+class Client implements ConfigJsonObject<moe.ymc.acron.auth.Client> {
+ @SerializedName("id")
+ private final String id;
+
+ @SerializedName("token")
+ private final String token;
+
+ @SerializedName("policy_mode")
+ private final Action policyMode;
+
+ @SerializedName("rules")
+ private final List<Rule> rules;
+
+ private Client(String id,
+ String token,
+ Action policyMode,
+ List<Rule> rules) {
+ this.id = id;
+ this.token = token;
+ this.policyMode = policyMode;
+ this.rules = rules;
+ }
+
+ @Override
+ public @NotNull moe.ymc.acron.auth.Client create(boolean startup) throws ConfigDeserializationException {
+ if (id == null || id.trim().equals("") ||
+ token == null || token.trim().equals("")) {
+ throw new ConfigDeserializationException(".clients[].id or .clients[].token is not supplied.");
+ }
+ return new moe.ymc.acron.auth.Client(id,
+ token,
+ policyMode == null ? Action.DENY : policyMode,
+ rules == null ? new moe.ymc.acron.auth.Rule[]{} :
+ rules.stream().map(rule -> rule.create(startup)).toList()
+ .toArray(new moe.ymc.acron.auth.Rule[rules.size()]));
+ }
+}
diff --git a/mod/src/main/java/moe/ymc/acron/config/json/Config.java b/mod/src/main/java/moe/ymc/acron/config/json/Config.java
new file mode 100644
index 0000000..e8c5a83
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/json/Config.java
@@ -0,0 +1,103 @@
+package moe.ymc.acron.config.json;
+
+import com.google.gson.annotations.SerializedName;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+class Config implements ConfigJsonObject<moe.ymc.acron.config.Config> {
+ private static final Logger LOGGER = LogManager.getLogger();
+
+ @SerializedName("listen")
+ private final String listen;
+
+ @SerializedName("port")
+ private final Integer port;
+
+ @SerializedName("native_transport")
+ private final boolean nativeTransport;
+
+ @SerializedName("clients")
+ private final List<Client> clients;
+
+ private Config(String listen,
+ Integer port,
+ boolean nativeTransport,
+ List<Client> clients) {
+ this.listen = listen;
+ this.port = port;
+ this.nativeTransport = nativeTransport;
+ this.clients = clients;
+ }
+
+ @Override
+ public @NotNull moe.ymc.acron.config.Config create(boolean startup) throws ConfigDeserializationException {
+ final InetAddress address;
+ final int p;
+ final boolean nt;
+ if (!startup) {
+ address = moe.ymc.acron.config.Config.getGlobalConfig().address();
+ p = moe.ymc.acron.config.Config.getGlobalConfig().port();
+ nt = moe.ymc.acron.config.Config.getGlobalConfig().useNativeTransport();
+ } else {
+ if (listen == null || listen.trim().equals("")) {
+ address = InetAddress.getLoopbackAddress();
+ } else {
+ try {
+ address = InetAddress.getByName(listen);
+ } catch (UnknownHostException e) {
+ throw new ConfigDeserializationException("Cannot parse address: " + e.getMessage(),
+ true);
+ }
+ }
+ if (port == null) {
+ p = 25575;
+ } else {
+ if (port < 0 || port > 65535) {
+ throw new ConfigDeserializationException("The port is out of range.", true);
+ }
+ p = port;
+ }
+ nt = nativeTransport;
+ }
+
+
+ Map<String, moe.ymc.acron.auth.Client> map;
+ try {
+ if (clients != null) {
+ map = clients.stream()
+ .collect(Collectors.<Client, String, moe.ymc.acron.auth.Client>
+ toMap(client -> client.create(startup).id(),
+ client -> client.create(startup)));
+ } else {
+ map = new HashMap<>(0);
+ }
+ } catch (IllegalStateException e) {
+ // Collision.
+ LOGGER.error("Duplicate clients with the same ID in the Acron configuration. All clients are ignored. " +
+ "Fix the configuration and reload.", e);
+ if (!startup) {
+ throw new ConfigDeserializationException("Duplicate clients with the same ID: " + e.getMessage());
+ }
+ map = new HashMap<>(0);
+ } catch (ConfigDeserializationException e) {
+ LOGGER.error("Cannot parse the Acron configuration. All clients are ignored. " +
+ "Fix the configuration and reload.", e);
+ if (!startup) {
+ throw e;
+ }
+ map = new HashMap<>(0);
+ }
+ return new moe.ymc.acron.config.Config(address,
+ p,
+ nt,
+ map);
+ }
+}
diff --git a/mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializationException.java b/mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializationException.java
new file mode 100644
index 0000000..baf5b35
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializationException.java
@@ -0,0 +1,18 @@
+package moe.ymc.acron.config.json;
+
+public class ConfigDeserializationException extends RuntimeException {
+ private final boolean fetal;
+
+ public ConfigDeserializationException(String message) {
+ this(message, false);
+ }
+
+ public ConfigDeserializationException(String message, boolean fetal) {
+ super(message);
+ this.fetal = fetal;
+ }
+
+ public boolean isFetal() {
+ return fetal;
+ }
+}
diff --git a/mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializer.java b/mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializer.java
new file mode 100644
index 0000000..e91b355
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/json/ConfigDeserializer.java
@@ -0,0 +1,27 @@
+package moe.ymc.acron.config.json;
+
+import com.google.gson.Gson;
+import moe.ymc.acron.config.Config;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+public class ConfigDeserializer {
+ public static @NotNull Config deserialize(@NotNull File file, boolean startup)
+ throws ConfigDeserializationException, IOException {
+ final Reader reader = new FileReader(file);
+ final moe.ymc.acron.config.json.Config config;
+ try {
+ config = new Gson()
+ .fromJson(reader, moe.ymc.acron.config.json.Config.class);
+ } catch (Throwable e) {
+ throw new ConfigDeserializationException("Cannot parse JSON: " + e.getMessage(),
+ true);
+ }
+ reader.close();
+ return config.create(startup);
+ }
+}
diff --git a/mod/src/main/java/moe/ymc/acron/config/json/ConfigJsonObject.java b/mod/src/main/java/moe/ymc/acron/config/json/ConfigJsonObject.java
new file mode 100644
index 0000000..0efd9a9
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/json/ConfigJsonObject.java
@@ -0,0 +1,7 @@
+package moe.ymc.acron.config.json;
+
+import org.jetbrains.annotations.NotNull;
+
+public interface ConfigJsonObject<T> {
+ @NotNull T create(boolean startup) throws ConfigDeserializationException;
+}
diff --git a/mod/src/main/java/moe/ymc/acron/config/json/Rule.java b/mod/src/main/java/moe/ymc/acron/config/json/Rule.java
new file mode 100644
index 0000000..114e17d
--- /dev/null
+++ b/mod/src/main/java/moe/ymc/acron/config/json/Rule.java
@@ -0,0 +1,35 @@
+package moe.ymc.acron.config.json;
+
+import com.google.gson.annotations.SerializedName;
+import moe.ymc.acron.auth.Action;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+class Rule implements ConfigJsonObject<moe.ymc.acron.auth.Rule> {
+ @SerializedName("regex")
+ private final String regex;
+
+ @SerializedName("action")
+ private final Action action;
+
+ @SerializedName("display")
+ private final boolean display;
+
+ private Rule(String regex,
+ Action action,
+ boolean display) {
+ this.regex = regex;
+ this.action = action;
+ this.display = display;
+ }
+
+ public @NotNull moe.ymc.acron.auth.Rule create(boolean startup) throws ConfigDeserializationException {
+ if (regex == null || regex.trim().equals("") ||
+ action == null) throw new ConfigDeserializationException(".clients.[]rules.regex or .clients.[]rules.action is" +
+ "not specified.");
+ return new moe.ymc.acron.auth.Rule(Pattern.compile(regex),
+ action,
+ display);
+ }
+}