134 lines
4.4 KiB
TypeScript
134 lines
4.4 KiB
TypeScript
import { promises as fs, watch, FSWatcher } from 'fs'
|
|
import path from 'path'
|
|
import { Database } from '../database/database'
|
|
|
|
export class DirectoryWatcher {
|
|
private readonly watchers: Map<string, FSWatcher> // Stores watchers with directory ID as the key
|
|
private readonly db: Database
|
|
private totalSizes: Map<string, number> // Stores total sizes per directory ID
|
|
|
|
constructor(pathToDatabaseFile: string) {
|
|
this.db = new Database(pathToDatabaseFile)
|
|
this.watchers = new Map<string, FSWatcher>()
|
|
this.totalSizes = new Map<string, number>()
|
|
}
|
|
|
|
// Start the watcher and register all directories
|
|
async start(): Promise<void> {
|
|
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<void> {
|
|
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}`)
|
|
}
|
|
}
|
|
}
|