WebSocketThe RFC 6455 accept token for a key — what an upgrade response must echo. Class-side so a Quoin SERVER can compute it too.
Open a WebSocket to a ws:// or wss:// URL: connect (TLS for wss), send the HTTP/1.1 upgrade with a random Sec-WebSocket-Key, and VERIFY the 101 response's Sec-WebSocket-Accept (base64(sha1(key + GUID))) — a wrong status or accept throws an IoError.
Internal: 'ws(s)://host[:port]/path?query' -> #( secure host port path ).
Close with code 1000 (normal). See close:reason:.
Run the close handshake: send a close frame, then drain incoming frames until the far side's close reply (data still in flight is discarded). Idempotent; a connection torn mid-handshake still ends closed. Returns nil.
The close code the far side sent (1005 when its close frame carried none), or nil while open.
The close reason text (possibly ''), or nil while open.
Whether the connection has closed (cleanly or by error).
Loop receive into the block until the connection closes; answers self.
A close frame arrived: record code/reason, echo the close unless we already sent ours, and tear down. Answers nil (receive's close answer).
Internal.
Send a ping (the far side must pong; incoming pings are answered automatically inside receive). Answers self.
A ping carrying a payload (String or Bytes, <= 125 bytes).
One frame off the wire: #( fin opcode payload ). Server frames must be unmasked; reserved bits mean an extension we never negotiated.
The next message: a String for a text frame, Bytes for binary — or nil once the connection closes cleanly. Fragmented messages are reassembled; pings are ponged and pongs ignored, invisibly. Parks the task while waiting. A connection torn without a close frame throws an IoError.
Send a binary message. Answers self.
Mask and send one frame (fin always set — we never fragment sends).
Send a text message (one frame, masked). Answers self.
The URL this socket connected to.