added email verification
This commit is contained in:
@@ -1,163 +1,134 @@
|
||||
import { promises as fs, watch, FSWatcher } from 'fs';
|
||||
import path from 'path';
|
||||
import { MemoryManager } from './memory_manager';
|
||||
import { JsonManager } from './json_manager';
|
||||
import { promises as fs, watch, FSWatcher } from 'fs'
|
||||
import path from 'path'
|
||||
import { JsonDatabase } from '../database/database'
|
||||
import { DatabaseScheme } from '../database/schemes/database_scheme'
|
||||
|
||||
export class DirectoryWatcher {
|
||||
private directoryPath: string;
|
||||
private directoryMemoryId: string;
|
||||
private directoryScheme: any;
|
||||
private applicationInfo: JsonManager;
|
||||
private memoryManager: MemoryManager;
|
||||
private readonly sourceKey: string;
|
||||
private directoryWatcher: FSWatcher | null;
|
||||
private totalSize: number;
|
||||
private isBusy: boolean;
|
||||
private readonly watchers: Map<string, FSWatcher> // Stores watchers with directory ID as the key
|
||||
private readonly db: JsonDatabase<DatabaseScheme, any>
|
||||
private totalSizes: Map<string, number> // Stores total sizes per directory ID
|
||||
|
||||
constructor(memoryManagerPath: string, applicationInfoPath: string, sourceKey: string) {
|
||||
this.sourceKey = sourceKey;
|
||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||
this.memoryManager = new MemoryManager(memoryManagerPath);
|
||||
this.directoryMemoryId = '';
|
||||
this.directoryPath = '';
|
||||
this.directoryWatcher = null;
|
||||
this.totalSize = 0;
|
||||
this.isBusy = false;
|
||||
constructor(pathToDatabaseFile: string) {
|
||||
this.db = new JsonDatabase<DatabaseScheme, any>(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
|
||||
}
|
||||
|
||||
// Start the watcher with a busy flag to prevent overlapping operations
|
||||
async start(): Promise<void> {
|
||||
setInterval(async () => {
|
||||
if (!this.isBusy) {
|
||||
this.isBusy = true;
|
||||
const initialized = await this.initialize();
|
||||
if (initialized) this.log('Directory watcher started successfully.');
|
||||
this.isBusy = false;
|
||||
}
|
||||
}, 10000); // 10-second interval for testing
|
||||
// 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
|
||||
}
|
||||
|
||||
// Method to initialize and validate the backup directory
|
||||
async initialize(): Promise<boolean> {
|
||||
const directoryData = await this.applicationInfo.readValue(this.sourceKey);
|
||||
if (!directoryData) {
|
||||
this.log('Directory data not found in application info.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.directoryPath = directoryData.path;
|
||||
this.directoryMemoryId = directoryData.id;
|
||||
|
||||
if (!this.directoryMemoryId || !this.directoryPath) {
|
||||
this.log('Components of entry in \'DirectoryWatcher\' not found.', 'error');
|
||||
await this.applicationInfo.removeValue(this.sourceKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.directoryScheme || Object.keys(this.directoryScheme).length === 0) {
|
||||
// No structure in memory, scan and save it
|
||||
const result = await this.buildDirectoryScheme(this.directoryPath);
|
||||
this.directoryScheme = result.structure;
|
||||
this.totalSize = result.size;
|
||||
|
||||
await this.memoryManager.updateMetaInformation(this.directoryMemoryId, {
|
||||
structure: this.directoryScheme,
|
||||
totalSize: this.totalSize,
|
||||
});
|
||||
}
|
||||
|
||||
// Start watching the directory (after stopping any existing watcher)
|
||||
this.restartWatcher();
|
||||
return true;
|
||||
if (this.watchers.has(id)) {
|
||||
this.log(`Watcher for ID ${id} is already running.`, 'error')
|
||||
return
|
||||
}
|
||||
|
||||
// Recursively build the directory structure and calculate the total size
|
||||
private async buildDirectoryScheme(dirPath: string): Promise<{ structure: any, size: number }> {
|
||||
const directoryScheme: any = {};
|
||||
let totalSize = 0;
|
||||
// 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)
|
||||
}
|
||||
})
|
||||
|
||||
const items = await fs.readdir(dirPath, { withFileTypes: true });
|
||||
this.watchers.set(id, watcher)
|
||||
this.log(`Watching directory: ${directoryPath} (ID: ${id})`)
|
||||
}
|
||||
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dirPath, item.name);
|
||||
const stats = await fs.stat(fullPath);
|
||||
// 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)
|
||||
|
||||
if (item.isDirectory()) {
|
||||
// If it's a directory, recursively build its structure and accumulate size
|
||||
const { structure, size } = await this.buildDirectoryScheme(fullPath);
|
||||
directoryScheme[item.name] = structure;
|
||||
totalSize += size;
|
||||
} else if (item.isFile()) {
|
||||
// If it's a file, store its full path and accumulate size
|
||||
directoryScheme[item.name] = fullPath;
|
||||
totalSize += stats.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
|
||||
}
|
||||
|
||||
return { structure: directoryScheme, size: totalSize };
|
||||
// @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
|
||||
}
|
||||
}
|
||||
|
||||
// Restart the directory watcher, ensuring any previous watcher is closed
|
||||
private restartWatcher(): void {
|
||||
if (this.directoryWatcher) {
|
||||
this.log('Stopping existing watcher...');
|
||||
this.directoryWatcher.close();
|
||||
}
|
||||
return { structure: directoryScheme, size: totalSize }
|
||||
}
|
||||
|
||||
this.startDirectoryWatcher();
|
||||
// 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}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Start watching the backup directory for changes
|
||||
private startDirectoryWatcher(): void {
|
||||
if (!this.directoryPath) {
|
||||
throw new Error('Backup directory not set. Cannot start watcher.');
|
||||
}
|
||||
|
||||
this.directoryWatcher = watch(this.directoryPath, { recursive: true }, async (eventType, filename) => {
|
||||
if (filename) {
|
||||
this.log(`File change detected: ${eventType} - ${filename}`);
|
||||
// Rebuild the directory scheme and update memory
|
||||
const result = await this.buildDirectoryScheme(this.directoryPath);
|
||||
this.directoryScheme = result.structure;
|
||||
this.totalSize = result.size;
|
||||
|
||||
await this.memoryManager.updateMetaInformation(this.directoryMemoryId, {
|
||||
structure: this.directoryScheme,
|
||||
totalSize: this.totalSize,
|
||||
});
|
||||
|
||||
this.log('Directory structure and size updated in memory.');
|
||||
}
|
||||
});
|
||||
|
||||
this.log(`Watching for changes in: ${this.directoryPath}`);
|
||||
// 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()
|
||||
}
|
||||
|
||||
// Close the directory watcher
|
||||
public closeWatcher(): void {
|
||||
if (this.directoryWatcher) {
|
||||
this.log(`Stopping watcher for ${this.directoryPath}`);
|
||||
this.directoryWatcher.close();
|
||||
this.directoryWatcher = null;
|
||||
}
|
||||
|
||||
if (global.gc) {
|
||||
global.gc();
|
||||
}
|
||||
}
|
||||
|
||||
// Unified logging function
|
||||
private log(message: string, level: 'log' | 'error' = 'log'): void {
|
||||
const sourcePrefix = `[DirectoryWatcher] {${this.capitalize(this.sourceKey)}}`;
|
||||
if (level === 'error') {
|
||||
console.error(`${sourcePrefix} ${message}`);
|
||||
} else {
|
||||
console.log(`${sourcePrefix} ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Capitalize the first letter of the sourceKey
|
||||
private capitalize(str: string): string {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
// 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}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user