import 'dotenv/config'; import { Pool } from 'pg'; import { scrapeAll } from './scraper'; import { syncToDatabase } from './db'; function log(msg: string) { console.log(`[sync] ${new Date().toISOString()} ${msg}`); } function requireEnv(name: string): string { const val = process.env[name]; if (!val) throw new Error(`Missing required environment variable: ${name}`); return val; } /** Returns milliseconds until the next midnight (00:00:00) in local time. */ function msUntilMidnight(): number { const now = new Date(); const midnight = new Date(now); midnight.setDate(now.getDate() + 1); midnight.setHours(0, 0, 0, 0); return midnight.getTime() - now.getTime(); } async function runSync(): Promise { const username = requireEnv('FDISK_USERNAME'); const password = requireEnv('FDISK_PASSWORD'); const pool = new Pool({ host: requireEnv('DB_HOST'), port: parseInt(process.env.DB_PORT ?? '5432'), database: requireEnv('DB_NAME'), user: requireEnv('DB_USER'), password: requireEnv('DB_PASSWORD'), }); try { log('Starting FDISK sync'); const { members, ausbildungen } = await scrapeAll(username, password); await syncToDatabase(pool, members, ausbildungen); log(`Sync complete — ${members.length} members, ${ausbildungen.length} Ausbildungen`); } finally { await pool.end(); } } async function main(): Promise { log('FDISK sync service started'); // 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}`)); // Then schedule at midnight every day while (true) { const delay = msUntilMidnight(); const nextRun = new Date(Date.now() + delay); log(`Next sync scheduled at ${nextRun.toLocaleString()} (in ${Math.round(delay / 60000)} min)`); await new Promise(r => setTimeout(r, delay)); await runSync().catch(err => log(`ERROR during scheduled sync: ${err.message}`)); } } main().catch(err => { console.error(`[sync] Fatal error: ${err.message}`); process.exit(1); });