import fs from 'fs'; import path from 'path'; export class QueueManager { private readonly filePath: string; private readonly lockFilePath: string; private queue: T[]; private readonly compareFn: (a: T, b: T) => boolean; // Comparison function constructor(filePath: string, compareFn: (a: T, b: T) => boolean) { this.filePath = filePath; this.lockFilePath = `${filePath}.lock`; // Define the lock file path this.queue = []; this.compareFn = compareFn; const dir = path.dirname(filePath); // Check if the directory exists, throw error if it doesn't if (!fs.existsSync(dir)) { throw new Error(`The directory does not exist: ${dir}`); } // If the file doesn't exist, create it if (!fs.existsSync(filePath)) { fs.writeFileSync(filePath, JSON.stringify([], null, 2), 'utf8'); } } // Method to acquire a lock (create .lock file) private acquireLock(): void { while (fs.existsSync(this.lockFilePath)) { // Wait until the lock file is released this.sleepSync(100); // 100ms delay before retrying } // Create the lock file fs.writeFileSync(this.lockFilePath, ''); } // Sleep function to simulate delay for locking mechanism private sleepSync(ms: number): void { const start = Date.now(); while (Date.now() - start < ms) { // busy wait } } // Method to release the lock (delete .lock file) private releaseLock(): void { if (fs.existsSync(this.lockFilePath)) { fs.unlinkSync(this.lockFilePath); } } // Load the queue from the JSON file loadQueue(): void { this.acquireLock(); // Acquire the lock try { const fileData = fs.readFileSync(this.filePath, 'utf8'); this.queue = JSON.parse(fileData) || []; } catch (err) { // If the file doesn't exist or is invalid, start with an empty queue this.queue = []; } finally { this.releaseLock(); // Release the lock } } // Save the queue back to the JSON file saveQueue(): void { this.acquireLock(); // Acquire the lock try { fs.writeFileSync(this.filePath, JSON.stringify(this.queue, null, 2), 'utf8'); } finally { this.releaseLock(); // Release the lock } } // Enqueue: Add an item to the end of the queue if it doesn't already exist enqueue(item: T): void { this.loadQueue(); // Ensure we load the latest queue // Check if the item already exists in the queue const exists = this.queue.some(existingItem => this.compareFn(existingItem, item)); console.log(this.queue); if (!exists) { this.queue.push(item); this.saveQueue(); // Save the updated queue } else { console.log('Item already exists in the queue. Skipping enqueue.'); } } // Dequeue: Remove an item from the front of the queue dequeue(): T | null { this.loadQueue(); // Ensure we load the latest queue if (this.queue.length === 0) { return null; // Queue is empty } const item = this.queue.shift() as T; // Remove the first item this.saveQueue(); // Save the updated queue return item; } // Peek: Get the item at the front of the queue without removing it peek(): T | null { this.loadQueue(); // Ensure we load the latest queue return this.queue.length > 0 ? this.queue[0] : null; } // Check if the queue is empty isEmpty(): boolean { this.loadQueue(); // Ensure we load the latest queue return this.queue.length === 0; } // Get the length of the queue length(): number { this.loadQueue(); // Ensure we load the latest queue return this.queue.length; } // Clear the entire queue clearQueue(): void { this.acquireLock(); // Acquire the lock try { this.queue = []; // Clear the queue fs.writeFileSync(this.filePath, JSON.stringify(this.queue, null, 2), 'utf8'); } finally { this.releaseLock(); // Release the lock } } }