import fs from 'fs'; import path from 'path'; export class JsonManager { private readonly filePath: string; private readonly lockFilePath: string; constructor(filePath: string) { 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}`); } this.filePath = filePath; this.lockFilePath = `${filePath}.lock`; // Define the lock file path // 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 async acquireLock(): Promise { while (fs.existsSync(this.lockFilePath)) { // Wait until the lock file is released await new Promise(resolve => setTimeout(resolve, 100)); // 100ms delay before retrying } // Create the lock file fs.writeFileSync(this.lockFilePath, ''); } // Method to release the lock (delete .lock file) private releaseLock(): void { if (fs.existsSync(this.lockFilePath)) { fs.unlinkSync(this.lockFilePath); } } // Read a value by key from the JSON file with a lock public async readValue(key: string): Promise { await this.acquireLock(); // Acquire the lock try { if (!fs.existsSync(this.filePath)) return null; const data = JSON.parse(fs.readFileSync(this.filePath, 'utf8')); return data[key] !== undefined ? data[key] : null; } catch (err: any) { console.error(`Error reading from JSON file: ${err.message}`); return null; } finally { this.releaseLock(); // Always release the lock after the operation } } // Write a key-value pair to the JSON file with a lock public async writeValue(key: string, value: any): Promise { await this.acquireLock(); // Acquire the lock try { let data: { [key: string]: any } = {}; if (fs.existsSync(this.filePath)) { data = JSON.parse(fs.readFileSync(this.filePath, 'utf8')); } // Update the key with the new value data[key] = value; fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf8'); return true; } catch (err: any) { console.error(`Error writing to JSON file: ${err.message}`); return false; } finally { this.releaseLock(); // Always release the lock after the operation } } // Remove a key-value pair from the JSON file with a lock public async removeValue(key: string): Promise { await this.acquireLock(); // Acquire the lock try { if (!fs.existsSync(this.filePath)) return false; const data = JSON.parse(fs.readFileSync(this.filePath, 'utf8')); if (data[key] !== undefined) { delete data[key]; fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf8'); return true; } return false; } catch (err: any) { console.error(`Error removing key from JSON file: ${err.message}`); return false; } finally { this.releaseLock(); // Always release the lock after the operation } } // Reset the JSON file by clearing all data with a lock public async resetFile(): Promise { await this.acquireLock(); // Acquire the lock try { fs.writeFileSync(this.filePath, JSON.stringify({}, null, 2), 'utf8'); return true; } catch (err: any) { console.error(`Error resetting JSON file: ${err.message}`); return false; } finally { this.releaseLock(); // Always release the lock after the operation } } }