update FDISK sync

This commit is contained in:
Matthias Hochmeister
2026-03-13 10:27:57 +01:00
parent 501b697ca2
commit 11fb533ad6
6 changed files with 273 additions and 1 deletions

View File

@@ -1,12 +1,36 @@
import 'dotenv/config';
import * as http from 'http';
import { Pool } from 'pg';
import { scrapeAll } from './scraper';
import { syncToDatabase } from './db';
// In-memory log ring buffer — last 500 lines captured from all modules
const LOG_BUFFER_MAX = 500;
const logBuffer: Array<{ ts: string; line: string }> = [];
const _origLog = console.log;
const _origErr = console.error;
function captureToBuffer(line: string) {
logBuffer.push({ ts: new Date().toISOString(), line });
if (logBuffer.length > LOG_BUFFER_MAX) logBuffer.shift();
}
console.log = (...args: unknown[]) => {
const line = args.map(String).join(' ');
_origLog(line);
captureToBuffer(line);
};
console.error = (...args: unknown[]) => {
const line = args.map(String).join(' ');
_origErr(line);
captureToBuffer(line);
};
function log(msg: string) {
console.log(`[sync] ${new Date().toISOString()} ${msg}`);
}
let syncRunning = false;
function requireEnv(name: string): string {
const val = process.env[name];
if (!val) throw new Error(`Missing required environment variable: ${name}`);
@@ -23,6 +47,11 @@ function msUntilMidnight(): number {
}
async function runSync(): Promise<void> {
if (syncRunning) {
log('Sync already in progress, skipping');
return;
}
syncRunning = true;
const username = requireEnv('FDISK_USERNAME');
const password = requireEnv('FDISK_PASSWORD');
@@ -40,13 +69,41 @@ async function runSync(): Promise<void> {
await syncToDatabase(pool, members, ausbildungen);
log(`Sync complete — ${members.length} members, ${ausbildungen.length} Ausbildungen`);
} finally {
syncRunning = false;
await pool.end();
}
}
function startHttpServer(port: number) {
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json');
if (req.method === 'GET' && req.url === '/logs') {
res.writeHead(200);
res.end(JSON.stringify({ running: syncRunning, logs: logBuffer }));
} else if (req.method === 'POST' && req.url === '/trigger') {
if (syncRunning) {
res.writeHead(409);
res.end(JSON.stringify({ running: true, message: 'Sync already in progress' }));
return;
}
res.writeHead(200);
res.end(JSON.stringify({ started: true }));
runSync().catch(err => log(`ERROR during manual sync: ${err.message}`));
} else {
res.writeHead(404);
res.end(JSON.stringify({ message: 'Not found' }));
}
});
server.listen(port, () => log(`HTTP control server listening on port ${port}`));
}
async function main(): Promise<void> {
log('FDISK sync service started');
const httpPort = parseInt(process.env.SYNC_HTTP_PORT ?? '3001', 10);
startHttpServer(httpPort);
// Run once immediately on startup so the first sync doesn't wait until midnight
await runSync().catch(err => log(`ERROR during initial sync: ${err.message}`));