tronbyt/docs/PLAN.md
2026-03-10 16:53:05 -07:00

142 lines
4.5 KiB
Markdown

# Tronbyt Toes App — Implementation Plan
## What This Is
A toes app that wraps the Tronbyt Go server (self-hosted Tidbyt replacement) as a managed subprocess. Bun proxies all HTTP and WebSocket traffic to the Go binary over a unix socket. The Tidbyt device talks to `tronbyt.toes.local` and everything chains through.
```
Tidbyt device
→ tronbyt.toes.local (toes proxy)
→ Bun app on PORT (this app)
→ Go binary on unix socket
```
## File Structure
```
tronbyt/
package.json
index.tsx # re-exports src/server
src/
server/
index.tsx # Hype app: spawns Go binary, proxies all traffic
pages/
index.tsx # Hype page (not needed, Go serves its own UI)
bin/
.gitkeep
tronbyt-server # pre-built binary (gitignored, per-platform)
docs/
PLAN.md # this file
```
## Implementation Steps
### 1. Binary setup
- Download the right binary from https://github.com/tronbyt/server/releases
- Mac dev: `tronbyt-server-darwin-arm64`
- Pi production: `tronbyt-server-linux-arm64`
- Place in `bin/tronbyt-server`, make executable (`chmod +x`)
- Add `bin/tronbyt-server` to `.gitignore`
- On macOS: System Settings → Privacy & Security → Allow Anyway
### 2. Spawn the Go binary
On server startup, spawn `bin/tronbyt-server` with these env vars:
| Env Var | Value | Why |
|---|---|---|
| `TRONBYT_UNIX_SOCKET` | `{DATA_DIR}/tronbyt.sock` | Avoids port conflicts, clean proxying |
| `DATA_DIR` | `{DATA_DIR}` | Persists DB, apps, firmware across deploys |
| `DB_DSN` | `{DATA_DIR}/tronbyt.db` | Explicit DB path |
| `PRODUCTION` | `false` | Skip firmware downloads (set `true` on Pi later) |
| `SINGLE_USER_AUTO_LOGIN` | `true` | Home network, no login needed |
| `SYSTEM_APPS_AUTO_REFRESH` | `true` | Keep community apps updated |
Wait for health by polling the unix socket at `/health` until it returns 200.
### 3. HTTP proxy
Proxy all requests from Bun → Go over the unix socket:
```ts
app.all('*', async (c) => {
const resp = await fetch(socketUrl + c.req.path + search, {
method: c.req.method,
headers: c.req.raw.headers,
body: c.req.raw.body,
unix: socketPath,
})
return new Response(resp.body, resp)
})
```
Bun's `fetch` supports `unix` option natively — no extra libraries needed.
### 4. WebSocket proxy
Two WS endpoints to proxy:
- `GET /ws` — dashboard real-time updates
- `GET /{deviceId}/ws` — device push connection
Use `Bun.serve`'s websocket support to accept the upgrade on the Bun side, then open a WebSocket to the Go server over the unix socket and relay messages bidirectionally.
### 5. Health check
```ts
app.get('/ok', async (c) => {
const resp = await fetch('http://localhost/health', { unix: socketPath })
return resp.ok ? c.text('ok') : c.text('unhealthy', 503)
})
```
### 6. Graceful shutdown
```ts
process.on('SIGTERM', () => {
goProcess.kill('SIGTERM')
})
```
The Go server handles SIGTERM cleanly. Toes gives 10s before SIGKILL.
### 7. Remove Hype pages
The scaffolded `src/pages/index.tsx` isn't needed — the Go server serves its own web UI. The Bun app is purely a proxy, no HTML rendering. Can simplify to just `src/server/index.tsx` or even a single `index.ts`.
## Toes Environment Variables
These are set automatically by toes on every app:
| Var | Description |
|---|---|
| `PORT` | Port to listen on |
| `DATA_DIR` | Per-app persistent data directory |
| `APPS_DIR` | Shared apps directory |
| `TOES_URL` | Base URL of toes server |
| `APP_URL` | This app's subdomain URL |
## Device Configuration
Flash the Tidbyt with Tronbyt firmware, then set:
```
Image URL: http://tronbyt.toes.local/<device-id>/next
```
The device ID is assigned by the Tronbyt server when you add the device in its web UI.
## Gotchas
1. **IPv6 binding** — Not an issue with unix socket approach (no TCP binding on Go side)
2. **First boot is slow** — Community apps repo clones on first start (~15s). With `PRODUCTION=false`, firmware download is skipped. Set `PRODUCTION=true` on Pi if you want OTA firmware updates.
3. **macOS unsigned binary** — System Settings → Privacy & Security → Allow Anyway
4. **Device WiFi** — Tidbyt ESP32 is 2.4GHz only
5. **Image URL must be full path**`http://tronbyt.toes.local/<device-id>/next`, not just the base URL
## Dependencies
No new dependencies needed beyond what's already in package.json. Bun's native `fetch` handles unix sockets. The Go binary is self-contained (Pixlet embedded).
Can remove `@because/forge` and `@because/howl` from dependencies since this app has no UI of its own.