Claude: Screenshot Phase 1
This commit is contained in:
@@ -2,14 +2,93 @@
|
||||
|
||||
const express = require('express');
|
||||
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
// Stabile Snapshot-Schnittstelle für das Homing-Projekt.
|
||||
// Entkoppelt den Consumer von go2rtc-Interna – proxied intern auf /api/frame.jpeg.
|
||||
//
|
||||
// GET /api/snapshot → JSON-Liste der Kameras (aus go2rtc /api/streams)
|
||||
// GET /api/snapshot/cam0 → aktuelles JPEG (aus go2rtc /api/frame.jpeg?src=cam0)
|
||||
// GET /api/snapshot/cam0/release-test → Phase-1-Messung (nur lesend, s.u.)
|
||||
function createSnapshotRouter(go2rtcUrl) {
|
||||
const router = express.Router();
|
||||
|
||||
// ── PHASE 1: Geräte-Freigabe messen (rein LESEND, kein Grab) ────────────────
|
||||
// Linchpin-Test aus doc/05_screenShot_roadmap.md: Gibt go2rtc das Gerät frei,
|
||||
// wenn cam0 den letzten Consumer verliert – und wie schnell?
|
||||
//
|
||||
// Voraussetzung: der Client hat seinen <video-stream> für :id bereits entfernt
|
||||
// (das „Umhängen"), BEVOR er diesen Endpunkt ruft. cam0 wird hier NICHT verändert
|
||||
// – wir pollen nur /api/streams und beobachten, wann der Producer stoppt.
|
||||
//
|
||||
// Antwort z.B.: { freed: true, msUntilFree: 1700, zeroConsumerAt, producerStoppedAt, samples }
|
||||
router.get('/:id/release-test', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const POLL_MS = 200;
|
||||
const MAX_MS = 10000;
|
||||
const t0 = Date.now();
|
||||
const samples = [];
|
||||
let zeroConsumerAt = null; // ms ab t0, sobald 0 Consumer beobachtet
|
||||
let producerStoppedAt = null; // ms ab t0, sobald kein laufender Producer mehr
|
||||
|
||||
console.log(`[release-test][${id}] Start – polle /api/streams alle ${POLL_MS}ms (max ${MAX_MS}ms)`);
|
||||
|
||||
while (Date.now() - t0 < MAX_MS) {
|
||||
const elapsed = Date.now() - t0;
|
||||
let nConsumers = null;
|
||||
let producerRunning = null;
|
||||
|
||||
try {
|
||||
// Per-Poll-Timeout: hängt go2rtc, darf das nicht den ganzen Endpunkt
|
||||
// blockieren (sonst kommt der Client nie zurück auf Live → Regel 4).
|
||||
const r = await fetch(`${go2rtcUrl}/api/streams`, { signal: AbortSignal.timeout(1000) });
|
||||
if (r.ok) {
|
||||
const streams = await r.json();
|
||||
const s = streams[id];
|
||||
if (s) {
|
||||
// Shape vgl. server.js-Monitor: producers[].state ('running'|'stop'|…), consumers[]
|
||||
const producers = s.producers ?? [];
|
||||
const consumers = s.consumers ?? [];
|
||||
nConsumers = consumers.length;
|
||||
producerRunning = producers.some((p) => (p.state ?? '') === 'running');
|
||||
} else {
|
||||
// Stream gar nicht (mehr) gelistet → kein Producer, keine Consumer
|
||||
nConsumers = 0;
|
||||
producerRunning = false;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// einzelner Poll-Fehler ist nicht fatal – weiter messen
|
||||
console.warn(`[release-test][${id}] Poll @${elapsed}ms fehlgeschlagen: ${e.message}`);
|
||||
}
|
||||
|
||||
samples.push({ t: elapsed, consumers: nConsumers, producerRunning });
|
||||
|
||||
if (zeroConsumerAt === null && nConsumers === 0) {
|
||||
zeroConsumerAt = elapsed;
|
||||
console.log(`[release-test][${id}] 0 Consumer @${elapsed}ms`);
|
||||
}
|
||||
if (zeroConsumerAt !== null && producerRunning === false && producerStoppedAt === null) {
|
||||
producerStoppedAt = elapsed;
|
||||
console.log(`[release-test][${id}] Producer gestoppt @${elapsed}ms → Gerät frei`);
|
||||
break;
|
||||
}
|
||||
|
||||
await sleep(POLL_MS);
|
||||
}
|
||||
|
||||
const freed = producerStoppedAt !== null;
|
||||
const msUntilFree =
|
||||
freed && zeroConsumerAt !== null ? producerStoppedAt - zeroConsumerAt : null;
|
||||
|
||||
console.log(
|
||||
`[release-test][${id}] Ergebnis: freed=${freed} msUntilFree=${msUntilFree} ` +
|
||||
`(0-Consumer@${zeroConsumerAt}ms, Producer-Stop@${producerStoppedAt}ms)`
|
||||
);
|
||||
|
||||
res.json({ id, freed, msUntilFree, zeroConsumerAt, producerStoppedAt, samples });
|
||||
});
|
||||
|
||||
router.get('/', async (_req, res) => {
|
||||
try {
|
||||
const r = await fetch(`${go2rtcUrl}/api/streams`);
|
||||
|
||||
Reference in New Issue
Block a user