mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
fix(dsh): synchronize observation state and manage thumbnail capture
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
* observation channel through the documented `webServer` route seam instead:
|
||||
*
|
||||
* GET /bsk-observation/state → { sessions, available }
|
||||
* GET /bsk-observation/events → SSE stream of ObservationEvent
|
||||
* GET /bsk-observation/events → SSE snapshot, then ObservationEvent increments
|
||||
* (?thumbnails=0 for state-only subscribers)
|
||||
* POST /bsk-observation/interrupt → body {sessionId?} → {interrupted: boolean}
|
||||
* POST /bsk-observation/stop → body {sessionId} → {stopped: boolean}
|
||||
* GET /bsk-observation/thumbnail/<attachmentId> → image bytes
|
||||
@@ -99,6 +100,7 @@ export function registerObservationRoutes(
|
||||
if (webServer === undefined) {
|
||||
return () => {};
|
||||
}
|
||||
const streams = new Set<() => void>();
|
||||
const disposers = [
|
||||
webServer.register({
|
||||
kind: "exact",
|
||||
@@ -129,14 +131,42 @@ export function registerObservationRoutes(
|
||||
"cache-control": "no-cache",
|
||||
connection: "keep-alive",
|
||||
});
|
||||
const unsubscribe = observation.subscribe((event) => {
|
||||
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
||||
});
|
||||
const heartbeat = setInterval(() => res.write(": heartbeat\n\n"), SSE_HEARTBEAT_MS);
|
||||
res.on("close", () => {
|
||||
const thumbnails =
|
||||
new URL(req.url ?? "/", "http://localhost").searchParams.get("thumbnails") !== "0";
|
||||
let unsubscribe: (() => void) | undefined;
|
||||
let heartbeat: ReturnType<typeof setInterval> | undefined;
|
||||
let closed = false;
|
||||
const close = () => {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearInterval(heartbeat);
|
||||
unsubscribe();
|
||||
});
|
||||
unsubscribe?.();
|
||||
streams.delete(close);
|
||||
res.end();
|
||||
};
|
||||
const write = (data: string) => {
|
||||
if (closed) return;
|
||||
try {
|
||||
res.write(data);
|
||||
} catch {
|
||||
close();
|
||||
}
|
||||
};
|
||||
streams.add(close);
|
||||
res.on("close", close);
|
||||
res.on("error", close);
|
||||
try {
|
||||
unsubscribe = observation.subscribe(
|
||||
(event) => {
|
||||
write(`data: ${JSON.stringify(event)}\n\n`);
|
||||
},
|
||||
{ thumbnails },
|
||||
);
|
||||
if (closed) unsubscribe();
|
||||
else heartbeat = setInterval(() => write(": heartbeat\n\n"), SSE_HEARTBEAT_MS);
|
||||
} catch {
|
||||
close();
|
||||
}
|
||||
},
|
||||
}),
|
||||
webServer.register({
|
||||
@@ -228,6 +258,7 @@ export function registerObservationRoutes(
|
||||
}),
|
||||
];
|
||||
return () => {
|
||||
for (const close of streams) close();
|
||||
for (const dispose of disposers) dispose();
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user