'use strict'; const db = require('../db/knex'); const { broadcastPhotoEvent, broadcastActivityEvent, } = require('../ws-server'); const { ensureServerEventOutbox, getNextPendingServerEvent, completeServerEvent, failServerEvent, } = require('../db/serverEventOutbox'); function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function dispatchEvent(event) { let payload; try { payload = JSON.parse(event.payload); } catch (err) { throw new Error( `Payload JSON non valido per evento ${event.id}: ${err.message}` ); } switch (event.channel) { case 'photo': await broadcastPhotoEvent(event.user, payload); return; case 'activity': await broadcastActivityEvent(event.user, payload); return; default: throw new Error( `Canale outbox sconosciuto: ${event.channel}` ); } } function startWsOutboxConsumer(options = {}) { const pollMs = Math.max( 100, Number(options.pollMs) || 250 ); let stopping = false; async function loop() { await ensureServerEventOutbox(db); console.log( `[WsOutboxConsumer] avviato; polling ${pollMs} ms` ); while (!stopping) { try { const event = await getNextPendingServerEvent(db); if (!event) { await sleep(pollMs); continue; } try { await dispatchEvent(event); await completeServerEvent(db, event.id); console.log( `[WsOutboxConsumer] evento ${event.id} inviato ` + `channel=${event.channel} user=${event.user}` ); } catch (err) { await failServerEvent( db, event.id, err.message ); console.error( `[WsOutboxConsumer] evento ${event.id} fallito:`, err.message ); // Evita un busy-loop continuo su un evento non valido. await sleep(pollMs); } } catch (err) { console.error( '[WsOutboxConsumer] errore ciclo:', err ); await sleep(pollMs); } } } loop().catch((err) => { console.error( '[WsOutboxConsumer] errore fatale:', err ); }); return () => { stopping = true; }; } module.exports = { startWsOutboxConsumer, };