Tell a client where to watch a printer's camera
`continuum-proxy` now generates go2rtc's configuration from the camera
URLs the printers themselves report, and sends two new things up: a
`stream_base_url` on its hello, and a `camera_stream` per printer in
telemetry. This is the other end of both.
`GET /printers/:id/stream` answers `{ streamUrl, cameraId }`, which is
everything a browser needs to open a WebRTC session against the gateway's
go2rtc. 404 rather than 200-with-nulls when either half is missing: a
client handed `{ streamUrl: null }` has to remember to check, and one that
forgets renders a player that can never load. The two causes get
different messages, because they are different problems for whoever is
debugging - a P1/A1 that can never stream is not a gateway that happens
to be offline - and the printer is checked first so a disconnected
gateway cannot mask the permanent case.
The resolution lives in `src/stream.ts` with no imports at all, for the
same reason `dispatch/job_status.ts` does: `../db` opens a connection at
import time, and these two messages are exactly the part worth testing
without one.
Storage, both decided against the obvious alternative:
- `stream_base_url` lives on the in-memory connection, so it goes away
with the socket. It is a LAN address that is only reachable while that
gateway is up; a column on `farms` would keep handing out an address
nothing answers after the gateway disconnected or moved.
- `camera_stream` gets a plain column, because every sibling telemetry
field already has one, and it is cleared when absent like the rest - a
printer that loses its stream must stop being offered one.
`cameraStream` is also added to `printerProjection`, which that file
deliberately requires someone to decide per column. It is a go2rtc stream
name, which is our own printer id echoed back, not a credential, and
having it in the list a client already fetches is what saves it from
calling the stream endpoint once per printer to discover that most of
them 404 by design.
Worth writing down, and it is in the route's comment too: `streamUrl` is
a LAN address and nothing relays it. A browser on the gateway's network
can play the stream and one outside cannot, and this endpoint cannot tell
which the caller is. Good enough for an operator in the workshop, a real
limit for anyone else, and a relay is the fix that does not exist yet.
85 tests (was 77), `bunx tsc --noEmit` clean.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Camera stream resolution, on its own with no imports - the same reason as
|
||||
* `dispatch/job_status.ts`: `../db` opens a connection at import time, and
|
||||
* the two distinct failure messages here are worth testing without one.
|
||||
*/
|
||||
|
||||
export const NO_CAMERA_MESSAGE = "this printer reports no camera that can be streamed";
|
||||
export const NO_GATEWAY_STREAM_MESSAGE =
|
||||
"this farm's gateway is not connected or advertises no stream base URL";
|
||||
|
||||
export type StreamResolution =
|
||||
| { ok: true; stream: { streamUrl: string; cameraId: string } }
|
||||
| { ok: false; reason: "no_camera" | "no_stream_base"; message: string };
|
||||
|
||||
/**
|
||||
* Both halves or an error naming the missing one. The printer is checked
|
||||
* first: if it can never stream, saying the gateway is offline would send
|
||||
* someone off to fix the wrong thing.
|
||||
*/
|
||||
export function resolveStream(
|
||||
cameraStream: string | null | undefined,
|
||||
streamBaseUrl: string | undefined,
|
||||
): StreamResolution {
|
||||
if (!cameraStream) return { ok: false, reason: "no_camera", message: NO_CAMERA_MESSAGE };
|
||||
if (!streamBaseUrl) {
|
||||
return { ok: false, reason: "no_stream_base", message: NO_GATEWAY_STREAM_MESSAGE };
|
||||
}
|
||||
return { ok: true, stream: { streamUrl: streamBaseUrl, cameraId: cameraStream } };
|
||||
}
|
||||
Reference in New Issue
Block a user