diff options
| author | Elizabeth Alexander Hunt <me@liz.coffee> | 2026-06-20 09:40:07 -0700 |
|---|---|---|
| committer | Elizabeth Alexander Hunt <me@liz.coffee> | 2026-06-20 09:40:07 -0700 |
| commit | fb653292612eddca5b088ed88466c546d1597107 (patch) | |
| tree | 900ed32e066812688858ed3bb15128c41bb78054 /README.md | |
| download | penguins.lan-fb653292612eddca5b088ed88466c546d1597107.tar.gz penguins.lan-fb653292612eddca5b088ed88466c546d1597107.zip | |
Initial commit
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..70de28d --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# 🐧 penguins.lan + +A little intranet for a battery-powered LAN with no internet. The successor to +`inetravel` — same "have fun on the network" spirit, but a real Go app instead +of PHP includes, and actually fun stuff: live chat now, an r/place-style shared +canvas next. + +## Stack + +- **Go** standard-library HTTP server, no framework. +- **SQLite** (`mattn/go-sqlite3`) for persistence. +- **gorilla/websocket** for the realtime hub. +- `html/template` for server-rendered pages. + +## Architecture + +Requests flow through a small continuation-passing pipeline. Each route in +[`api/serve.go`](api/serve.go) reads as a flat chain of `Continuation`s, where +every link gets a `(success, failure)` pair and decides which to call. Shared +state for a request lives on `types.RequestContext`. + +``` +LogRequest -> ResolveSession -> RequireUser -> <feature continuations> -> Template -> LogTime +``` + +Layout: + +| path | what | +|------------------|-------------------------------------------------------------| +| `main.go` | entrypoint: load env, open db, migrate, serve | +| `args/` | flag parsing | +| `database/` | sqlite conn, migrations, per-feature queries | +| `adapters/arp/` | resolves a client IP -> MAC from the host's ARP table | +| `api/` | server wiring (`serve.go`) + feature packages | +| `api/auth/` | **MAC-based identity** — sessions, portal, reclaim | +| `api/ws/` | **websocket hub** — broadcast chat, foundation for realtime | +| `api/template/` | html/template rendering + 404 handling | +| `templates/` | server-rendered pages, wrapped in `base.html` | +| `static/` | css / js / images | + +## Identity (`api/auth` + `adapters/arp`) + +No passwords — on a trust-based LAN your **MAC address is your credential**. The +router (nodogsplash) keeps every client on one L2 segment, so the server reads +each visitor's MAC from the ARP table (`arp -an`). + +- **First visit** → the portal asks for a handle; claiming it creates a `user`, + binds your current MAC, and sets a session cookie. +- **Return visit** → a live session cookie logs you in; if it's gone, a + recognised MAC logs you straight back in. +- **Rotated MAC** (privacy randomization) → you show up as a new device. The + portal reports when that handle was *last online* and lets you **log back in** + to reclaim it, re-binding your new MAC to the existing account. + +One user can own many MACs (`macs` table). Chat messages reference `user_id` +(not a name), so identity survives MAC rotation and renames. + +> **Local dev:** the browser is on loopback and never appears in the ARP table, +> so set `DEV_MAC=aa:bb:cc:dd:ee:ff` to force a MAC and exercise the whole flow. +> Never set it in production — it would make every visitor one shared identity. + +## Realtime (`api/ws`) + +The `Hub` owns the set of connected clients and a broadcast channel; all client +set mutations happen in its single `Run()` goroutine, so no locks. Each `Client` +has a `readPump` and `writePump`. Messages are JSON tagged by `type` +(`chat` / `system` / `history`). To add a new realtime feature (e.g. the canvas), +add a `type` and handle it in the hub + client — no new connection plumbing. + +## Run it + +```sh +go mod download +go run . --server --migrate +# -> http://localhost:8080 +``` + +Flags: `--server`, `--migrate`, `--port 8080`, +`--database-path ./db/penguins.db`, `--template-path ./templates`, +`--static-path ./static`. + +### Docker + +```sh +docker compose up --build +``` + +## Roadmap + +- [x] base framework + live chat over websockets +- [x] MAC-based accounts + portal with reclaim +- [ ] r/place-style shared canvas +- [ ] presence / who's online +- [ ] more LAN games |
