120 lines
4.0 KiB
TypeScript
120 lines
4.0 KiB
TypeScript
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<void> {
|
|
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<any | null> {
|
|
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<boolean> {
|
|
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<boolean> {
|
|
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<boolean> {
|
|
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
|
|
}
|
|
}
|
|
}
|