diff --git a/server.js b/server.js index 620ebda..c611fd8 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,8 @@ const path = require('path'); const ROOT = __dirname; const DATA_FILE = path.join(ROOT, 'data.json'); +const BACKUP_DIR = process.env.BPI_BACKUP_DIR || path.join(ROOT, 'backups'); +const MAX_BACKUPS = Number(process.env.BPI_MAX_BACKUPS) || 100; const PORT = Number(process.env.PORT) || 8080; const TYPES = { @@ -34,6 +36,34 @@ function readBody(req) { }); } +function timestamp() { + return new Date().toISOString().replace(/[:.]/g, '-'); +} + +function backupDataFile() { + if (!fs.existsSync(DATA_FILE)) return null; + + fs.mkdirSync(BACKUP_DIR, { recursive: true }); + const backupFile = path.join(BACKUP_DIR, `data-${timestamp()}.json`); + fs.copyFileSync(DATA_FILE, backupFile); + + const backups = fs + .readdirSync(BACKUP_DIR) + .filter((name) => /^data-.*\.json$/.test(name)) + .map((name) => ({ + name, + file: path.join(BACKUP_DIR, name), + mtime: fs.statSync(path.join(BACKUP_DIR, name)).mtimeMs, + })) + .sort((a, b) => b.mtime - a.mtime); + + for (const oldBackup of backups.slice(MAX_BACKUPS)) { + fs.rmSync(oldBackup.file, { force: true }); + } + + return backupFile; +} + const server = http.createServer(async (req, res) => { try { const url = new URL(req.url, `http://${req.headers.host}`); @@ -46,8 +76,9 @@ const server = http.createServer(async (req, res) => { return send(res, 400, JSON.stringify({ error: 'Invalid data format' }), 'application/json; charset=utf-8'); } + const backupFile = backupDataFile(); fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2) + '\n'); - return send(res, 200, JSON.stringify({ ok: true }), 'application/json; charset=utf-8'); + return send(res, 200, JSON.stringify({ ok: true, backup: backupFile ? path.basename(backupFile) : null }), 'application/json; charset=utf-8'); } if (req.method !== 'GET' && req.method !== 'HEAD') {