crdtRelayWebSocketHandler function
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,
);
}