New Feature: XEP-0198 Stream management#867
Open
jcbrand wants to merge 8 commits into
Open
Conversation
3b6ad79 to
35a010b
Compare
Stream management engine which can be used either from the page-bound Connection or from inside a SharedWorker. This will let us do SM inside a SharedWorker, solving the problem of different connections using a shared Websocket connection not keeping track of the same SM counts.
Groundwork for worker-resident XEP-0198 stream management: exactly one tab (port) holds the 'primary' role, all others are secondaries that attach to the shared session.
35a010b to
8c5a401
Compare
Wires the SM engine into the websocket connect flow via a page-side adapter. Opt in with the enableStreamManagement option (plus optional streamManagement tuning). sessionStorage is used automatically in browsers. The engine is constructed for any non-worker transport, but SM is only negotiated over websocket, decided per stream on the live transport: embedders can swap _proto after construction (e.g. via XEP-0156 discovery, or a BOSH-websocket fallback on reconnect), so a construction-time check would silently disable SM for exactly those setups. Over BOSH the engine simply stays inert.
The worker is the only party that sees every tab's traffic (one socket, all sends relayed through it), so it now owns the SM session: counting, the unacked queue, <r/>-><a/> replies (no page round-trip), <a/> reconciliation and resend-on-resume. A stanza sent from a secondary tab survives resumption, and failover to another tab needs no reconnect.
…nection A message or presence sent from one tab was invisible to the other tabs of a shared (worker) connection. Inbound frames are broadcast, but outbound frames were only relayed to the socket. The worker now reflects outbound message/presence frames to every port except the sender (including stanzas salvaged into the SM queue from a send into a dead socket, since those are replayed on the next resume). On the page they surface through the new overridable Connection.onForeignStanzaSent(elem) hook IQs are not reflected, since they're request/response traffic private to the sending tab.
Found by compiling Converse.js against this package: - Use relative internal imports. tsc emits bare specifiers like 'types' verbatim into the .d.ts files, and a consumer with its own baseUrl resolves them against its own project root. - Give NS a string index signature, since it is extended at runtime via Strophe.addNamespace. - Add the missing log/error methods to the Strophe namespace type. - Type the callback that attach() accepts in place of a JID as ConnectCallback instead of () => void. - Expose the SM storage backends on the Strophe namespace and export ConnectionOptions and ConnectCallback from the package root.
2abba73 to
22f8dc3
Compare
A silently dead socket (NAT timeout, sleep/wake) keeps reporting OPEN, and under the shared worker no page-side recovery could reach it: a reloading or reconnecting tab is idempotently joined onto the existing session while the socket looks live, so the only way out was the OS's TCP timeout, which can take many minutes. The worker's sweep now sends an <r/> when an SM-enabled stream has been quiet for a full PING_INTERVAL (doubling as a keepalive), and treats no inbound traffic within PROBE_TIMEOUT as socket death: the zombie is closed and the tabs are told, so they reconnect and the worker resumes the session with the unacked queue replayed. A tab joining the established session triggers an immediate probe, so a page reload recovers within seconds.
The new liveness probe correctly declared the socket dead, but the recovery afterwards wedged every tab, and a related mirror gap surfaced: - The tab driving the reconnect never learned that the worker's new connection attempt failed: the worker broadcasts _onClose with a reason string, and the base Websocket._onClose ignores closes while not connected unless given a real CloseEvent with code 1006. The tab sat in CONNECTING forever. WorkerWebsocket now fails the attempt with CONNFAIL and disconnects, so the embedder's reconnect logic retries. - A tab whose _connect join was parked on the failed handshake was answered with ATTACHFAIL, which a connect()-initiated page treats as terminal. Parked joins now remember how they joined: _attach joins keep the ATTACHFAIL contract, _connect joins are told the socket closed and retry like the driver. - A tab joining after <enabled/> missed the _smEnabled broadcast, so its SM mirror reported no Stream Management. The worker now seeds the mirror when handing out ATTACHED.
4c8981b to
259ddcf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds support to XEP-0198 to Strophe, together with shared worker improvements and the ability to also do stream management when the websocket connection is in a shared worker.