Files

105 lines
3.9 KiB
Markdown

# iroh-live-relay: Browser Bridging
## Overview
The relay server bridges iroh P2P streams to browser clients via WebTransport. Browsers cannot speak iroh's QUIC protocol directly, so the relay accepts WebTransport connections and either serves locally-published broadcasts or pulls them from remote iroh publishers on demand.
**Architecture:**
```
iroh-live publish --(iroh P2P)--> iroh-live-relay <--(WebTransport)-- browser
browser --(WebTransport)--> iroh-live-relay --(iroh P2P)--> iroh-live subscribe
```
## Components
### `RelayConfig` (CLI Configuration)
```rust
pub struct RelayConfig {
pub bind: SocketAddr, // QUIC/WebTransport bind (default: [::]:4443)
pub http_bind: SocketAddr, // HTTP static files bind (default: same as bind)
}
```
Flattenable into a clap CLI via `#[command(flatten)]`.
### `run(config)` — Main Server Loop
The main entry point. Sets up:
1. **QUIC/WebTransport server** — Uses `moq-native::ServerConfig` with:
- QUIC backend: `noq` (a custom QUIC implementation)
- iroh endpoint integration
- Self-signed TLS certificates (dev mode) for `localhost`
- Max streams: `moq_relay::DEFAULT_MAX_STREAMS`
2. **iroh endpoint** — Binds an iroh endpoint for P2P connectivity, prints its ID
3. **moq-relay Cluster** — The broadcast routing engine. Manages broadcast lifecycle: when all subscribers disconnect, the broadcast is removed.
4. **HTTP server** — Axum router serving:
- `GET /certificate.sha256` — TLS fingerprint for dev mode
- `GET /` — Web viewer landing page
- `GET /{path}` — Static file serving with CORS
- Embedded via `include_dir!` from `web/dist/`
5. **Pull mode** — If iroh endpoint is available, creates a `PullState` for on-demand remote broadcast fetching
6. **Connection loop** — Accepts incoming connections, parses the URL path as a `LiveTicket`, and if valid, triggers a pull before running the connection
### `PullState` — On-Demand Remote Fetching
When a browser connects with a broadcast name that is a valid `LiveTicket`, the relay:
1. Checks if the broadcast already exists in the cluster (fast path)
2. If not, connects to the remote publisher via iroh-live's `Moq::connect()`
3. Subscribes to the remote broadcast
4. Publishes the consumer into the local cluster under the ticket string as the name
5. Spawns a keepalive task that holds the session until it closes
**Concurrency:** Duplicate concurrent pulls for the same ticket are deduplicated using a `HashMap<String, Arc<Notify>>`. Waiters block on the `Notify` until the first connector finishes.
```rust
pub(crate) struct PullState {
live: iroh_live::Live,
cluster: Cluster,
connecting: Arc<Mutex<HashMap<String, Arc<Notify>>>>>,
}
```
### Web Viewer
The relay embeds a SolidJS + TypeScript web application compiled by Vite. It uses:
- `@moq/watch` — Web component for watching streams via WebCodecs
- `@moq/publish` — Web component for publishing from browser camera/mic
- WebTransport — For QUIC connectivity from the browser
Watch URLs: `https://relay:4443/?name=<BROADCAST_OR_TICKET>`
### Data Directory
The relay persists data to `$IROH_LIVE_RELAY_DATA` (or the platform default). This includes:
- iroh secret key (`iroh_secret_key`) — ensures endpoint ID stability across restarts
- TLS certificates
### TLS and Certificates
Currently **self-signed only**. ACME/Let's Encrypt is planned but not implemented. In dev mode, browsers need `--ignore-certificate-errors` or the relay's fingerprint (served at `/certificate.sha256`) for WebTransport to work.
## Error Handling
No authentication is implemented yet. The relay accepts all connections. MoQ supports token-based authentication which could be added.
## CLI Binary
```rust
// iroh-live-relay/src/main.rs
#[derive(Parser)]
struct Cli {
#[command(flatten)]
relay: RelayConfig,
}
```
Must call `rustls::crypto::aws_lc_rs::default_provider().install_default()` before `run()`.