/* IMPORT */ import { FileType, TargetEvent } from './enums.js'; import LazyMapSet from './lazy_map_set.js'; import Utils from './utils.js'; import WatcherStats from './watcher_stats.js'; /* MAIN */ class WatcherPoller { constructor() { /* VARIABLES */ this.inos = {}; this.paths = new LazyMapSet(); this.stats = new Map(); } /* API */ getIno(targetPath, event, type) { const inos = this.inos[event]; if (!inos) return; const ino = inos[targetPath]; if (!ino) return; if (type && ino[1] !== type) return; return ino[0]; } getStats(targetPath) { return this.stats.get(targetPath); } async poll(targetPath, timeout) { const stats = await Utils.fs.poll(targetPath, timeout); if (!stats) return; const isSupported = stats.isFile() || stats.isDirectory(); if (!isSupported) return; return new WatcherStats(stats); } reset() { this.inos = {}; this.paths = new LazyMapSet(); this.stats = new Map(); } async update(targetPath, timeout) { const prev = this.getStats(targetPath); const next = await this.poll(targetPath, timeout); this.updateStats(targetPath, next); if (!prev && next) { if (next.isFile()) { this.updateIno(targetPath, TargetEvent.ADD, next); return [TargetEvent.ADD]; } if (next.isDirectory()) { this.updateIno(targetPath, TargetEvent.ADD_DIR, next); return [TargetEvent.ADD_DIR]; } } else if (prev && !next) { if (prev.isFile()) { this.updateIno(targetPath, TargetEvent.UNLINK, prev); return [TargetEvent.UNLINK]; } if (prev.isDirectory()) { this.updateIno(targetPath, TargetEvent.UNLINK_DIR, prev); return [TargetEvent.UNLINK_DIR]; } } else if (prev && next) { if (prev.isFile()) { if (next.isFile()) { if (prev.ino === next.ino && !prev.size && !next.size) return []; // Same path, same content and same file, nothing actually changed this.updateIno(targetPath, TargetEvent.CHANGE, next); return [TargetEvent.CHANGE]; } if (next.isDirectory()) { this.updateIno(targetPath, TargetEvent.UNLINK, prev); this.updateIno(targetPath, TargetEvent.ADD_DIR, next); return [TargetEvent.UNLINK, TargetEvent.ADD_DIR]; } } else if (prev.isDirectory()) { if (next.isFile()) { this.updateIno(targetPath, TargetEvent.UNLINK_DIR, prev); this.updateIno(targetPath, TargetEvent.ADD, next); return [TargetEvent.UNLINK_DIR, TargetEvent.ADD]; } if (next.isDirectory()) { if (prev.ino === next.ino) return []; // Same path and same directory, nothing actually changed this.updateIno(targetPath, TargetEvent.UNLINK_DIR, prev); this.updateIno(targetPath, TargetEvent.ADD_DIR, next); return [TargetEvent.UNLINK_DIR, TargetEvent.ADD_DIR]; } } } return []; } updateIno(targetPath, event, stats) { const inos = this.inos[event] = this.inos[event] || (this.inos[event] = {}); const type = stats.isFile() ? FileType.FILE : FileType.DIR; inos[targetPath] = [stats.ino, type]; } updateStats(targetPath, stats) { if (stats) { this.paths.set(stats.ino, targetPath); this.stats.set(targetPath, stats); } else { const ino = this.stats.get(targetPath)?.ino || -1; this.paths.delete(ino, targetPath); this.stats.delete(targetPath); } } } /* EXPORT */ export default WatcherPoller;