mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 14:21:46 +00:00
Initial commit — NOMAD (Navigation Organizer for Maps, Activities & Destinations)
Self-hosted travel planner with Express.js, SQLite, React & Tailwind CSS.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
const cron = require('node-cron');
|
||||
const archiver = require('archiver');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const dataDir = path.join(__dirname, '../data');
|
||||
const backupsDir = path.join(dataDir, 'backups');
|
||||
const uploadsDir = path.join(__dirname, '../uploads');
|
||||
const settingsFile = path.join(dataDir, 'backup-settings.json');
|
||||
|
||||
const CRON_EXPRESSIONS = {
|
||||
hourly: '0 * * * *',
|
||||
daily: '0 2 * * *',
|
||||
weekly: '0 2 * * 0',
|
||||
monthly: '0 2 1 * *',
|
||||
};
|
||||
|
||||
const VALID_INTERVALS = Object.keys(CRON_EXPRESSIONS);
|
||||
|
||||
let currentTask = null;
|
||||
|
||||
function loadSettings() {
|
||||
try {
|
||||
if (fs.existsSync(settingsFile)) {
|
||||
return JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
|
||||
}
|
||||
} catch (e) {}
|
||||
return { enabled: false, interval: 'daily', keep_days: 7 };
|
||||
}
|
||||
|
||||
function saveSettings(settings) {
|
||||
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
|
||||
fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
|
||||
}
|
||||
|
||||
async function runBackup() {
|
||||
if (!fs.existsSync(backupsDir)) fs.mkdirSync(backupsDir, { recursive: true });
|
||||
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
const filename = `auto-backup-${timestamp}.zip`;
|
||||
const outputPath = path.join(backupsDir, filename);
|
||||
|
||||
try {
|
||||
// Flush WAL to main DB file before archiving
|
||||
try { const { db } = require('./db/database'); db.exec('PRAGMA wal_checkpoint(TRUNCATE)'); } catch (e) {}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const output = fs.createWriteStream(outputPath);
|
||||
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||
output.on('close', resolve);
|
||||
archive.on('error', reject);
|
||||
archive.pipe(output);
|
||||
const dbPath = path.join(dataDir, 'travel.db');
|
||||
if (fs.existsSync(dbPath)) archive.file(dbPath, { name: 'travel.db' });
|
||||
if (fs.existsSync(uploadsDir)) archive.directory(uploadsDir, 'uploads');
|
||||
archive.finalize();
|
||||
});
|
||||
console.log(`[Auto-Backup] Erstellt: ${filename}`);
|
||||
} catch (err) {
|
||||
console.error('[Auto-Backup] Fehler:', err.message);
|
||||
if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = loadSettings();
|
||||
if (settings.keep_days > 0) {
|
||||
cleanupOldBackups(settings.keep_days);
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupOldBackups(keepDays) {
|
||||
try {
|
||||
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1000;
|
||||
const files = fs.readdirSync(backupsDir).filter(f => f.endsWith('.zip'));
|
||||
for (const file of files) {
|
||||
const filePath = path.join(backupsDir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
if (stat.birthtimeMs < cutoff) {
|
||||
fs.unlinkSync(filePath);
|
||||
console.log(`[Auto-Backup] Altes Backup gelöscht: ${file}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Auto-Backup] Bereinigungsfehler:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (currentTask) {
|
||||
currentTask.stop();
|
||||
currentTask = null;
|
||||
}
|
||||
|
||||
const settings = loadSettings();
|
||||
if (!settings.enabled) {
|
||||
console.log('[Auto-Backup] Deaktiviert');
|
||||
return;
|
||||
}
|
||||
|
||||
const expression = CRON_EXPRESSIONS[settings.interval] || CRON_EXPRESSIONS.daily;
|
||||
currentTask = cron.schedule(expression, runBackup);
|
||||
console.log(`[Auto-Backup] Geplant: ${settings.interval} (${expression}), Aufbewahrung: ${settings.keep_days === 0 ? 'immer' : settings.keep_days + ' Tage'}`);
|
||||
}
|
||||
|
||||
module.exports = { start, loadSettings, saveSettings, VALID_INTERVALS };
|
||||
Reference in New Issue
Block a user