const path = require('path'); const chokidar = require('chokidar'); const { open, writeFile } = require('fs/promises'); const Environment = require('../models/Environment.js'); class Watcher { constructor() { this.#initialize(); } async #initialize() { if (config?.library === undefined) { throw new Error('library not defined'); } if (config?.library?.sources === undefined || config?.library?.sources.length === 0) { throw new Error('no library sources defined'); } let initialScan = config?.library?.initialscan?.enabled; if (initialScan === undefined) { initialScan = true; } for (let index = 0; index < config.library.sources.length; index++) { const directory = path.resolve(config.library.sources[index]); let ignoreInitial = !initialScan; if (ignoreInitial === false) { let env = new Environment(constants.ENVIRONMENT_LASTSCAN); await env.find('key'); if (env === undefined) { env = new Environment(constants.ENVIRONMENT_LASTSCAN, new Date().getTime().toString()); env.save(); } ignoreInitial = (new Date().getTime() - await this.#checkHiddenFile(directory)) < (config?.library?.initialscan?.maxage || 86400000); } logger.debug('watching directory \'' + directory + '\'...'); this.#handleEvents(chokidar.watch(directory, { ignoreInitial: ignoreInitial })); } } #handleEvents(watcher) { if (watcher === undefined) { return; } watcher.on(constants.FS_EVENT_ADD, (file, stats) => { queue.add(constants.FS_EVENT_ADD, file, stats); }); watcher.on(constants.FS_EVENT_UNLINK, (file, stats) => { queue.add(constants.FS_EVENT_UNLINK, file, stats); }); watcher.on(constants.FS_EVENT_CHANGE, (file, stats) => { queue.add(constants.FS_EVENT_CHANGE, file, stats); }); } async #checkHiddenFile(directory) { if (directory === undefined) { return; } const hiddenFile = path.join(directory, '.kannon'); let filehandle; try { filehandle = await open(hiddenFile); return (await filehandle.readFile()).toString(); } catch (error) { if (error.code === 'ENOENT') { return await this.#createHiddenFile(hiddenFile); } logger.error('encountered an error checking the hidden file \'' + hiddenFile + '\' > ' + error); } finally { filehandle?.close(); } } async #createHiddenFile(file) { if (file === undefined) { return; } const timestamp = new Date().getTime().toString(); try { await writeFile(file, timestamp); return timestamp; } catch (error) { logger.error('encountered an error writing the hidden file \'' + file + '\' > ' + error); } } } module.exports = Watcher;