Serve a read-only status page on the bridge port
GET / now returns a dashboard for the reader: mode, port, uptime, card presence, the current card, event counters and a live event log seeded from /api/taps and updated over the /api/events SSE stream. The page is read-only on purpose - it has no claim button, because POST /api/card/claim spends the tap and merely viewing the status would otherwise consume a real login. Serving the page requires allowing same-origin browser requests: a browser sends Origin even for a request to the same origin, so _cors_ok() used to reject the page's own API calls with 403 unless --allow-origin was passed. Loopback and same-host origins are now accepted, and the Access-Control-Allow-Origin echo is applied consistently in one helper instead of four copies. --no-page reverts POST-free deployments to API-only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -309,10 +309,31 @@ cleared, so it cannot be mistaken for a tap still waiting to be used.
|
||||
> per placement may be a long time. Matching them (`--heartbeat 10 --tap-ttl 10`)
|
||||
> avoids the gap for a card held in place.
|
||||
|
||||
### Status page
|
||||
|
||||
Serving also puts a **status page** at `GET /` on the same port, so you can see
|
||||
what the reader is doing from a browser:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8765/
|
||||
```
|
||||
|
||||
It shows the reader's mode, port, uptime, whether a card is present and
|
||||
claimable, the current card, the event counters, and a live event log. The log
|
||||
is seeded with recent history from `/api/taps` and then updated live over the
|
||||
`/api/events` SSE stream, so it keeps filling in without a refresh.
|
||||
|
||||
The page is **read-only**: it deliberately has no "claim" button, because
|
||||
`POST /api/card/claim` spends the tap, and a page that claimed would silently
|
||||
consume a real login just for being open. Claim from your own app instead.
|
||||
|
||||
Disable it with `--no-page` if you want the port to serve the API only.
|
||||
|
||||
### Endpoints
|
||||
|
||||
| Method | Path | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/` | Status page (unless `--no-page`) |
|
||||
| `GET` | `/api/card` | The latched tap: `present`, `claimable`, `consumed`, `age_seconds`, `card` |
|
||||
| `POST` | `/api/card/claim` | Spend the tap on one login. `200`, or `409` if used/none, `410` if expired |
|
||||
| `GET` | `/api/events` | Server-Sent Events stream, pushes each event as it happens |
|
||||
@@ -479,6 +500,9 @@ A healthy startup logs one line:
|
||||
### Checking the reader from the command line
|
||||
|
||||
```bash
|
||||
# Everything at once, in a browser: the status page
|
||||
xdg-open http://127.0.0.1:8765/ # or open it on another machine
|
||||
|
||||
# Is the reader alive? (status, port, uptime)
|
||||
curl -sS http://127.0.0.1:8765/api/health | python3 -m json.tool
|
||||
|
||||
@@ -882,6 +906,7 @@ src/rdm_card_reader/
|
||||
demo.py simulated reads
|
||||
ports.py stable serial port identification
|
||||
bridge.py the HTTP bridge behind --serve
|
||||
webui.py the status page served at GET / by the bridge
|
||||
led.py status LED
|
||||
bootstrap.py offline dependency install
|
||||
wheels/ the bundled wheels (offline install source)
|
||||
|
||||
Reference in New Issue
Block a user