Add a real WebSocket builtin module - #510
Open
dan-distributive wants to merge 1 commit into
Open
dan-distributive wants to merge 1 commit into
dan-distributive wants to merge 1 commit into
Conversation
pythonmonkey has never had a WebSocket implementation. dcp-client's own SocketIOTransport.buildOptions() explicitly special-cases this: every platform except pythonmonkey gets transports: ['websocket', 'polling'] and upgrades to a persistent WebSocket within the first round trip or two; pythonmonkey is hard-restricted to ['polling'] forever, since `typeof WebSocket` was previously `undefined`. That forces pythonmonkey to be the only client that ever *sustains* HTTP long-polling for an entire connection's lifetime against services like DCP's package manager - a code path essentially unexercised by any other real client, where a real, reproducible session-routing bug lives (a freshly issued session id doesn't reliably route to the same backend on the very next polling request; confirmed independent of pythonmonkey/dcp-client with plain curl, aiohttp, and Node https). Rather than work around that bug, this gives pythonmonkey a real WebSocket implementation - a JS class matching the DOM API (builtin_modules/WebSocket.js), backed by a Python aiohttp-based implementation (builtin_modules/WebSocket-internal.py), following the exact existing pattern XMLHttpRequest already uses (loaded dynamically via require() at pythonmonkey import time, no C++ rebuild needed). Two real bugs were found and fixed while building it (documented inline in WebSocket.js/WebSocket-internal.py's own docstrings): - A race between the 'open' event firing and send/close functions being available, since real clients often send their first message immediately on 'open'. - engine.io-client's real WS transport unconditionally calling `this.ws._socket.unref()` (a Node `ws`-library-shaped assumption that doesn't hold for a browser-style WebSocket), worked around with a harmless no-op `_socket` property. This alone doesn't change any existing behavior - dcp-client's platform check still needs its pythonmonkey exclusion relaxed on its own side for anything to actually use this. Verified via a real end-to-end DCP job (job.exec(), real network dispatch to the demo/dcp compute group) after also relaxing that check locally. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
pythonmonkey has never had a
WebSocketimplementation. dcp-client's ownSocketIOTransport.buildOptions()explicitly special-cases this — every platform except pythonmonkey getstransports: ['websocket', 'polling']and upgrades to a persistent WebSocket within the first round trip or two; pythonmonkey is hard-restricted to['polling']forever. That forces pythonmonkey to be the only client that ever sustains HTTP long-polling for an entire connection's lifetime against services like DCP's package manager — a code path essentially unexercised by any other real client, where a real, reproducible session-routing bug lives (confirmed independent of pythonmonkey/dcp-client with plaincurl,aiohttp, and Nodehttps).Rather than work around that bug, this gives pythonmonkey a real
WebSocket— a JS class matching the DOM API (builtin_modules/WebSocket.js), backed by a Pythonaiohttp-based implementation (builtin_modules/WebSocket-internal.py), following the exact existing patternXMLHttpRequestalready uses (loaded dynamically viarequire(), no C++ rebuild needed).Two real bugs were found and fixed while building it (documented inline in both files' own docstrings — read those for the reasoning):
'open'event firing andsend/closefunctions being available (real clients, dcp-client included, often send their first message immediately onopen).engine.io-client's realWStransport unconditionally callingthis.ws._socket.unref()— a Nodews-library-shaped assumption that doesn't hold for a browser-styleWebSocket— worked around with a harmless no-op_socketproperty.This alone doesn't change any existing behavior —
dcp-client's platform check still needs its pythonmonkey exclusion relaxed on its own side (a separate, dcp-client-side change, not part of this PR) before anything actually uses this.Test plan
job.exec(), real network dispatch to thedemo/dcpcompute group) after also relaxing dcp-client's platform check locally — real WebSocket connection, real job completion.Note on authorship
Largely produced by Claude (Anthropic's Claude Code) working under my direction. Flagging this since it hasn't had a second human reviewer yet.
🤖 Generated with Claude Code