shellphone 0.2.1

Pipe CLI commands to a secure mobile web terminal
---
id: http-server
title: HTTP and WebSocket server
altitude: 1
topics:
- server
relations:
- type: refines
  target: architecture
- type: depends_on
  target: pty-bridge
- type: depends_on
  target: session-guard
summary: 'The axum server: routes, embedded frontend, WebSocket handling, TLS support, and port fallback.'
---

# HTTP and WebSocket server

`src/server.rs` runs an axum server with three routes and optional TLS.

## Routes

- **`GET /`** — serves the embedded `frontend/index.html` as HTML.
- **`GET /assets/{*path}`** — serves vendored frontend assets (xterm.js, CSS) with MIME type detection.
- **`GET /ws`** — WebSocket upgrade. Reads `token` and `refresh` query parameters.

## Server startup

`start()` accepts a `ServerConfig` and returns `(SocketAddr, Arc<Notify>)`. The `Notify` fires when a client successfully authenticates, used by `main` to clear the QR code.

Port binding tries `{bind_ip}:3845` first, falls back to `{bind_ip}:0` (OS-assigned) if the port is taken.

For TLS mode, the server uses `axum-server` with `RustlsConfig` from PEM-encoded cert/key generated by `src/tls.rs`.

## WebSocket lifecycle

1. `ws_handler` extracts `token` and `refresh` from query params, upgrades the connection.
2. `handle_ws` calls `SessionGuard::authenticate`. On `NewSession`, it notifies the connected signal and sends the refresh token as a JSON text frame. On `Failed`, the socket is dropped.
3. Two concurrent tasks bridge the WebSocket to the PTY:
   - **send_task:** `PtyEvent::Output` → binary WS frames; `PtyEvent::Exit` → JSON text frame, then break.
   - **recv_task:** parses JSON `ClientMessage` from text frames → `PtyCommand::Input` or `PtyCommand::Resize`.

## Output fan-out

`relay_events` creates a fresh `broadcast::Sender` from the PTY bridge's `broadcast::Receiver`, allowing per-connection subscribers via `.subscribe()`.