Commit Graph
2 Commits
Author SHA1 Message Date
ChuckandClaude Opus 5.5 d8390e35c5 fix(api): echo only known control-socket reason codes as socket_error
The on-demand routes returned ControlError.reason verbatim. Every reason the
client raises is a fixed code, but the display's error code arrives over the
socket, so map the value onto the known set (transport reasons plus
ErrorCode) and report anything else as "other". Resolves CodeQL
py/stack-trace-exposure on the on-demand stop/start responses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:27:50 -04:00
ChuckandClaude Opus 5.5 af8dc3940a feat(ipc): display control socket, stage 1: on-demand with acks
The display process now serves a Unix socket, /run/ledmatrix/control.sock,
carrying versioned newline-delimited JSON commands that are acknowledged.
Stage 1 moves on-demand start/stop (plus status, hello and ping) onto it;
the cache-file mailbox stays as the fallback for one release.

- src/ipc/contract.py: typed request/response envelopes, command args,
  error codes, NDJSON framing with a 64 KiB limit, socket path rules.
- src/ipc/server.py: threaded server owned by the display. Handlers only
  queue onto a bounded queue and ack with the request id; the render
  thread drains it where it reads the mailbox. Bounded clients, timeouts,
  garbage/oversize/disconnect handling; 0660 socket in the cache dir's
  group plus SO_PEERCRED checks; skips cleanly on Windows or when off.
- src/ipc/client.py: one short-timeout request; any failure raises
  ControlError(reason).
- api_v3/display.py: on-demand start/stop try the socket, fall back to
  the mailbox exactly as before, and report transport/socket_error.
- display_controller.py: start/close the server; the mailbox handler body
  is extracted into _handle_on_demand_request and shared by both paths.
- docs/IPC_CONTROL_SOCKET.md: protocol, security model, stage plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 21:28:31 -04:00