'use strict'; const chokidar = require('chokidar'); const path = require('path'); const { fullScan, processResultDir } = require('./scanner'); const { resetByFileIdAndDevice } = require('./db'); const { broadcast } = require('./sse'); let targetWatcher = null; let resultsWatcher = null; function debounce(fn, ms) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; } function startWatching(targetDir, resultsDir) { stopWatching(); if (!targetDir || !resultsDir) return; // ── Target dir ──────────────────────────────────────────────────────────── // Any change to test files (new cases added or removed) triggers a full // rescan so the test list stays in sync. targetWatcher = chokidar.watch(targetDir, { depth: 1, ignoreInitial: true, awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }, }); const debouncedFullScan = debounce(async () => { await fullScan(targetDir, resultsDir); broadcast({ type: 'update' }); }, 1000); targetWatcher.on('add', debouncedFullScan); targetWatcher.on('unlink', debouncedFullScan); // ── Results dir ─────────────────────────────────────────────────────────── // depth: 1 covers both immediate result subdirectories (addDir/unlinkDir) // and log files inside them (add). resultsWatcher = chokidar.watch(resultsDir, { depth: 1, ignoreInitial: true, awaitWriteFinish: { stabilityThreshold: 2000, pollInterval: 200 }, }); // New result directory → mark test complete resultsWatcher.on('addDir', async (dirPath) => { if (path.normalize(dirPath) === path.normalize(resultsDir)) return; const dirName = path.basename(dirPath); await processResultDir(resultsDir, dirName); broadcast({ type: 'update' }); }); // New log file inside a result directory → update timing resultsWatcher.on('add', async (filePath) => { const dirPath = path.dirname(filePath); if (path.normalize(dirPath) === path.normalize(resultsDir)) return; const dirName = path.basename(dirPath); await processResultDir(resultsDir, dirName); broadcast({ type: 'update' }); }); // Result directory deleted → reset test to pending resultsWatcher.on('unlinkDir', (dirPath) => { if (path.normalize(dirPath) === path.normalize(resultsDir)) return; const dirName = path.basename(dirPath); const segs = dirName.split(/[_\-]/); const test_id = segs.find(s => /^R\d+[A-Z0-9]+$/i.test(s)) || null; const device = segs.find(s => /^CGW\d+$/i.test(s)) || null; if (test_id) { resetByFileIdAndDevice(test_id, device); broadcast({ type: 'update' }); } }); } function stopWatching() { if (targetWatcher) { targetWatcher.close(); targetWatcher = null; } if (resultsWatcher) { resultsWatcher.close(); resultsWatcher = null; } } module.exports = { startWatching, stopWatching };