crdtRelayWebSocketHandler function

Handler crdtRelayWebSocketHandler(
  1. RelaySessionHost host, {
  2. Iterable<String>? protocols,
  3. Iterable<String>? allowedOrigins,
  4. Duration? pingInterval,
})

A Dart Frog Handler that upgrades the request and hands the socket to host, the relay (RelaySessionHost) side of the protocol.

// routes/relay.dart
Future<Response> onRequest(RequestContext context) async {
  return crdtRelayWebSocketHandler(context.read<RelaySessionHost>())(
    context,
  );
}

Calling this completes the WebSocket upgrade. From then on the response is a 101, so a client the host will not take — stopped, disposed, or a session id already in use — is hung up on, with no status code and no reason. Refuse before the call to answer with one:

Future<Response> onRequest(RequestContext context) async {
  final token = context.request.headers[HttpHeaders.authorizationHeader];
  if (!await isAuthorized(token)) {
    return Response(statusCode: HttpStatus.unauthorized);
  }
  return crdtRelayWebSocketHandler(context.read<RelaySessionHost>())(
    context,
  );
}

The same window is where SessionHostServer.isRunning belongs, for a shutdown that should answer 503 rather than accept a socket and close it.

The room (document id) travels inside the hello frame, not in the URL, so one route serves every room.

protocols, allowedOrigins and pingInterval are passed straight to dart_frog_web_socket. allowedOrigins is the one to set for a browser client: unset, any origin may connect.

pingInterval is a WebSocket-level ping, which is not the protocol's own ping (Protocol.pingInterval, 15s, answered with a pong and carrying the client's version vector). They serve different purposes — setting one does not let you drop the other.

Implementation

Handler crdtRelayWebSocketHandler(
  RelaySessionHost host, {
  Iterable<String>? protocols,
  Iterable<String>? allowedOrigins,
  Duration? pingInterval,
}) {
  return hostWebSocketHandler(
    host,
    protocols: protocols,
    allowedOrigins: allowedOrigins,
    pingInterval: pingInterval,
  );
}