rk_quic 0.2.1
rk_quic: ^0.2.1 copied to clipboard
QUIC and WebTransport for Dart over a native library, so a Dart process can serve browser clients directly instead of waiting for HTTP/3 in the SDK.
0.2.1 #
- An endpoint bound to an IPv6 address now asks for dual stack explicitly,
instead of leaving
IPV6_V6ONLYat whatever the operating system defaults to.[::]:4433used to mean every address on Linux and only the IPv6 half of them on Windows, with nothing on either side saying which — and the missing half is the one a browser reaches first, because Windows resolves a machine name andlocalhostto IPv6 ahead of IPv4. - The failure this fixes was silent in both directions. A client on the family
the socket did not carry sent packets and heard nothing: Chrome reports
QUIC_NETWORK_IDLE_TIMEOUTwithnum_undecryptable_packets: 0, and awtransportclient simply times out after thirty seconds.curlis no help at all — it answers 200 through an address the browser cannot use, because it picks a family differently. tests/dual_stack.rsholds it there: one listener on[::]:0, a real WebTransport client over[::1]and over127.0.0.1, both required to open a session. Measured failing before the change on Windows 11 (the IPv4 half timed out), passing after.- No ABI change: generation 2, and
QuicServerConfigis untouched. A caller that was passing0.0.0.0gets exactly what it did before.
0.2.0 #
- Bidirectional streams: an exchange can now be a question and its answer, a subscription, or a run reporting progress. C ABI generation 2.
server.eventsgainsstreamOpened,streamDataandstreamClosed, each carrying astreamIdalongside the session. A session is not an exchange: a browser may have several questions in flight at once, and only the stream says which answer belongs to which.QuicServer.sendOn(sessionId, streamId, message)writes back into the stream a peer opened without ending it;QuicServer.closeStream()ends it. Which kind of exchange it is belongs to the caller, not to the transport.StreamClosedis not an unsubscribe. The endpoint reads a message whole before reporting it, so it learns of a request only once the client has finished writing — and the event therefore arrives immediately behindStreamData, identically for a one-off question and for a subscription meant to last an hour. Treating it as "the client went away" cancels every subscription the moment it is created. A peer that really has gone is learned from a write refused withpeerGone, and fromsessionClosed.sessionClosednow leaves the queue only after the session has been forgotten. The previous order was racy: under concurrent sessions a send could succeed after its own close event had already been read.- An event field of the wrong type no longer throws. The reader used a cast, which threw instead of yielding null, on the isolate where nothing would have reported it — so one oddly-typed field from a newer library looked like "events stopped arriving" rather than like one odd event.
- C ABI generation is 2:
rk_quic_stream_sendandrk_quic_stream_closewere added. A Dart side written against generation 2 refuses a generation-1 library by name rather than dying on a missing symbol.
0.1.0 #
The first version with a native part — and a QUIC endpoint that speaks first.
QuicServer.start()brings up an HTTP/3 endpoint and accepts WebTransport sessions;server.eventsyieldssessionOpened,sessionClosed,datagramandstreamMessage;server.send()writes into a session over a stream (ordered, retransmitted) or as a datagram. Implemented on quinn — see the README for why not quiche.- Everything that blocks — waiting for an event and sending reliably — is on helper isolates: the interface isolate never enters the native part.
idleTimeoutMsis mandatory and has no "never" value. Measured: without it a client that vanished without warning is not noticed at all — the server had still not seensessionClosedtwenty seconds after the client left.- The package does not issue certificates: that is
rk_pki's job. The chain has one representation across both packages —rustls_pki_types::CertificateDer.
Breaking. rkQuicVersion was a const String and is now a String?, read
out of the loaded library. A constant would go on reporting the right version
while a year-old library sat next to it; that is what the version was raised
for.
hasNativeTransportis now a real probe: it opens the library and checks the ABI generation. No longer a stub returningfalse.probeNativeLibrary()returns aNativeProbe:loaded,unsupportedPlatform,libraryMissing,symbolMissing,abiMismatch. Not one of these cases throws an exception or brings the process down.- Statuses cross the boundary by name, not by number; an unfamiliar name
becomes
RkQuicStatus.unrecognisedrather than somebody else's branch. - The native part builds and reaches the application on Windows, Linux and Android. For macOS and iOS the build files are written but not confirmed by a build — there is no Mac available.
- The package is safe to import in a browser:
dart:ffiis behind a conditional import.
0.0.1 #
- Name claimed. No content yet: the package proves the publishing pipeline, it does not solve the problem.