feat: ship HTTP dashboard and harden daemon/API flows

Add the static HTTP dashboard example and wire in the recent daemon/API polish:
CORS-aware API routing, service-install behavior cleanup, safer systemd unit
ExecStart quoting, and friendly-name validation for path-safe targeting.

Also refresh README/API/roadmap docs, remove the temporary claude observations
file, and include the related tests for API/status and daemon validation.
This commit is contained in:
44r0n7
2026-04-18 16:45:12 -04:00
parent 795aa2f713
commit 59fb56558f
17 changed files with 999 additions and 726 deletions
+45
View File
@@ -90,6 +90,16 @@ builders — Home Assistant integrations, stream deck plugins, scripts, dashboar
default. HTTP handlers dispatch directly inside the daemon process rather than looping back through
the Unix socket. All responses are JSON.
Browser clients can be enabled with opt-in CORS settings:
```toml
[daemon]
cors_enabled = true
cors_allowed_origins = ["http://127.0.0.1:8080", "http://localhost:8080"]
```
A full endpoint test dashboard example lives at `examples/http-dashboard/`.
**Adapter Layer**
Each TV platform is implemented as an adapter behind a common Rust trait. The adapter handles all
platform-specific protocol details. Above the adapter layer, nothing knows or cares whether the TV
@@ -300,6 +310,20 @@ GET /v1/devices/a3f2c1d4-.../state
GET /v1/devices/living-room/state ← same result
```
If you use a friendly name in the path, URL-encode it first. This is required
for names containing spaces or reserved characters.
```bash
# Friendly name: "Living Room TV"
curl http://127.0.0.1:7272/v1/devices/Living%20Room%20TV/state
```
Friendly-name validation:
- Spaces are allowed.
- Leading/trailing whitespace is trimmed.
- `/` and `%` are rejected to keep path-based targeting safe and unambiguous.
### Example Requests
```bash
@@ -381,6 +405,8 @@ socket = "/run/user/1000/tvctl.sock"
http_enabled = true
http_port = 7272
http_host = "127.0.0.1"
cors_enabled = false
cors_allowed_origins = []
log_level = "info"
[discovery]
@@ -405,6 +431,8 @@ roku_password = ""
| `daemon.http_enabled` | `true` | Expose HTTP API |
| `daemon.http_port` | `7272` | HTTP API port |
| `daemon.http_host` | `127.0.0.1` | Bind address (loopback by default) |
| `daemon.cors_enabled` | `false` | Enable browser CORS responses for allowed origins |
| `daemon.cors_allowed_origins` | `[]` | Explicit CORS origin allowlist used when CORS is enabled |
| `daemon.log_level` | `info` | Tracing filter (for example `info` or `tvctl=debug`), applied on daemon start and `tvctl config reload` |
| `discovery.auto_discover` | `true` | Discover devices on daemon start |
| `discovery.interval_secs` | `300` | Re-scan interval (0 = disabled) |
@@ -419,6 +447,23 @@ roku_password = ""
## Storage Layout
```
## Dashboard Example
A static browser dashboard for manually testing every API endpoint is included:
`examples/http-dashboard/`
Run it:
```bash
tvctl config set daemon.cors_enabled true
tvctl config set daemon.cors_allowed_origins "http://127.0.0.1:8080,http://localhost:8080"
tvctl config reload
python3 -m http.server 8080 -d examples/http-dashboard
```
Open `http://127.0.0.1:8080`.
~/.config/tvctl/
└── config.toml