LibJF/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/JfConfigWatchService.java

87 lines
3.1 KiB
Java

package io.gitlab.jfronny.libjf.config.impl;
import io.gitlab.jfronny.commons.throwable.ThrowingRunnable;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder;
import io.gitlab.jfronny.libjf.coprocess.ThreadCoProcess;
import net.fabricmc.loader.api.FabricLoader;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
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() {
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
return;
}
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);
}
}