diff --git a/Dockerfile b/Dockerfile index 01f3fb6..4b8e978 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN apk add --no-cache python3 make g++ cairo-dev pango-dev libjpeg-turbo-dev gi COPY src/ ./src/ # Crée les répertoires pour les volumes -RUN mkdir -p /app/config +RUN mkdir -p /app/config /app/data/pdfs # Crée le fichier projects.json COPY config/projects.json.example /app/config/projects.json diff --git a/docker-compose.yml b/docker-compose.yml index c41861b..501dfea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,7 @@ services: # Volumes pour la configuration volumes: - ./config/projects.json:/app/config/projects.json:ro # Fichier projects.json en lecture seule + - pdf-data:/app/data/pdfs # # Réseau networks: diff --git a/src/commands/handlers/PdfHandler.js b/src/commands/handlers/PdfHandler.js index 9f2b819..c3dfea7 100644 --- a/src/commands/handlers/PdfHandler.js +++ b/src/commands/handlers/PdfHandler.js @@ -13,8 +13,12 @@ const logger = require('../../utils/logger'); */ class PdfHandler { constructor() { + this.storageDir = process.env.PDF_STORAGE_DIR || path.join(process.cwd(), 'data', 'pdfs'); + this.sessionFile = path.join(this.storageDir, 'sessions.json'); this.sessions = new Map(); // messageId -> { pdfPath, totalPages, ownerId, createdAt, downloadUrl, isPublic } pdfjsLib.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.min.js'); + this.ensureStorageDir(); + this.loadSessions(); } /** @@ -76,6 +80,7 @@ class PdfHandler { downloadUrl: sourceUrl, isPublic }); + this.saveSessions(); logger.info(`PDF affiché (${totalPages} pages) par ${interaction.user.tag}`); @@ -135,9 +140,10 @@ class PdfHandler { */ async downloadPdf(url) { const response = await axios.get(url, { responseType: 'arraybuffer' }); - const tmpPath = path.join(os.tmpdir(), `pdf-${Date.now()}-${Math.random().toString(36).slice(2)}.pdf`); - fs.writeFileSync(tmpPath, response.data); - return tmpPath; + const fileName = `pdf-${Date.now()}-${Math.random().toString(36).slice(2)}.pdf`; + const targetPath = path.join(this.storageDir, fileName); + fs.writeFileSync(targetPath, response.data); + return targetPath; } /** @@ -222,6 +228,47 @@ class PdfHandler { return 'Visualisation PDF'; } } + + /** + * Persistance des sessions pour survivre aux redémarrages + */ + ensureStorageDir() { + fs.mkdirSync(this.storageDir, { recursive: true }); + } + + loadSessions() { + try { + if (!fs.existsSync(this.sessionFile)) return; + const raw = fs.readFileSync(this.sessionFile, 'utf8'); + const data = JSON.parse(raw); + data.forEach(entry => { + if (entry.pdfPath && fs.existsSync(entry.pdfPath)) { + this.sessions.set(entry.messageId, { + pdfPath: entry.pdfPath, + totalPages: entry.totalPages, + ownerId: entry.ownerId, + createdAt: entry.createdAt, + downloadUrl: entry.downloadUrl, + isPublic: entry.isPublic + }); + } + }); + } catch (e) { + logger.error('Erreur lors du chargement des sessions PDF persistées:', e); + } + } + + saveSessions() { + try { + const data = []; + for (const [messageId, session] of this.sessions.entries()) { + data.push({ messageId, ...session }); + } + fs.writeFileSync(this.sessionFile, JSON.stringify(data, null, 2), 'utf8'); + } catch (e) { + logger.error('Erreur lors de la sauvegarde des sessions PDF:', e); + } + } } module.exports = PdfHandler;