const BaseService = require('./BaseService'); const cron = require('node-cron'); const fs = require('fs').promises; const path = require('path'); class FileCleanupService extends BaseService { constructor(config = {}) { super('fileCleanup', { fileInfoPath: config.fileInfoPath || path.join(process.cwd(), 'data', 'file_info.json'), cronSchedule: config.cronSchedule || '0 * * * *', ...config }); this.job = null; } async _startImplementation() { if (this.job) { return; } // Valider le cron schedule if (!cron.validate(this.config.cronSchedule)) { throw new Error(`Schedule cron invalide: ${this.config.cronSchedule}`); } this.job = cron.schedule(this.config.cronSchedule, () => this.cleanup()); } async _stopImplementation() { if (this.job) { this.job.stop(); this.job = null; } } // Réutiliser vos méthodes existantes async fileExists(filepath) { try { await fs.access(filepath); return true; } catch { return false; } } normalizePath(filepath) { return path.normalize(filepath).replace(/\\/g, '/'); } async readFileInfo() { try { const data = await fs.readFile(this.config.fileInfoPath, 'utf8'); return JSON.parse(data); } catch (err) { this.logger.error('Erreur lors de la lecture du fichier info:', err); return []; } } async saveFileInfo(fileInfo) { try { await fs.writeFile( this.config.fileInfoPath, JSON.stringify(fileInfo, null, 2), 'utf8' ); return true; } catch (err) { this.logger.error('Erreur lors de la sauvegarde du fichier info:', err); return false; } } async processFile(file, now) { const normalizedPath = this.normalizePath(file.path); if (file.expiryDate && new Date(file.expiryDate) <= now) { return { status: 'expired', file: { ...file, path: normalizedPath } }; } if (!(await this.fileExists(normalizedPath))) { return { status: 'missing', file: { ...file, path: normalizedPath } }; } return { status: 'valid', file }; } async cleanup() { try { const fileInfo = await this.readFileInfo(); const now = new Date(); const results = { expired: [], missing: [], processed: 0, remaining: 0 }; const validFiles = []; await Promise.all(fileInfo.map(async (file) => { const { status, file: processedFile } = await this.processFile(file, now); if (status === 'expired') { results.expired.push(processedFile); results.processed++; } else if (status === 'missing') { results.missing.push(processedFile); results.processed++; } else { validFiles.push(file); } })); if (results.processed > 0) { results.remaining = validFiles.length; await this.saveFileInfo(validFiles); this.logger.info('Nettoyage des fichiers terminé', { expired: results.expired.length, missing: results.missing.length, totalProcessed: results.processed, remainingFiles: results.remaining }); } return results; } catch (err) { this.logger.error('Erreur lors du nettoyage des fichiers:', { error: err.message, stack: err.stack }); throw err; } } async forceCleanup() { return this.cleanup(); } } module.exports = new FileCleanupService();