2022-02-17 18:35:07 +01:00
|
|
|
package io.gitlab.jfronny.libjf.config.impl;
|
2022-02-12 12:16:19 +01:00
|
|
|
|
|
|
|
import io.gitlab.jfronny.libjf.LibJf;
|
|
|
|
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
|
|
|
|
import io.gitlab.jfronny.libjf.coprocess.ThreadCoProcess;
|
|
|
|
import io.gitlab.jfronny.libjf.interfaces.ThrowingRunnable;
|
|
|
|
import net.fabricmc.loader.api.FabricLoader;
|
|
|
|
|
|
|
|
import java.io.Closeable;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.nio.file.*;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import static java.nio.file.StandardWatchEventKinds.*;
|
|
|
|
|
|
|
|
public class JfConfigWatchService extends ThreadCoProcess implements Closeable {
|
|
|
|
private static final Path CONFIG_DIR = FabricLoader.getInstance().getConfigDir();
|
|
|
|
private static final Set<JfConfigWatchService> REGISTERED_INSTANCES = new HashSet<>();
|
|
|
|
private final WatchService service;
|
|
|
|
private static final Map<Path, Integer> locked = new HashMap<>();
|
|
|
|
public static <TEx extends Throwable> void lock(Path p, ThrowingRunnable<TEx> task) throws TEx {
|
|
|
|
synchronized (CONFIG_DIR) {
|
|
|
|
locked.compute(p, (p1, val) -> val == null ? 1 : val + 1);
|
|
|
|
task.run();
|
|
|
|
for (JfConfigWatchService instance : REGISTERED_INSTANCES) {
|
|
|
|
instance.executeIteration();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public JfConfigWatchService() {
|
|
|
|
WatchService ws = null;
|
|
|
|
try {
|
|
|
|
ws = FileSystems.getDefault().newWatchService();
|
|
|
|
CONFIG_DIR.register(ws, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
|
|
|
|
} catch (IOException e) {
|
|
|
|
if (ws != null) {
|
|
|
|
try {
|
|
|
|
ws.close();
|
|
|
|
} catch (IOException ignored) {
|
|
|
|
}
|
|
|
|
ws = null;
|
|
|
|
}
|
|
|
|
LibJf.LOGGER.error("Could not initialize FS watcher for configs");
|
|
|
|
}
|
|
|
|
service = ws;
|
|
|
|
REGISTERED_INSTANCES.add(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void executeIteration() {
|
|
|
|
synchronized (CONFIG_DIR) {
|
|
|
|
WatchKey key = service.poll();
|
|
|
|
if (key != null) {
|
|
|
|
ConfigHolder ch = ConfigHolder.getInstance();
|
|
|
|
for (WatchEvent<?> event : key.pollEvents()) {
|
|
|
|
if (event.context() instanceof Path p) {
|
|
|
|
p = CONFIG_DIR.resolve(p);
|
|
|
|
if (ch.isRegistered(p)) {
|
|
|
|
int lockCurr = locked.getOrDefault(p, 0);
|
|
|
|
if (lockCurr == 0) {
|
|
|
|
LibJf.LOGGER.info("Detected updated config: " + p + ", reloading");
|
|
|
|
ch.get(p).load();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
locked.put(p, lockCurr - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!key.reset()) LibJf.LOGGER.error("Could not reset config watch key");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void close() throws IOException {
|
|
|
|
service.close();
|
|
|
|
REGISTERED_INSTANCES.remove(this);
|
|
|
|
}
|
|
|
|
}
|