import { promises as fs, watch, FSWatcher } from 'fs' import path from 'path' import { Database } from '../database/database' export class DirectoryWatcher { private readonly watchers: Map // Stores watchers with directory ID as the key private readonly db: Database private totalSizes: Map // Stores total sizes per directory ID constructor(pathToDatabaseFile: string) { this.db = new Database(pathToDatabaseFile) this.watchers = new Map() this.totalSizes = new Map() } // Start the watcher and register all directories async start(): Promise { const dbData = await this.db.read() const directorySchemes = dbData.local_resources?.directory_schemes if (!directorySchemes) { this.log('Error: directory_schemes not found in database.', 'error') return } // Initialize watchers for each directory this.registerWatcher(directorySchemes.backup?.id, directorySchemes.backup?.path) this.registerWatcher(directorySchemes.department?.id, directorySchemes.department?.path) this.registerWatcher(directorySchemes.shared?.id, directorySchemes.shared?.path) this.log('Directory watcher started successfully.') } // Register a watcher for a directory with a given ID private registerWatcher(id: string | undefined, directoryPath: string | undefined): void { if (!id || !directoryPath) { this.log(`Skipping watcher: ID or path is missing.`, 'error') return } if (this.watchers.has(id)) { this.log(`Watcher for ID ${id} is already running.`, 'error') return } // Create and store a new watcher const watcher = watch(directoryPath, { recursive: true }, async (eventType, filename) => { if (filename) { this.log(`File change detected in ${directoryPath}: ${eventType} - ${filename}`) await this.handleDirectoryChange(id, directoryPath) } }) this.watchers.set(id, watcher) this.log(`Watching directory: ${directoryPath} (ID: ${id})`) } // Handle directory change and update the correct entry in the database private async handleDirectoryChange(id: string, directoryPath: string): Promise { const result = await this.buildDirectoryScheme(directoryPath) this.totalSizes.set(id, result.size) await this.db.update((data) => { // @ts-ignore if (!data.local_resources || !data.local_resources.directory_schemes[id]) { this.log(`Error: Directory scheme for ID ${id} not found in database.`, 'error') return data } // @ts-ignore data.local_resources.directory_schemes[id].structure = result.structure // @ts-ignore data.local_resources.directory_schemes[id].totalSize = result.size return data }) this.log(`Updated directory scheme for ID: ${id}`) } // Recursively build the directory structure and calculate total size private async buildDirectoryScheme(dirPath: string): Promise<{ structure: any; size: number }> { const directoryScheme: any = {} let totalSize = 0 const items = await fs.readdir(dirPath, { withFileTypes: true }) for (const item of items) { const fullPath = path.join(dirPath, item.name) const stats = await fs.stat(fullPath) if (item.isDirectory()) { const { structure, size } = await this.buildDirectoryScheme(fullPath) directoryScheme[item.name] = structure totalSize += size } else if (item.isFile()) { directoryScheme[item.name] = fullPath totalSize += stats.size } } return { structure: directoryScheme, size: totalSize } } // Stop and remove a watcher for a specific directory ID public stopWatcher(id: string): void { const watcher = this.watchers.get(id) if (watcher) { watcher.close() this.watchers.delete(id) this.log(`Stopped watcher for ID: ${id}`) } } // Stop all watchers public stopAllWatchers(): void { for (const [id, watcher] of this.watchers) { watcher.close() this.log(`Stopped watcher for ID: ${id}`) } this.watchers.clear() } // Unified logging function private log(message: string, level: 'log' | 'error' = 'log'): void { const sourcePrefix = `[DirectoryWatcher]` if (level === 'error') { console.error(`${sourcePrefix} ${message}`) } else { console.log(`${sourcePrefix} ${message}`) } } }