chore: prettier everywhere
This commit is contained in:
@@ -43,8 +43,8 @@ export class BackupUtils {
|
||||
if (process.env.BACKUP_STORAGE_PATH) {
|
||||
return path.resolve(process.cwd(), process.env.BACKUP_STORAGE_PATH);
|
||||
}
|
||||
|
||||
return process.env.NODE_ENV === 'production'
|
||||
|
||||
return process.env.NODE_ENV === 'production'
|
||||
? path.join(process.cwd(), 'data', 'backups')
|
||||
: path.join(process.cwd(), 'backups');
|
||||
}
|
||||
@@ -52,14 +52,17 @@ export class BackupUtils {
|
||||
/**
|
||||
* Crée une sauvegarde SQLite en utilisant la commande .backup
|
||||
*/
|
||||
static async createSQLiteBackup(sourcePath: string, backupPath: string): Promise<void> {
|
||||
static async createSQLiteBackup(
|
||||
sourcePath: string,
|
||||
backupPath: string
|
||||
): Promise<void> {
|
||||
// Vérifier que le fichier source existe
|
||||
try {
|
||||
await fs.stat(sourcePath);
|
||||
} catch {
|
||||
throw new Error(`Source database not found: ${sourcePath}`);
|
||||
}
|
||||
|
||||
|
||||
// Méthode 1: Utiliser sqlite3 CLI (plus fiable)
|
||||
try {
|
||||
const command = `sqlite3 "${sourcePath}" ".backup '${backupPath}'"`;
|
||||
@@ -67,7 +70,10 @@ export class BackupUtils {
|
||||
console.log(`✅ SQLite backup created using CLI: ${backupPath}`);
|
||||
return;
|
||||
} catch (cliError) {
|
||||
console.warn(`⚠️ SQLite CLI backup failed, trying copy method:`, cliError);
|
||||
console.warn(
|
||||
`⚠️ SQLite CLI backup failed, trying copy method:`,
|
||||
cliError
|
||||
);
|
||||
}
|
||||
|
||||
// Méthode 2: Copie simple du fichier (fallback)
|
||||
@@ -84,7 +90,7 @@ export class BackupUtils {
|
||||
*/
|
||||
static async compressFile(filePath: string): Promise<string> {
|
||||
const compressedPath = `${filePath}.gz`;
|
||||
|
||||
|
||||
try {
|
||||
const command = `gzip -c "${filePath}" > "${compressedPath}"`;
|
||||
await execAsync(command);
|
||||
@@ -99,7 +105,10 @@ export class BackupUtils {
|
||||
/**
|
||||
* Décompresse un fichier gzip temporairement
|
||||
*/
|
||||
static async decompressFileTemp(compressedPath: string, tempPath: string): Promise<void> {
|
||||
static async decompressFileTemp(
|
||||
compressedPath: string,
|
||||
tempPath: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
await execAsync(`gunzip -c "${compressedPath}" > "${tempPath}"`);
|
||||
} catch (error) {
|
||||
@@ -114,12 +123,12 @@ export class BackupUtils {
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
let size = bytes;
|
||||
let unitIndex = 0;
|
||||
|
||||
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
|
||||
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
@@ -138,31 +147,40 @@ export class BackupUtils {
|
||||
/**
|
||||
* Parse le nom de fichier de backup pour extraire les métadonnées
|
||||
*/
|
||||
static parseBackupFilename(filename: string): { type: 'manual' | 'automatic'; date: Date | null } {
|
||||
static parseBackupFilename(filename: string): {
|
||||
type: 'manual' | 'automatic';
|
||||
date: Date | null;
|
||||
} {
|
||||
// Nouveau format: towercontrol_manual_2025-09-18T14-12-05-737Z.db
|
||||
// Ancien format: towercontrol_2025-09-18T14-12-05-737Z.db (considéré comme automatic)
|
||||
let type: 'manual' | 'automatic' = 'automatic';
|
||||
let dateMatch = filename.match(/towercontrol_(manual|automatic)_(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)/);
|
||||
|
||||
let dateMatch = filename.match(
|
||||
/towercontrol_(manual|automatic)_(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)/
|
||||
);
|
||||
|
||||
if (!dateMatch) {
|
||||
// Format ancien sans type - considérer comme automatic
|
||||
dateMatch = filename.match(/towercontrol_(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)/);
|
||||
dateMatch = filename.match(
|
||||
/towercontrol_(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)/
|
||||
);
|
||||
if (dateMatch) {
|
||||
dateMatch = [dateMatch[0], 'automatic', dateMatch[1]]; // Restructurer pour compatibilité
|
||||
}
|
||||
} else {
|
||||
type = dateMatch[1] as 'manual' | 'automatic';
|
||||
}
|
||||
|
||||
|
||||
let date: Date | null = null;
|
||||
if (dateMatch && dateMatch[2]) {
|
||||
// Convertir le format de fichier vers ISO string valide
|
||||
// Format: 2025-09-18T14-12-05-737Z -> 2025-09-18T14:12:05.737Z
|
||||
const isoString = dateMatch[2]
|
||||
.replace(/T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z/, 'T$1:$2:$3.$4Z');
|
||||
const isoString = dateMatch[2].replace(
|
||||
/T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z/,
|
||||
'T$1:$2:$3.$4Z'
|
||||
);
|
||||
date = parseDate(isoString);
|
||||
}
|
||||
|
||||
|
||||
return { type, date };
|
||||
}
|
||||
|
||||
@@ -178,17 +196,17 @@ export class BackupUtils {
|
||||
* Écrit une entrée dans le fichier de log
|
||||
*/
|
||||
static async writeLogEntry(
|
||||
logPath: string,
|
||||
type: 'manual' | 'automatic',
|
||||
action: 'created' | 'skipped' | 'failed',
|
||||
details: string,
|
||||
logPath: string,
|
||||
type: 'manual' | 'automatic',
|
||||
action: 'created' | 'skipped' | 'failed',
|
||||
details: string,
|
||||
extra?: { hash?: string; size?: number; previousHash?: string }
|
||||
): Promise<void> {
|
||||
try {
|
||||
const date = formatDateForDisplay(getToday(), 'DISPLAY_LONG');
|
||||
|
||||
|
||||
let logEntry = `[${date}] ${type.toUpperCase()} BACKUP ${action.toUpperCase()}: ${details}`;
|
||||
|
||||
|
||||
if (extra) {
|
||||
if (extra.hash) {
|
||||
logEntry += ` | Hash: ${extra.hash.substring(0, 12)}...`;
|
||||
@@ -200,9 +218,9 @@ export class BackupUtils {
|
||||
logEntry += ` | Previous: ${extra.previousHash.substring(0, 12)}...`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logEntry += '\n';
|
||||
|
||||
|
||||
await fs.appendFile(logPath, logEntry);
|
||||
} catch (error) {
|
||||
console.error('Error writing to backup log:', error);
|
||||
|
||||
Reference in New Issue
Block a user