Relay P1/A1 camera frames to viewers

GET /printers/:id/snapshot asks the farm's gateway for one JPEG frame
(camera_snapshot_request) and returns it no-store. Concurrent viewers
share one read and a frame under 800 ms old is reused, because the
printer's camera serves one client. /stream answers kind "snapshot" for
these printers; printers.camera_snapshot is set from telemetry.

scripts/e2e-camera-snapshot.sh reads real frames from the P1P through
the real proxy and backend.
This commit is contained in:
2026-10-29 16:11:10 +00:00
parent cd34f7b597
commit a190c896da
10 changed files with 1176 additions and 6 deletions
+21 -1
View File
@@ -1,7 +1,7 @@
import { describe, expect, test } from "bun:test";
import { Value } from "@sinclair/typebox/value";
import { EdgeClientMessageSchema } from "@continuum/ts-types";
import { NO_CAMERA_MESSAGE, NO_GATEWAY_MESSAGE, resolveStream } from "../src/stream";
import { NO_CAMERA_MESSAGE, NO_GATEWAY_MESSAGE, NO_SNAPSHOT_MESSAGE, resolveSnapshot, resolveStream } from "../src/stream";
const hello = { type: "hello", gateway_id: "gw-1", farm_id: "f1", token: "t" };
@@ -63,3 +63,23 @@ describe("resolveStream", () => {
expect(!both.ok && both.reason).toBe("no_camera");
});
});
describe("snapshot cameras (P1/A1)", () => {
test("telemetry and the gateway's answer survive the validators", () => {
expect(
Value.Check(EdgeClientMessageSchema, {
type: "telemetry",
printers: [{ printer_id: "p1", name: "P1P", camera_snapshot: true }],
}),
).toBe(true);
expect(Value.Check(EdgeClientMessageSchema, { type: "camera_snapshot", request_id: "r", jpeg_base64: "/9j/" })).toBe(true);
expect(Value.Check(EdgeClientMessageSchema, { type: "camera_snapshot", request_id: "r", error: "no frame" })).toBe(true);
expect(Value.Check(EdgeClientMessageSchema, { type: "camera_snapshot", jpeg_base64: "/9j/" })).toBe(false);
});
test("the printer is checked before the gateway", () => {
expect(resolveSnapshot(false, false)).toMatchObject({ ok: false, reason: "no_camera", message: NO_SNAPSHOT_MESSAGE });
expect(resolveSnapshot(true, false)).toMatchObject({ ok: false, reason: "gateway_offline", message: NO_GATEWAY_MESSAGE });
expect(resolveSnapshot(true, true)).toEqual({ ok: true });
});
});