import { syncService } from './syncService' import { db } from '../config/database' import { logger } from '../utils/logger' interface SyncInterval { value: string milliseconds: number } const SYNC_INTERVALS: Record = { '5min': { value: '5min', milliseconds: 5 * 60 * 1000 }, '15min': { value: '15min', milliseconds: 15 * 60 * 1000 }, '30min': { value: '30min', milliseconds: 30 * 60 * 1000 }, '1hour': { value: '1hour', milliseconds: 60 * 60 * 1000 }, 'daily': { value: 'daily', milliseconds: 24 * 60 * 60 * 1000 } } export class SyncScheduler { private static instance: SyncScheduler private intervalId: NodeJS.Timeout | null = null private currentInterval: string = 'disabled' private constructor() { this.initialize() } static getInstance(): SyncScheduler { if (!SyncScheduler.instance) { SyncScheduler.instance = new SyncScheduler() } return SyncScheduler.instance } private initialize() { // Check current sync settings on startup this.checkAndUpdateInterval() // Check for interval changes every minute setInterval(() => { this.checkAndUpdateInterval() }, 60000) } private checkAndUpdateInterval() { try { const settings = db.prepare('SELECT auto_sync_interval FROM sync_settings WHERE id = ?').get('default') as any const newInterval = settings?.auto_sync_interval || 'disabled' if (newInterval !== this.currentInterval) { logger.info(`Sync interval changed from ${this.currentInterval} to ${newInterval}`) this.currentInterval = newInterval this.updateSchedule() } } catch (error) { logger.error('Failed to check sync interval:', error) } } private updateSchedule() { // Clear existing interval if (this.intervalId) { clearInterval(this.intervalId) this.intervalId = null } // Set new interval if not disabled if (this.currentInterval !== 'disabled' && SYNC_INTERVALS[this.currentInterval]) { const { milliseconds } = SYNC_INTERVALS[this.currentInterval] logger.info(`Starting automatic sync with interval: ${this.currentInterval}`) // Run sync immediately this.runSync() // Then schedule regular syncs this.intervalId = setInterval(() => { this.runSync() }, milliseconds) } else { logger.info('Automatic sync disabled') } } private async runSync() { try { logger.info('Running scheduled sync...') // Check if we're the admin node const nodeType = process.env.NODE_TYPE || 'local' if (nodeType === 'admin') { // Admin pushes to all local nodes await syncService.triggerSync() } else { // Local nodes sync with admin const adminNode = db.prepare(` SELECT id FROM network_nodes WHERE type = 'admin' AND is_online = 1 LIMIT 1 `).get() as any if (adminNode) { await syncService.syncWithNode(adminNode.id) } else { logger.warn('No admin node available for sync') } } logger.info('Scheduled sync completed') } catch (error) { logger.error('Scheduled sync failed:', error) } } // Manual trigger for testing async triggerManualSync() { await this.runSync() } // Get current status getStatus() { return { enabled: this.currentInterval !== 'disabled', interval: this.currentInterval, nextRun: this.intervalId ? new Date(Date.now() + (SYNC_INTERVALS[this.currentInterval]?.milliseconds || 0)) : null } } } export const syncScheduler = SyncScheduler.getInstance()