const express = require('express'); const bodyParser = require('body-parser'); const sqlite3 = require('sqlite3').verbose(); const fs = require('fs'); const path = require('path'); const cron = require('node-cron'); const app = express(); const port = 3001; // Serve static files from the current directory app.use(express.static(__dirname)); app.use(bodyParser.json()); // Add CORS middleware app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); next(); }); // Create backups directory if it doesn't exist const backupDir = path.join(__dirname, 'backups'); if (!fs.existsSync(backupDir)) { fs.mkdirSync(backupDir, { recursive: true }); } // Database setup const db = new sqlite3.Database('./rechner.db', (err) => { if (err) { console.error('Error opening database:', err.message); } else { console.log('Connected to the SQLite database.'); // Create tables if they don't exist db.run(`CREATE TABLE IF NOT EXISTS coin_trackers ( id TEXT PRIMARY KEY, data TEXT NOT NULL, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )`); } }); // API route to save coin trackers app.post('/api/coinTrackers', (req, res) => { const data = req.body.data; if (!data) { return res.status(400).json({ error: 'No data provided' }); } // Save data to database db.run('DELETE FROM coin_trackers', [], function(err) { if (err) { return res.status(500).json({ error: err.message }); } const stmt = db.prepare('INSERT INTO coin_trackers (id, data) VALUES (?, ?)'); data.forEach(tracker => { stmt.run(tracker.id, JSON.stringify(tracker)); }); stmt.finalize(); res.json({ success: true, message: 'Data saved successfully' }); }); }); // API route to get coin trackers app.get('/api/coinTrackers', (req, res) => { db.all('SELECT id, data FROM coin_trackers', [], (err, rows) => { if (err) { return res.status(500).json({ error: err.message }); } const data = rows.map(row => JSON.parse(row.data)); res.json({ data }); }); }); // API route to create a backup app.get('/api/backup/create', (req, res) => { const name = req.query.name || `Backup_${new Date().toISOString()}`; const timestamp = Date.now(); const fileName = `backup_${timestamp}_name_${name}.json`; const filePath = path.join(backupDir, fileName); // Get all data from database db.all('SELECT id, data FROM coin_trackers', [], (err, rows) => { if (err) { return res.status(500).json({ error: err.message }); } const data = rows.map(row => JSON.parse(row.data)); const backupData = { date: new Date().toISOString(), name: name, data: data }; // Write backup file fs.writeFile(filePath, JSON.stringify(backupData, null, 2), (err) => { if (err) { return res.status(500).json({ error: err.message }); } res.json({ success: true, message: 'Backup created successfully', file: fileName }); }); }); }); // API route to list backups app.get('/api/backup/list', (req, res) => { fs.readdir(backupDir, (err, files) => { if (err) { return res.status(500).json({ error: err.message }); } const backups = []; // Process each file synchronously for (const file of files) { if (!file.startsWith('backup_') || !file.endsWith('.json')) continue; const filePath = path.join(backupDir, file); const stats = fs.statSync(filePath); let name = file; if (file.includes('_name_')) { name = file.split('_name_')[1].split('.json')[0]; } const timestamp = file.split('_')[1]; backups.push({ file: file, date: new Date(parseInt(timestamp)).toISOString(), size: stats.size, name: name }); } res.json({ backups }); }); }); // API route to restore from a backup app.get('/api/backup/restore/:file', (req, res) => { const fileName = req.params.file; const filePath = path.join(backupDir, fileName); if (!fs.existsSync(filePath)) { return res.status(404).json({ error: 'Backup file not found' }); } fs.readFile(filePath, 'utf8', (err, data) => { if (err) { return res.status(500).json({ error: err.message }); } try { const backupData = JSON.parse(data); // Clear existing data db.run('DELETE FROM coin_trackers', [], function(err) { if (err) { return res.status(500).json({ error: err.message }); } // Insert backup data if (backupData.data && Array.isArray(backupData.data)) { const stmt = db.prepare('INSERT INTO coin_trackers (id, data) VALUES (?, ?)'); backupData.data.forEach(tracker => { stmt.run(tracker.id, JSON.stringify(tracker)); }); stmt.finalize(); } res.json({ success: true, message: 'Backup restored successfully' }); }); } catch (e) { res.status(500).json({ error: 'Invalid backup file format' }); } }); }); // Add a status endpoint for testing app.get('/api/status', (req, res) => { res.json({ status: 'ok', version: '1.0', timestamp: new Date().toISOString() }); }); // Start the server app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); // Schedule automatic backups daily at midnight cron.schedule('0 0 * * *', () => { console.log('Creating automatic daily backup'); const name = `Auto_${new Date().toLocaleDateString()}`; const timestamp = Date.now(); const fileName = `backup_${timestamp}_name_${name}.json`; const filePath = path.join(backupDir, fileName); db.all('SELECT id, data FROM coin_trackers', [], (err, rows) => { if (err) { console.error('Auto backup error:', err); return; } const data = rows.map(row => JSON.parse(row.data)); const backupData = { date: new Date().toISOString(), name: name, data: data }; fs.writeFile(filePath, JSON.stringify(backupData, null, 2), (err) => { if (err) { console.error('Error writing auto backup:', err); return; } console.log('Automatic backup created successfully'); }); }); });