feat: code-review-tea — Gitea/tea fork of Anthropic's code-review plugin #10

Open
alee wants to merge 11 commits from plugin/code-review-tea into main
Showing only changes of commit 475c7b097b - Show all commits

View File

@@ -0,0 +1,164 @@
# Camera Stream Simulator — Design
**Status:** Approved
**Date:** 2026-04-05
**Scope:** Development tooling only. Not shipped to operators.
## Purpose
Loop phone-recorded video files as local RTSP streams so Vigilar's real camera
pipeline (OpenCV capture, motion detection, HLS, recording, reconnect logic)
can be exercised end-to-end without physical cameras. The operator records
35 minutes of footage from each angle on a phone, drops the files into a
`videos/` directory, and runs a single script that serves them as
`rtsp://127.0.0.1:8554/<camera_id>`.
Primary use case: manual dev testing with 45 real clips. Secondary use case:
stress testing with up to 32 distinct clips.
## Non-Goals
- Not a production feature. Never invoked in deployed installs.
- Not a pytest fixture. Manual workflow only.
- No per-stream jitter, audio, non-mp4 inputs, or CLI flags.
- No Python rewrite or `vigilar sim` subcommand.
## Architecture
One bash script, one helper binary (MediaMTX), one ffmpeg process per stream.
```
scripts/sim_cameras.sh
├── starts: mediamtx (127.0.0.1:8554) ← single static Go binary
├── reads: config/vigilar.toml ← discovers camera ids
├── for each [[cameras]] block:
│ expects videos/<camera_id>.mp4
│ spawns: ffmpeg -stream_loop -1 -re -i videos/<id>.mp4 \
│ -c copy -f rtsp rtsp://127.0.0.1:8554/<id>
├── writes: config/vigilar.sim.toml ← copy of real config,
│ rtsp_urls rewritten
└── foreground; Ctrl-C kills all children
```
Operator workflow:
```
$ ./scripts/sim_cameras.sh
→ serving 5 streams on 127.0.0.1:8554
→ wrote config/vigilar.sim.toml
$ vigilar start --config config/vigilar.sim.toml # in another terminal
```
Strict 1:1 mapping — each simulated stream corresponds to exactly one video
file, named after the camera id in `vigilar.toml`. No file reuse, no cycling.
## Components
### `scripts/sim_cameras.sh`
Bash, no Python dependencies. Responsibilities:
1. Resolve paths: `$REPO/config/vigilar.toml`, `$REPO/videos/`,
`$REPO/.sim/mediamtx`, `$REPO/.sim/logs/`.
2. Check prerequisites: `ffmpeg` on PATH, `mediamtx` binary present,
`videos/` directory exists.
3. Parse camera ids from `vigilar.toml` by grepping `^id = "..."` lines
inside `[[cameras]]` blocks. No TOML parser — tolerable because the
config format is stable and this is dev tooling.
4. Verify `videos/<id>.mp4` exists for every camera id. List **all**
missing files in one error message, then exit 1.
5. Launch `mediamtx` in the background, writing its log to
`.sim/logs/mediamtx.log`. Wait ~500ms, then verify the RTSP port
(8554) is listening (`ss -lnt` or `/dev/tcp`).
6. Launch one ffmpeg process per camera, backgrounded, with stdout/stderr
redirected to `.sim/logs/<id>.log`. Track PIDs in a bash array.
7. Generate `config/vigilar.sim.toml`: copy the real TOML, rewrite each
`rtsp_url = "..."` line to `rtsp://127.0.0.1:8554/<id>` using `sed`
scoped per camera block.
8. Print a summary: each served URL, the sim config path, and
"Press Ctrl-C to stop".
9. Install a `trap` on EXIT/INT/TERM that kills mediamtx and every ffmpeg
child PID, then removes `.sim/`. Idempotent.
10. `wait` on child PIDs so the script blocks until Ctrl-C.
### `scripts/download_mediamtx.sh`
Parallel to the existing `scripts/download_model.sh`. Downloads the
MediaMTX static binary for the current architecture from the official
GitHub release into `.sim/mediamtx`, verifies it is executable, and exits.
Run once per machine.
### `videos/` (gitignored)
Operator drops `<camera_id>.mp4` files matching camera ids in
`config/vigilar.toml`. Format is mp4 only; other extensions are rejected.
### `.sim/` (gitignored)
Working directory, recreated each run:
- `.sim/mediamtx` — the static binary (installed by `download_mediamtx.sh`)
- `.sim/logs/mediamtx.log`
- `.sim/logs/<camera_id>.log`
### `config/vigilar.sim.toml` (gitignored)
Generated artifact. Overwritten on every run. Never hand-edited. The real
`config/vigilar.toml` is read-only from the simulator's perspective.
### MediaMTX
Single static Go binary. Default configuration is sufficient — listens on
RTSP port 8554, accepts `rtsp://127.0.0.1:8554/<path>` publishes from
ffmpeg. No custom yaml required.
## Error Handling
Fail loud and early. No silent fallbacks.
| Condition | Behavior |
|---|---|
| `ffmpeg` not on PATH | Print install hint, exit 1 |
| `.sim/mediamtx` missing | Print "run scripts/download_mediamtx.sh", exit 1 |
| `videos/` missing or any `videos/<id>.mp4` missing | List **all** missing files, exit 1 |
| MediaMTX fails to bind 8554 | Dump `.sim/logs/mediamtx.log` tail, exit 1 |
| ffmpeg child dies mid-run | Log to stderr, leave others running. Vigilar's reconnect logic handles the gap — this is a feature, not a bug. |
| Ctrl-C / script death | `trap` kills mediamtx + all ffmpeg PIDs, removes `.sim/` |
## Acceptance Criteria
Manual verification — this is dev tooling, not production code.
1. Drop 5 mp4s matching camera ids into `videos/`, run
`./scripts/sim_cameras.sh`. 5 URLs print.
2. `ffprobe rtsp://127.0.0.1:8554/<id>` succeeds for each stream.
3. In another terminal:
`vigilar start --config config/vigilar.sim.toml`. The web UI shows
5 camera tiles with live HLS. Waving at phone footage triggers motion
events in the event log.
4. Kill one ffmpeg process manually. Vigilar marks that camera as
disconnected; reconnect loop engages. Restart the same ffmpeg
invocation → stream recovers in the UI.
5. Ctrl-C the sim script. `pgrep ffmpeg` and `pgrep mediamtx` both empty.
`.sim/` removed.
6. Scale test: populate 32 dummy mp4s matching 32 camera blocks. Script
starts cleanly; CPU remains within reason (subjective; no hard target).
### Automated Check
One light test: `tests/unit/test_sim_script.py` runs
`bash -n scripts/sim_cameras.sh` (syntax check) and, if `shellcheck` is
available, runs it as well. No integration tests — the simulator exists to
support manual testing.
## File Inventory
New files:
- `scripts/sim_cameras.sh`
- `scripts/download_mediamtx.sh`
- `tests/unit/test_sim_script.py`
Modified files:
- `.gitignore` — add `videos/`, `.sim/`, `config/vigilar.sim.toml`
No changes to `vigilar/` package code. The simulator is fully external.