diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/settings/network/NetworkSettingManager.java b/Plan/common/src/main/java/com/djrapitops/plan/system/settings/network/NetworkSettingManager.java
new file mode 100644
index 000000000..cadfae0b8
--- /dev/null
+++ b/Plan/common/src/main/java/com/djrapitops/plan/system/settings/network/NetworkSettingManager.java
@@ -0,0 +1,177 @@
+package com.djrapitops.plan.system.settings.network;
+
+import com.djrapitops.plan.api.exceptions.EnableException;
+import com.djrapitops.plan.system.database.DBSystem;
+import com.djrapitops.plan.system.database.databases.Database;
+import com.djrapitops.plan.system.file.PlanFiles;
+import com.djrapitops.plan.system.info.server.ServerInfo;
+import com.djrapitops.plan.system.settings.config.Config;
+import com.djrapitops.plan.system.settings.config.ConfigReader;
+import com.djrapitops.plan.system.settings.config.ConfigWriter;
+import com.djrapitops.plan.system.settings.config.PlanConfig;
+import com.djrapitops.plan.system.settings.paths.TimeSettings;
+import com.djrapitops.plan.system.tasks.TaskSystem;
+import com.djrapitops.plan.utilities.file.FileWatcher;
+import com.djrapitops.plan.utilities.file.WatchedFile;
+import com.djrapitops.plugin.api.TimeAmount;
+import com.djrapitops.plugin.logging.error.ErrorHandler;
+import com.djrapitops.plugin.task.AbsRunnable;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * In charge of all configs on the network.
+ *
+ * Performs the following tasks related to network configs:
+ * - File modification watching related to server configs
+ * - Database update operations related to server configs
+ * - File update operations from database related to server configs
+ *
+ * @author Rsl1122
+ */
+@Singleton
+public class NetworkSettingManager {
+
+ private final PlanFiles files;
+ private final DBSystem dbSystem;
+ private final ServerInfo serverInfo;
+ private final TaskSystem taskSystem;
+ private PlanConfig config;
+ private ErrorHandler errorHandler;
+
+ private File serverSettingsFolder;
+
+ private FileWatcher watcher;
+
+ @Inject
+ public NetworkSettingManager(
+ PlanFiles files,
+ PlanConfig config,
+ DBSystem dbSystem,
+ ServerInfo serverInfo,
+ TaskSystem taskSystem,
+ ErrorHandler errorHandler
+ ) {
+ this.files = files;
+ this.config = config;
+ this.dbSystem = dbSystem;
+ this.serverInfo = serverInfo;
+ this.taskSystem = taskSystem;
+
+ this.errorHandler = errorHandler;
+ }
+
+ public void enable() throws EnableException {
+ serverSettingsFolder = createServerSettingsFolder();
+
+ watcher = prepareFileWatcher();
+ watcher.start();
+
+ scheduleDBCheckTask();
+ }
+
+ public void disable() {
+ if (watcher != null) {
+ watcher.interrupt();
+ }
+ }
+
+ private FileWatcher prepareFileWatcher() {
+ FileWatcher fileWatcher = new FileWatcher(serverSettingsFolder, errorHandler);
+
+ File[] files = serverSettingsFolder.listFiles((dir, name) -> name.endsWith(".yml"));
+ if (files != null) {
+ for (File file : files) {
+ addFileToWatchList(fileWatcher, file);
+ }
+ }
+
+ return fileWatcher;
+ }
+
+ private void addFileToWatchList(FileWatcher fileWatcher, File file) {
+ try {
+ String fileName = file.getName();
+ String uuidString = fileName.substring(0, fileName.length() - 4);
+ UUID serverUUID = UUID.fromString(uuidString);
+
+ fileWatcher.addToWatchlist(new WatchedFile(file, () -> updateConfigInDB(file, serverUUID)));
+ } catch (IndexOutOfBoundsException | IllegalArgumentException ignore) {
+ /* Invalid file-name, ignored */
+ }
+ }
+
+ private void scheduleDBCheckTask() {
+ long checkPeriod = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MINUTES);
+ taskSystem.registerTask("Config Update DB Checker", new AbsRunnable() {
+ @Override
+ public void run() {
+ checkDBForNewConfigSettings();
+ }
+ }).runTaskTimerAsynchronously(checkPeriod, checkPeriod);
+ }
+
+ private File createServerSettingsFolder() throws EnableException {
+ try {
+ File serverConfigFolder = files.getFileFromPluginFolder("serverConfiguration");
+ Files.createDirectories(serverConfigFolder.toPath());
+ return serverConfigFolder;
+ } catch (IOException e) {
+ throw new EnableException("Could not initialize NetworkSettingManager: " + e.getMessage(), e);
+ }
+ }
+
+ private File getServerConfigFile(UUID serverUUID) {
+ return new File(serverSettingsFolder, serverUUID + ".yml");
+ }
+
+ private void checkDBForNewConfigSettings() {
+ Database database = dbSystem.getDatabase();
+ List serverUUIDs = database.fetch().getServerUUIDs();
+ serverUUIDs.remove(serverInfo.getServerUUID());
+
+ for (UUID serverUUID : serverUUIDs) {
+ checkDBForNewConfigSettings(database, serverUUID);
+ }
+ }
+
+ private void checkDBForNewConfigSettings(Database database, UUID serverUUID) {
+ File configFile = getServerConfigFile(serverUUID);
+ long lastModified = configFile.exists() ? configFile.lastModified() : -1;
+
+ Optional foundConfig = database.fetch().getNewConfig(lastModified, serverUUID);
+ if (foundConfig.isPresent()) {
+ try {
+ new ConfigWriter(configFile.toPath()).write(foundConfig.get());
+ addFileToWatchList(watcher, configFile);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+ private void updateConfigInDB(File file, UUID serverUUID) {
+ if (!file.exists()) {
+ return;
+ }
+
+ Database database = dbSystem.getDatabase();
+
+ try {
+ Config config = new ConfigReader(file.toPath()).read();
+ database.save().saveConfig(serverUUID, config);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/settings/paths/TimeSettings.java b/Plan/common/src/main/java/com/djrapitops/plan/system/settings/paths/TimeSettings.java
index 6ddd34dc7..1c4179939 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/system/settings/paths/TimeSettings.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/system/settings/paths/TimeSettings.java
@@ -22,6 +22,7 @@ public class TimeSettings {
public static final Setting ANALYSIS_REFRESH_PERIOD = new TimeSetting("Time.Periodic_tasks.Analysis_refresh_every");
public static final Setting CLEAN_CACHE_PERIOD = new TimeSetting("Time.Periodic_tasks.Clean_caches_every");
public static final Setting CLEAN_DATABASE_PERIOD = new TimeSetting("Time.Periodic_tasks.Clean_Database_every");
+ public static final Setting CONFIG_UPDATE_INTERVAL = new TimeSetting("Time.Periodic_tasks.Check_DB_for_server_config_files_every");
private TimeSettings() {
/* static variable class */
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java b/Plan/common/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java
index c255de838..4f25386ed 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java
@@ -43,7 +43,7 @@ public abstract class TaskSystem implements SubSystem {
return registerTask(taskName, runnable);
}
- protected PluginRunnable registerTask(String name, AbsRunnable runnable) {
+ public PluginRunnable registerTask(String name, AbsRunnable runnable) {
return runnableFactory.create(name, runnable);
}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/FileWatcher.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/FileWatcher.java
index b791d6447..18e99619a 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/FileWatcher.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/FileWatcher.java
@@ -23,8 +23,8 @@ import com.djrapitops.plugin.utilities.Verify;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
@@ -40,16 +40,16 @@ public class FileWatcher extends Thread {
private volatile boolean running;
private Path watchedPath;
- private List watchedFiles;
+ private Set watchedFiles;
public FileWatcher(File folder, ErrorHandler errorHandler) {
- this(folder, errorHandler, new ArrayList<>());
+ this(folder, errorHandler, new HashSet<>());
}
public FileWatcher(
File folder,
ErrorHandler errorHandler,
- List watchedFiles
+ Set watchedFiles
) {
this.errorHandler = errorHandler;
this.running = false;
@@ -61,6 +61,7 @@ public class FileWatcher extends Thread {
}
public void addToWatchlist(WatchedFile watchedFile) {
+ watchedFiles.remove(watchedFile);
watchedFiles.add(watchedFile);
}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/WatchedFile.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/WatchedFile.java
index a758a7ae9..2df09b56b 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/WatchedFile.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/file/WatchedFile.java
@@ -20,6 +20,7 @@ import com.djrapitops.plan.utilities.java.VoidFunction;
import java.io.File;
import java.nio.file.Path;
+import java.util.Objects;
/**
* File with a consumer that is called if the file is modified.
@@ -41,4 +42,17 @@ public class WatchedFile {
onChange.apply();
}
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ WatchedFile that = (WatchedFile) o;
+ return Objects.equals(file, that.file);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(file);
+ }
}
diff --git a/Plan/common/src/main/resources/bungeeconfig.yml b/Plan/common/src/main/resources/bungeeconfig.yml
index 2257472a5..6e14e70fb 100644
--- a/Plan/common/src/main/resources/bungeeconfig.yml
+++ b/Plan/common/src/main/resources/bungeeconfig.yml
@@ -84,6 +84,8 @@ Time:
Remove_inactive_player_data_after: 180
Unit: DAYS
Periodic_tasks:
+ Check_DB_for_server_config_files_every: 1
+ Unit: MINUTES
Clean_caches_every: 10
Unit: MINUTES
Clean_Database_every: 1
diff --git a/Plan/common/src/main/resources/config.yml b/Plan/common/src/main/resources/config.yml
index 10a275122..f6fc8d97b 100644
--- a/Plan/common/src/main/resources/config.yml
+++ b/Plan/common/src/main/resources/config.yml
@@ -91,6 +91,8 @@ Time:
Periodic_tasks:
Analysis_refresh_every: 60
Unit: MINUTES
+ Check_DB_for_server_config_files_every: 1
+ Unit: MINUTES
Clean_caches_every: 10
Unit: MINUTES
Clean_Database_every: 1