Skip to content

Releases: yetone/alma-relay

v1.2.0 — relay protocol 2

Choose a tag to compare

@yetone yetone released this 01 Nov 13:55

Relay protocol 2

Upload bodies now stream through the relay, and tunnel frames are sent as binary instead of base64 JSON. The protocol is negotiated, so old and new desktops keep working against either relay version.

Desktop Relay Result
old (v1) 1.2.0 protocol 1, unchanged
new (v2) 1.1.x or older protocol 1, unchanged
new (v2) 1.2.0 protocol 2

How it works:

  • The desktop adds proto: 2 to register. The relay answers with {t:'registered', proto}. A reply without proto means 1.
  • RELAY_PROTOCOL=1 on the relay turns v2 off, so you can roll back without redeploying the desktop.

What protocol 2 adds

  • Streamed request bodies. Uploads are forwarded in 256 KiB slices with a 4 MiB per-request window that the desktop acknowledges. A large upload no longer has to fit in relay memory. A stalled upload gets a 504 after STALL_TIMEOUT_S, and an oversized one gets a 413.
  • Binary frames. Response chunks, request bodies and WebSocket messages travel as binary WebSocket frames, without the 33% base64 overhead.
  • Body limit. MAX_BODY_MB is configurable, default 100. On v1 the limit stays at 24 MB on Cloudflare.

Cloudflare note

The Cloudflare edge buffers the whole request body before the Worker runs. On the Cloudflare edition, protocol 2 therefore does not improve time-to-first-byte for uploads. It still lifts the 24 MB cap, keeps bodies out of Durable Object memory, paces delivery to the desktop and uses binary frames. The Node edition streams end to end.

See docs/PROTOCOL.md for the wire format.

v1.1.0

Choose a tag to compare

@yetone yetone released this 01 Nov 09:52

Node edition: flow control and resource limits

  • Backpressure. A phone that reads slower than the desktop sends no longer makes the relay buffer the whole stream. Once a phone has 8 MiB queued, the relay stops reading the desktop's socket, so TCP pushes back on the desktop, and resumes below 1 MiB. A phone that drains nothing for STALL_TIMEOUT_S (60 s) is cut off. In the other direction, phone sockets pause while the desktop's socket is backed up.
  • Limits: MAX_BUFFERED_MB (512), MAX_AGENTS (10000), MAX_REQUESTS_PER_AGENT / MAX_SOCKETS_PER_AGENT (256 each) and MAX_CONNECTIONS.
    • An oversized Content-Length is refused before the body is read.
    • Agent sockets must register within 10 s.
    • Phones may send at most 4 MiB before the desktop opens its side.
  • Frame caps now match the Cloudflare edition: 32 MiB agent frames and 24 MiB phone messages (both were 256 MiB).

Cloudflare edition

  • LOCATION_HINT now actually moves tunnels. Tunnels are named <hint>:<hash>. A desktop that hasn't redialled since the hint was set is still found in its old tunnel. Only the relay's own "no desktop" answer triggers that fallback, so a desktop's 502 still reaches the phone.
  • RELAY_TOKEN_MESSAGE sets what a desktop without a valid relay token is told.
  • cloudflare/worker.mjs ships in the package. A deployment can now depend on alma-relay and point wrangler's main at node_modules/alma-relay/cloudflare/worker.mjs.

See docs/PROTOCOL.md for details.

v1.0.1

Choose a tag to compare

@yetone yetone released this 01 Nov 07:37
  • Cloudflare: WebSocket close handshakes now complete. Phones used to wait ~10 s and end with 1006 (#1, thanks @NaNhkNaN).
  • Cloudflare: a desktop error before the response head returns 502 with the desktop's message, not 504 (#1).
  • APNs: carries Live Activity pushes (pushType: 'liveactivity', priority), matching Alma's hosted relay.

Docker: ghcr.io/yetone/alma-relay:1.0.1. Cloudflare: git pull && npx wrangler deploy.