mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-18 02:20:47 -04:00
85 lines
2.4 KiB
JavaScript
85 lines
2.4 KiB
JavaScript
const EventEmitter = require('events');
|
|
const logger = require('../globals/logger').child('roomCameraSnapshot');
|
|
const { getRoomCameras, roomCameraEvents } = require('./roomCameraService');
|
|
|
|
const POLL_INTERVAL_MS = 800;
|
|
const FETCH_TIMEOUT_MS = 2000;
|
|
|
|
const cameraState = new Map(); // id -> {frame, ts, error, failures, fetching}
|
|
const events = new EventEmitter(); // frame, status
|
|
let pollTimer = null;
|
|
|
|
function markState(id, updates = {}) {
|
|
const prev = cameraState.get(id) || {};
|
|
const next = { ...prev, ...updates };
|
|
cameraState.set(id, next);
|
|
return next;
|
|
}
|
|
|
|
async function fetchSnapshot(camera) {
|
|
const { id, url } = camera;
|
|
const state = cameraState.get(id);
|
|
if (!url || state?.fetching) return;
|
|
markState(id, { fetching: true });
|
|
const abortController = new AbortController();
|
|
const timeout = setTimeout(() => abortController.abort(), FETCH_TIMEOUT_MS);
|
|
try {
|
|
const res = await fetch(url, { signal: abortController.signal });
|
|
if (!res.ok) {
|
|
throw new Error(`HTTP ${res.status}`);
|
|
}
|
|
const arrayBuffer = await res.arrayBuffer();
|
|
const buffer = Buffer.from(arrayBuffer);
|
|
const ts = Date.now();
|
|
markState(id, { frame: buffer, ts, error: null, failures: 0 });
|
|
events.emit('frame', { id, buffer, ts });
|
|
} catch (err) {
|
|
const failures = (state?.failures || 0) + 1;
|
|
markState(id, { error: err.message, failures });
|
|
events.emit('status', { id, error: err.message });
|
|
logger.warn('Snapshot fetch failed', { id, err: err.message });
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
markState(id, { fetching: false });
|
|
}
|
|
}
|
|
|
|
function stopAll() {
|
|
if (pollTimer) {
|
|
clearInterval(pollTimer);
|
|
pollTimer = null;
|
|
}
|
|
cameraState.clear();
|
|
}
|
|
|
|
function startAll() {
|
|
stopAll();
|
|
pollTimer = setInterval(() => {
|
|
getRoomCameras().forEach((camera) => fetchSnapshot(camera));
|
|
}, POLL_INTERVAL_MS);
|
|
getRoomCameras().forEach((camera) => fetchSnapshot(camera));
|
|
logger.info('Started snapshot polling', { count: getRoomCameras().length });
|
|
}
|
|
|
|
function getState(id) {
|
|
const state = cameraState.get(id);
|
|
if (!state) return null;
|
|
return {
|
|
frame: state.frame || null,
|
|
ts: state.ts || null,
|
|
error: state.error || null,
|
|
};
|
|
}
|
|
|
|
roomCameraEvents.on('update', () => {
|
|
logger.info('Room cameras changed; restarting snapshot pollers');
|
|
startAll();
|
|
});
|
|
|
|
startAll();
|
|
|
|
module.exports = {
|
|
roomCameraStreamEvents: events,
|
|
getRoomCameraState: getState,
|
|
};
|