+package org.simantics.filesystem.services.internal.sizetracker;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+import org.simantics.filesystem.services.sizetracker.SizeChangeEvent;
+import org.simantics.filesystem.services.sizetracker.SizeTracker;
+import org.simantics.utils.datastructures.file.DirectorySizeTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ *
+ * TODO: change to use quiet time and "post notification" to throttle updates
+ */
+public class SizeTrackerImpl implements SizeTracker {
+
+ private Logger logger = LoggerFactory.getLogger(SizeTrackerImpl.class);
+
+ private Path path;
+ private DirectorySizeServiceImpl service;
+ private DirectorySizeTracker tracker;
+ private CopyOnWriteArrayList<Consumer<SizeChangeEvent>> listeners = new CopyOnWriteArrayList<>();
+ private volatile long oldSize = 0L;
+
+ private LongConsumer theListener = newSize -> {
+ long os = oldSize;
+ oldSize = newSize;
+ //logger.info(path + ": size changed: " + ((double) os / (1024.0*1024.0)) + " MB -> " + ((double) newSize / (1024.0*1024.0)) + " MB");
+ fireSizeChange(os, newSize);
+ };
+
+ public SizeTrackerImpl(DirectorySizeServiceImpl service, Path path) throws IOException {
+ this.service = service;
+ this.path = path;
+ this.tracker = DirectorySizeTracker.startTracker(theListener);
+ }
+
+ public SizeTrackerImpl start() throws IOException {
+ new Thread(() -> {
+ try {
+ synchronized (SizeTrackerImpl.this) {
+ if (tracker != null)
+ tracker.track(path);
+ }
+ } catch (IOException e) {
+ logger.error("Failed to start tracking size of directory " + path, e);
+ }
+ }, "SizeTrackerStarter").start();
+ return this;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (tracker == null)
+ return;
+ tracker.close();
+ tracker = null;
+ service.removeTracker(path);
+ }
+
+ @Override
+ public Path path() {
+ return path;
+ }
+
+ @Override
+ public long size() {
+ return oldSize;
+ }
+
+ @Override
+ public void addListener(Consumer<SizeChangeEvent> listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(Consumer<SizeChangeEvent> listener) {
+ listeners.remove(listener);
+ }
+
+ private void fireSizeChange(long oldSize, long newSize) {
+ SizeChangeEvent e = new SizeChangeEventImpl(path, oldSize, newSize);
+ listeners.forEach(c -> c.accept(e));
+ }
+
+}