require('dotenv').config(); const express = require('express'); const path = require('path'); const fs = require('fs'); const config = require('./api_v1/config'); const { startWsOutboxConsumer } = require('./ws-server/ws-outbox-consumer'); const { jwtMiddleware } = require('./middleware/jwt'); const staticMiddleware = require('./middleware/static'); const { createWaitForCastSegment } = require('./middleware/waitForCastSegment'); // removed old hls middleware // const hlsMiddleware = require('./middleware/hls'); const authRouter = require('./routes/auth'); const configRouter = require('./routes/config'); const scanRouter = require('./routes/scan'); const autoScanRouter = require('./routes/autoScan'); const shareRouter = require('./routes/share'); const photosRouter = require('./routes/photos'); const activitiesRouter = require('./routes/activities'); const scanActivitiesRouter = require('./routes/scanActivities'); const scanStatusRouter = require('./routes/scanStatus'); const usersRouter = require('./routes/users'); const faceReviewRouter = require('./routes/faceReview'); // nuovo: router HLS che sta in routes/hls.js const hlsRouter = require('./routes/hls'); const server = express(); // CORS per i flussi video HLS pubblici server.use(['/hls', '/cast'], (req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS'); res.setHeader( 'Access-Control-Allow-Headers', 'Origin, Accept, Content-Type, Range, Authorization' ); res.setHeader( 'Access-Control-Expose-Headers', 'Content-Length, Content-Range, Accept-Ranges, Content-Type' ); if (req.method === 'OPTIONS') { return res.sendStatus(204); } next(); }); /* * I manifest VOD anticipati possono fare riferimento a segmenti * che FFmpeg non ha ancora prodotto. * * Per le sole richieste /cast/.../segment_XXXXX.ts, il server * attende la comparsa del file invece di rispondere subito 404. * * Deve essere montato prima di express.static. */ const castRoot = path.resolve( __dirname, 'public', 'cast' ); server.use( '/cast', createWaitForCastSegment({ castRoot, // Attesa massima per un seek molto avanti. timeoutMs: Number( process.env.CAST_SEGMENT_WAIT_TIMEOUT_MS || 300000 ), // Controlla la comparsa del file ogni 100 ms. pollMs: Number( process.env.CAST_SEGMENT_WAIT_POLL_MS || 100 ), // Evita di servire un segmento ancora in scrittura. stabilityMs: Number( process.env.CAST_SEGMENT_STABILITY_MS || 50 ) }) ); // Statici pubblici (mantieni il tuo middleware statico) server.use(staticMiddleware); // Body parser (deve essere prima delle route che leggono JSON) server.use(express.json()); server.use(express.urlencoded({ extended: true })); // Base directory per gli output HLS (puoi sovrascriverla con env HLS_BASE) const HLS_BASE = process.env.HLS_BASE || path.join(process.cwd(), 'hls_output'); fs.mkdirSync(HLS_BASE, { recursive: true }); // Serve i file HLS generati (master.m3u8 e .ts) pubblicamente su /hls server.use('/hls', express.static(HLS_BASE)); // Login pubblico server.get('/login', (req, res) => { res.sendFile(path.join(__dirname, 'public/login.html')); }); // Rotte pubbliche server.use('/auth', authRouter); server.use('/config', configRouter); //server.use('/share', shareRouter); // JWT per tutto il resto (mantieni la tua regex) server.use( /^(?!\/auth)(?!\/share)(?!\/login)(?!\/login.html)(?!\/css)(?!\/js)(?!\/img)(?!\/fonts)(?!\/favicon).*$/, jwtMiddleware ); // Monta il router HLS dopo il jwtMiddleware in modo che le API siano protette // GET statici /hls/ sono giĆ  serviti pubblicamente dalla express.static sopra server.use('/hls', hlsRouter); // Rotte protette server.use('/share', shareRouter); server.use('/users', usersRouter); server.use('/face-review', faceReviewRouter); server.use('/photos', photosRouter); server.use('/activities', activitiesRouter); server.use('/scan', scanRouter); server.use('/scanActivities', scanActivitiesRouter); server.use('/api_v1/auto_scan', autoScanRouter); server.use('/scanStatus', scanStatusRouter); // Home server.get('/', (req, res) => { res.sendFile(path.resolve('public/index.html')); }); server.listen(config.PORT, () => { console.log(`Server running on port ${config.PORT}`); // Solo il processo principale consuma la outbox e possiede // le connessioni WebSocket. startWsOutboxConsumer({ pollMs: Number(process.env.WS_OUTBOX_POLL_MS || 250) }); });