142 lines
4.5 KiB
Markdown
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.
|