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 REGISTERED_INSTANCES = new HashSet<>(); private final WatchService service; private static final Map locked = new HashMap<>(); public static void lock(Path p, ThrowingRunnable 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); } }