Skip to content

relay: WS upgrade for /v1/server — accept binary connection, validate headers, claim server-id #4

@ilmoniemi

Description

@ilmoniemi

User Story

As a pyry binary opening an outbound WebSocket to the relay, I want a /v1/server endpoint that validates the required headers, registers my connection in the registry under my server-id, and returns WS close 4409 if another binary already holds it, so that the binary side of the routing topology is established cleanly per the protocol spec.

Context

Implements the binary-side handshake from pyrycode/pyrycode/docs/protocol-mobile.md § Authentication → Binary → relay. First-claim-wins enforcement; the registry (#3) provides the underlying primitive. WebSocket library choice: nhooyr.io/websocket (modern, context-aware, idiomatic Go).

Acceptance Criteria

  • New file internal/relay/server_endpoint.go exporting:
    • func ServerHandler(r *Registry, logger *slog.Logger) http.Handler — returns an http.Handler for /v1/server.
  • On request:
  • cmd/pyrycode-relay/main.go updated: register the handler at /v1/server on the existing mux. Existing /healthz keeps working.
  • Tests in internal/relay/server_endpoint_test.go covering:
    • Successful upgrade with all required headers → registry shows binary registered.
    • Missing each required header → 400 (table-driven test, one row per missing header).
    • Conflict (second binary tries to claim) → second connection receives close 4409.
    • Closing the WS unregisters from the registry.
    • Invalid WS upgrade (e.g. wrong method, missing Upgrade header) → standard 426/400 from nhooyr.io/websocket.
  • gosec + govulncheck clean.

Technical Notes

Size Estimate

S — ~120 LOC + ~150 LOC tests. Adds nhooyr.io/websocket dep.

Depends on

Metadata

Metadata

Assignees

No one assigned

    Labels

    security-sensitiveTouches auth, crypto, or internet-exposed input paths

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions