2026-02-08 03:03:53 -05:00
|
|
|
const sqlite3 = require('sqlite3');
|
|
|
|
|
const { open } = require('sqlite');
|
2026-02-09 01:01:12 -05:00
|
|
|
// Node 18+ has global fetch built-in
|
2026-02-08 03:03:53 -05:00
|
|
|
|
|
|
|
|
const SERVICES = [
|
2026-02-09 01:48:53 -05:00
|
|
|
{ name: 'Website', url: 'https://akkolli.net' },
|
2026-02-08 03:03:53 -05:00
|
|
|
{ name: 'Gitea', url: 'https://code.akkolli.net' },
|
2026-02-09 00:50:40 -05:00
|
|
|
{ name: 'Nextcloud', url: 'http://host.docker.internal:6060' },
|
2026-02-08 03:03:53 -05:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
async function monitor() {
|
|
|
|
|
console.log('Starting monitoring loop...');
|
|
|
|
|
|
2026-02-08 03:20:36 -05:00
|
|
|
const dbPath = process.env.DB_PATH || './dashboard.db';
|
|
|
|
|
|
2026-02-08 03:03:53 -05:00
|
|
|
const db = await open({
|
2026-02-08 03:20:36 -05:00
|
|
|
filename: dbPath,
|
2026-02-08 03:03:53 -05:00
|
|
|
driver: sqlite3.Database
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Ensure table exists (in case monitor runs before app)
|
|
|
|
|
await db.exec(`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS uptime_logs (
|
|
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
|
service_name TEXT NOT NULL,
|
|
|
|
|
url TEXT NOT NULL,
|
|
|
|
|
status TEXT NOT NULL,
|
|
|
|
|
latency INTEGER,
|
|
|
|
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
);
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
setInterval(async () => {
|
|
|
|
|
console.log('Running checks...');
|
|
|
|
|
const now = new Date().toISOString();
|
|
|
|
|
|
|
|
|
|
for (const service of SERVICES) {
|
|
|
|
|
const start = performance.now();
|
|
|
|
|
let status = 'down';
|
|
|
|
|
let latency = 0;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const controller = new AbortController();
|
|
|
|
|
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
|
|
|
|
|
|
|
|
const res = await fetch(service.url, {
|
|
|
|
|
method: 'HEAD',
|
|
|
|
|
signal: controller.signal
|
|
|
|
|
});
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
2026-02-09 01:48:53 -05:00
|
|
|
// Any HTTP response means the service is reachable (up).
|
|
|
|
|
// Only network errors/timeouts (caught below) count as down.
|
|
|
|
|
status = res.status < 500 ? 'up' : 'down';
|
2026-02-08 03:03:53 -05:00
|
|
|
const end = performance.now();
|
|
|
|
|
latency = Math.round(end - start);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
status = 'down';
|
|
|
|
|
latency = 0;
|
|
|
|
|
// console.error(`Failed to reach ${service.name}:`, err.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await db.run(
|
|
|
|
|
`INSERT INTO uptime_logs (service_name, url, status, latency, timestamp) VALUES (?, ?, ?, ?, ?)`,
|
|
|
|
|
service.name, service.url, status, latency, now
|
|
|
|
|
);
|
|
|
|
|
} catch (dbErr) {
|
|
|
|
|
console.error('DB Write Error:', dbErr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prune old logs (keep 7 days)
|
|
|
|
|
try {
|
|
|
|
|
await db.run(`DELETE FROM uptime_logs WHERE timestamp < datetime('now', '-7 days')`);
|
|
|
|
|
} catch (e) { }
|
|
|
|
|
|
|
|
|
|
}, 60000); // Run every minute
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
monitor();
|