Skip to content

blackbull.client.websocket

blackbull.client.websocket

WebSocket client (RFC 6455).

Two pieces:

  • WebSocketClient opens a TCP/TLS connection and drives the HTTP/1.1 Upgrade: websocket handshake.
  • WebSocketSession, returned by WebSocketClient.connect, owns the post-handshake frame loop: send_text / send_bytes / receive / ping / close.

Reuses HTTP1RequestSender / HTTP1ResponseRecipient for the handshake and encode_frame(mask=True) / WebSocketRecipient(require_masked=False) for post-handshake frames — the same codec serves both directions, parameterised by the mask flag.

WebSocketClient

Async WebSocket client.

Use as an async context manager::

async with WebSocketClient('localhost', 8000) as c:
    ws = await c.connect('/path', subprotocols=[b'chat'])
    await ws.send_text('hello')
    msg = await ws.receive()
    await ws.close()

The transport is held open between connect() and __aexit__; only one concurrent session per WebSocketClient is supported.

connect(path, *, subprotocols=()) async

Run the HTTP/1.1 Upgrade: websocket handshake on this connection.

Returns a WebSocketSession once the server has confirmed the upgrade with HTTP 101 and a valid Sec-WebSocket-Accept header. Raises HandshakeError on any handshake-time failure.

WebSocketSession

Frame-level WebSocket session over an established connection.

Always masks outgoing frames (RFC 6455 §5.1). Reads use WebSocketRecipient(require_masked=False) because servers MUST NOT mask their outgoing frames.

receive() async

Read one ASGI websocket.* event from the connection.

Returns one of
  • {'type': 'websocket.receive', 'text': str, 'bytes': None}
  • {'type': 'websocket.receive', 'text': None, 'bytes': bytes}
  • {'type': 'websocket.disconnect', 'code': int}

Server-initiated PING frames are auto-PONGed by the underlying WebSocketRecipient (with masking, since this session is the client). Server PONG frames are silently dropped.