100 lines
2.9 KiB
JavaScript
100 lines
2.9 KiB
JavaScript
require("dotenv").config({quiet:true});
|
|
|
|
//DB Setup
|
|
const sqlite3 = require('sqlite3').verbose();
|
|
const dbFile = process.env.DB_FILE || 'database.db';
|
|
global.db = new sqlite3.Database(dbFile, (err) => {
|
|
if (err) {
|
|
console.error('Could not connect to database', err);
|
|
process.exit(1); // We simply CANNOT continue without a database
|
|
} else {
|
|
console.log('Connected to database');
|
|
require("./migrations.js")(global.db);
|
|
}
|
|
});
|
|
|
|
|
|
//Express Setup
|
|
const express = require('express');
|
|
const app = express();
|
|
const port = process.env.SERVER_PORT || 3000;
|
|
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
app.use(express.static('public'));
|
|
|
|
//Debugger
|
|
app.use((req, res, next) => {
|
|
if (process.env.DEBUG !== 'true') {
|
|
return next();
|
|
}
|
|
console.log(`${req.method} ${req.url}`);
|
|
console.log('Body:', req.body);
|
|
console.log('Query:', req.query);
|
|
console.log('Params:', req.params);
|
|
console.log('Headers:', req.headers);
|
|
console.log('---');
|
|
next();
|
|
})
|
|
|
|
global.auth = (req, res, next) => {
|
|
if(!process.env.API_KEY) {
|
|
return next(); // No API key set, allow all requests
|
|
}
|
|
if (process.env.API_KEY && req.headers['authorization'] === process.env.API_KEY) {
|
|
return next();
|
|
}
|
|
return res.status(401).json({ error: 'Unauthorized' });
|
|
}
|
|
|
|
// Load routes from routes/* recursively
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
function loadRoutes(dir) {
|
|
fs.readdirSync(dir).forEach(file => {
|
|
const fullPath = path.join(dir, file);
|
|
const stat = fs.statSync(fullPath);
|
|
if (stat.isDirectory()) {
|
|
loadRoutes(fullPath);
|
|
} else if (stat.isFile() && file.endsWith('.js')) {
|
|
const route = require(fullPath);
|
|
// Derive the route path from the file path
|
|
const routePath = '/' + path.relative(path.join(__dirname, 'routes'), fullPath)
|
|
.replace(/\\/g, '/') // Windows compatibility
|
|
.replace('.js', '')
|
|
.replace(/index$/,'');
|
|
app.use(routePath, route);
|
|
console.log(`Loaded route: ${routePath} from ${fullPath}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
loadRoutes(path.join(__dirname, 'routes'));
|
|
|
|
app.listen(port, () => {
|
|
console.log(`Listening on ${port}`);
|
|
// Heartbeat checks
|
|
setInterval(() => {
|
|
const now = Date.now() / 1000;
|
|
global.db.run('SELECT * FROM analytics WHERE heartbeatCheck <= ? AND endTime IS NULL', [now], (err, rows) => {
|
|
if (err) {
|
|
return console.error('Failed to run heartbeat check', err);
|
|
}
|
|
console.log(rows)
|
|
rows.forEach(row => {
|
|
console.log(`Server ${row.id} missed heartbeat check. Marking as inactive.`);
|
|
// Set endTime to last known heartbeatCheck time, shutdownReason "missedHeartbeat"
|
|
global.db.run(
|
|
'UPDATE analytics SET endTime = ?, shutdownReason = ? WHERE id = ?',
|
|
[Math.floor(row.heartbeatCheck), 'missedHeartbeat', row.id],
|
|
(err) => {
|
|
if (err) {
|
|
return console.error(`Failed to mark server ${row.id} as inactive`, err);
|
|
}
|
|
console.log(`Server ${row.id} marked as inactive due to missed heartbeat.`);
|
|
}
|
|
);
|
|
});
|
|
});
|
|
}, 1000);
|
|
}); |