const express = require('express'); const { requireAuth, requireAdmin } = require('../auth'); const liveProjection = require('../services/liveProjectionService'); const router = express.Router(); function serializeState(state) { return { status: state.status, stale: state.status !== 'success', startedAt: state.started_at, completedAt: state.completed_at, inputHash: state.input_hash, projectedCount: state.projected_count, processed: state.processed_count, total: state.total_count, error: state.error }; } router.get('/channels', requireAuth, async (req, res) => { const sourceId = req.query.sourceId === undefined ? null : Number(req.query.sourceId); if (sourceId !== null && (!Number.isInteger(sourceId) || sourceId <= 0)) { return res.status(400).json({ error: 'sourceId must be a positive integer' }); } if (req.query.includeHidden !== undefined && !['true', 'false'].includes(req.query.includeHidden)) { return res.status(400).json({ error: 'includeHidden must be true or false' }); } const includeHidden = req.query.includeHidden === 'true'; try { let state = liveProjection.projectionState(); if (state.status !== 'success' && state.status !== 'building') { state = await liveProjection.startRebuild().promise; } const channels = liveProjection.getChannels({ sourceId, includeHidden, userId: req.user.id }); return res.json({ projection: serializeState(state), channels }); } catch (error) { console.error('[LiveProjection] Failed to serve projected channels:', error.message); const state = liveProjection.projectionState(); return res.status(503).json({ projection: serializeState(state), channels: [], error: 'Live channel projection is unavailable' }); } }); router.get('/projection/status', requireAuth, (req, res) => { try { return res.json(serializeState(liveProjection.projectionState())); } catch (error) { return res.status(500).json({ error: 'Unable to read Live projection status' }); } }); router.post('/projection/rebuild', requireAuth, requireAdmin, (req, res) => { try { const started = liveProjection.startRebuild(); started.promise.catch(error => { console.error('[LiveProjection] Manual rebuild failed:', error.message); }); return res.status(202).json({ alreadyRunning: started.alreadyRunning, projection: serializeState(started.state) }); } catch (error) { console.error('[LiveProjection] Unable to start manual rebuild:', error.message); return res.status(500).json({ error: 'Unable to start Live projection rebuild' }); } }); module.exports = router; module.exports.serializeState = serializeState;