rpc_dart_websocket 0.5.0
rpc_dart_websocket: ^0.5.0 copied to clipboard
Web-safe subset of rpc_dart_transports providing WebSocket caller/responder transports (caller + server) for Dart2JS/WASM builds.
0.5.0 #
Added #
connect()takesheadersandconnectTimeout. Neither had any way through: an auth header could not be attached to the handshake at all, and a server that accepted the TCP connection and then never completed the upgrade hung the caller forever. Both are re-applied on reconnect.RpcWebSocketNonBinaryFrame— the error raised for a TEXT frame on a binary channel, markedIRpcAdvisoryChannelErrorso it stops at the connection instead of failing every call in flight.
Fixed #
- A call landing inside a reconnect is refused rather than served by a dead
socket.
send, reads andsendDirectObjectall now see the window.
Changed #
- Requires rpc_dart 6.1, for
IRpcAdvisoryChannelError.
0.4.0 #
Breaking #
permessage-deflateis off by default, on the server and in what the client offers. It is a decompression bomb with no output bound: 0.25 MiB uploaded expanded to 516 MiB of RSS (2071x), against 2.7x with it off. The inflation happens insidedart:io, which exposes no limit, so the only lever is not negotiating the extension. Re-enable it deliberately if both peers are trusted.pingIntervaldefaults to 30s on the server. A peer that completes the handshake and then goes silent used to hold its connection, endpoint and contracts forever.- Requires rpc_dart 6. See its changelog — notably that a handler's bare
Exceptiontext no longer reaches the caller, and that a response ending without agrpc-statusnow raisesUNAVAILABLEinstead of ending cleanly.
Security #
- A server can refuse a cross-origin handshake (opt-in): a browser will happily let any page open a WebSocket to your server.
- A duplicated
Originheader no longer kills the server process. - The drain on a refused upgrade is bounded, so refusing a connection is cheaper than accepting one rather than more expensive.
- The inbound message ceiling is pinned by a test rather than claimed in a
doc comment: a 64 MiB message closes the connection with 4400 and the reason
naming the buffer overflow, three 8 MiB messages are accepted. What bounds it
is
maxMessageLengthBytes; the peak allocation cannot be helped, becausedart:iobuffers a whole message before delivering it, so what matters is that the connection closes — a surviving one is an unlimited supply of peaks.
Fixed #
- A dead call's teardown acted on a live one after a reconnect, because the stream id had been reused.
- Concurrent
reconnect()orphaned a socket per attempt. - Keepalive on both halves, which is the only way to notice a half-open path; neither caller noticed the peer had died.
- Graceful drain on
stop()(opt-in), and the server stops accepting before it drains. - A framing violation hung up without saying so, and a non-binary frame was dropped silently instead of reported.
- The peer's close code reaches the caller as a gRPC status instead of a
blanket
UNAVAILABLE. close()deadlocked when nothing listened toincoming.- A failed
start()left the server claiming to run, and a call after a failed reconnect killed the isolate. - A socket that arrives after the transport has closed is closed, not leaked.
- The endpoint is released when
onEndpointCreatedthrows. - The transport no longer hides its security policy from the endpoint, and a throwing observability callback no longer kills the server.
0.3.0 #
Fixed #
- Per-connection endpoints are closed when their connection ends; they were never released, so every connection leaked one.
Changed #
- Requires rpc_dart 5. See its changelog: flow control is on by default, an
expired deadline is now
RpcDeadlineExceededExceptionon every shape, and a stream that ends without a trailer raisesUNAVAILABLE.
0.2.3 #
- Fixed:
RpcWebSocketCallerTransportno longer permanently closes itself when the underlying socket drops gracefully (server-side FIN) and areconnectFactoryis configured. Previously theonDonecascade flipped the transport to closed, so a laterreconnect()returned "Transport closed" — defeating reconnect after a server-initiated drop. The stableincomingMessagesstream now survives the drop so subscribers persist andreconnect()can re-attach. This is the recovery path therpc_dart_logclient relies on. Without areconnectFactorythe transport still closes fully on drop (unchanged). - Expanded test coverage of the flagship streaming transport:
test/websocket_rpc_contract_test.dart: full typed RPC contract end-to-end over a realdart:ioWebSocket server (RpcWebSocketServer+RpcResponderEndpoint/RpcCallerEndpoint, ephemeral localhost port). Covers unary, server-stream (ordered delivery + completion), client-stream (aggregation), bidirectional (ordered echo), typedRpcStatusExceptionpropagation, mid-stream cancellation (no hang, transport stays usable), concurrent calls/streams (no cross-wiring), and a high-volume ordered stream.test/websocket_reconnect_test.dart: reconnect coverage (previously zero). Provesreconnect()re-establishes the socket, the stableincomingMessagesstream survives for pre-existing subscribers, requests issued after reconnect reach a freshly-bound server, full endpoint-level RPC recovers after a server swap, the no-factory/already-closed paths report correctly, and a regression guard for the graceful-drop fix above.
0.2.2 #
- Web-correctness verification: the client transport (
RpcWebSocketCallerTransport/RpcWebSocketChannel) is confirmed dart2js-safe. Nodart:ioon the client path; the frame multiplexer header uses only 32-bitByteDataops (nosetUint64/getUint64), so it is safe under dart2js' 32-bit integer semantics. - Added
test/websocket_web_smoke_test.dart: frame round-trip plus caller/responder round-trips over an in-memoryWebSocketChannelpair (nodart:io). Passes on VM, node, and chrome (fvm dart test -p vm|node|chrome). - Added
asyncandstream_channeldev dependencies for the in-memory channel pair used by the web smoke test.
0.2.1 #
RpcWebSocketServer: addedonPeerEndpointCreatedcallback — when set, each accepted connection creates anRpcPeerEndpointinstead ofRpcResponderEndpoint, enabling bidirectional server-initiated calls over WebSocket.RpcWebSocketCallerTransport.connect(): now awaitsWebSocketChannel.readybefore returning, so connection errors are reported at connect time rather than leaking as unhandled stream errors.- Updated to
rpc_dart: ^3.1.0.
0.2.0 #
- Updated to
rpc_dart: ^3.0.0. - Migrated to 3-layer transport architecture (
IRpcChannel/IRpcMultiplexedChannel/RpcChannelTransport). - WebSocket metadata encoding switched to binary CBOR for consistency with core.
0.1.0 #
- Initial release: WebSocket caller/responder transports for rpc_dart (web-safe, works on Dart2JS/WASM).