duck.contrib.websockets¶
Duck WebSocket Implementation.
In your urlpatterns, you can use websocket protocol as follows:
# urls.py
from duck.urls import path
from duck.contrib.websockets import WebSocketView, OpCode
class MyWebSocket(WebSocketView):
async def on_open(self):
print("WebSocket connection established")
async def on_receive(data, opcode: int):
if opcode == OpCode.TEXT:
message = "Client sent " + data.decode("utf-8")
await self.send_text(message)
else:
# Handle binary here
pass
# Now create a urlpattern entry
urlpatterns = [
path("/ws/myws", MyWebSocket, name="mywebsocket"),
# other patterns here.
]
Submodules¶
Package Contents¶
Classes¶
Int enum of connection state. |
|
RFC 7692-compliant WebSocket view with permessage-deflate compression, context takeover negotiation, heartbeat, fragmentation handling, partial streaming of large frames, and robust error handling. |
API¶
- class duck.contrib.websockets.State¶
Bases:
enum.IntEnumInt enum of connection state.
Initialization
Initialize self. See help(type(self)) for accurate signature.
- CLOSED¶
0
- INITIATED¶
2
- INITIATING¶
None
- OPEN¶
1
- class duck.contrib.websockets.WebSocketView(upgrade_request: duck.http.request.HttpRequest, **kwargs)¶
Bases:
duck.views.ViewRFC 7692-compliant WebSocket view with permessage-deflate compression, context takeover negotiation, heartbeat, fragmentation handling, partial streaming of large frames, and robust error handling.
Features:
Supports WebSocket upgrade handshake with version checks.
Negotiates permessage-deflate compression extension with context takeover flags.
Sends and receives WebSocket frames with optional compression.
Implements ping/pong heartbeat with exponential backoff and failure detection.
Handles fragmented message reassembly.
Ensures all task exceptions in heartbeat and receive loops are properly re-raised.
Cleanly closes connections and releases resources.
Initialization
Initialize the WebSocketView with the initial HTTP upgrade request.
- Parameters:
upgrade_request – The HTTP request that initiated the WebSocket upgrade.
**kwargs – Additional keyword arguments passed to subclasses.
Initializes internal state for compression, heartbeat, fragmentation, and communication queues.
- MAGIC_STRING¶
‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’
str: Magic string for generating Sec-WebSocket-Accept-Key.
- MAX_BACKOFF¶
45
int: Maximum exponential backoff delay in seconds.
- MAX_FRAME_SIZE¶
None
int: Maximum allowed size of incoming message frame in bytes (1MB).
- PING_INTERVAL¶
20
int: Seconds between sending ping frames.
- PONG_TIMEOUT¶
10
int: Seconds to wait for a pong response.
- RECEIVE_TIMEOUT¶
120
int: Timeout in seconds for receiving WebSocket frames.
- async _heartbeat_loop()¶
Periodically send ping frames and verify pong responses.
Uses exponential backoff on missed pong frames. Raises TimeoutError after three consecutive failures.
- Raises:
TimeoutError – If pong not received within timeout multiple times.
Exception – Propagates other exceptions from send_ping or sleep.
- async _receive_loop()¶
Continuously reads frames from the client, handles control frames, reassembles fragmented messages, and dispatches complete messages to the handler.
- Raises:
Exception – Propagates exceptions from socket read or processing.
- get_sec_accept_key(sec_websocket_key: str) str¶
Generates the Sec-WebSocket-Accept key for the handshake response.
- Parameters:
sec_websocket_key – Sec-WebSocket-Key header value.
- Returns:
Base64-encoded SHA-1 hash of the client’s Sec-WebSocket-Key and the magic string.
- Return type:
str
- async initiate_upgrade_to_ws() bool¶
Perform the WebSocket handshake and send upgrade response to client.
Negotiates permessage-deflate compression extension and context takeover parameters per RFC 7692 if supported by the client.
- Returns:
True if handshake and upgrade succeeded, False otherwise.
- Return type:
bool
- async on_close(frame: duck.contrib.websockets.frame.Frame = None)¶
Called when the WebSocket connection is closed.
Override to implement cleanup logic but make sure to call
safe_close(call_on_close_handler=False)to actually close the connection.- Parameters:
frame – Close frame if the client sent a close frame.
- async on_new_frame(frame: duck.contrib.websockets.frame.Frame)¶
Handles the new frame by parsing it to
on_receive.
- async on_open()¶
Called on WebSocket open.
- abstractmethod async on_receive(message: bytes, opcode, **kwargs)¶
Called when a full WebSocket message is received.
Should be overridden by subclasses to implement message handling.
- Parameters:
message – Message payload.
opcode – Message opcode.
- async read_frame() duck.contrib.websockets.frame.Frame¶
Read a single WebSocket frame from the client.
Handles masking and permessage-deflate decompression.
- Returns:
The parsed frame.
- Return type:
- Raises:
ProtocolError – If the frame format is invalid.
PayloadTooBig – If the payload exceeds max_size.
- async run() None¶
Entry point for executing the WebSocket view.
This method runs the view’s main event loop (
run_forever). It is expected thatrun_forevernever returns under normal operation. If it does return without raising an exception, anExpectingNoResponseerror is raised, indicating an unexpected termination.- Raises:
ExpectingNoResponse – If
run_forevercompletes without raising an exception.Exception – Any exception raised during the execution of
run_forever.
- async run_forever()¶
Run the WebSocket connection until closed or error occurs.
Starts asynchronous tasks for heartbeat ping/pong and receiving frames. Waits until one of the tasks completes or raises an exception.
Exceptions raised inside heartbeat or receive loops are re-raised here.
Upon exit, calls
safe_closeto clean up resources.
- async safe_close(disable_logging: bool = False, call_on_close_handler: bool = True)¶
Safely close the WebSocket connection and invoke
on_closecallback.Ensures close logic is only run once.
- Parameters:
disable_logging – Disables logging even on first attempt.
call_on_close_handler – Whether to call
on_closemethod before closing.
- async send(data: Union[str, bytes], opcode: int = OpCode.TEXT)¶
Alias to send a WebSocket message frame.
- Parameters:
data – Payload data.
opcode – WebSocket frame opcode. Defaults to 0x1 (TEXT).
- async send_binary(data: bytes)¶
Send binary data as a WebSocket message.
- Parameters:
data – Raw bytes to send.
- async send_close(code: int = CloseCode.NORMAL_CLOSURE, reason: str = '')¶
Send a close control frame and initiate connection close.
This is failsafe, meaning it just fails silently.
- Parameters:
code – WebSocket close status code. Defaults to 1000 (Normal Closure).
reason – Optional close reason string.
- async send_frame(frame: duck.contrib.websockets.frame.Frame)¶
Sends a frame to the client, first it applies all negotiated extensions received upon upgrare and then it sends the frame to the connected client socket.
- async send_json(data: Union[dict, list])¶
Serialize a Python object to JSON and send as a text message.
- Parameters:
data – Python data to serialize.
- async send_ping(data: bytes = b'')¶
Send a ping control frame.
- Parameters:
data – Optional ping payload.
- async send_pong(data: bytes = b'')¶
Send a pong control frame.
- Parameters:
data – Optional pong payload.
- async send_text(data: str)¶
Send a text WebSocket message.
- Parameters:
data – Text message to send.
- property server¶
- property sock¶
Returns the connected socket.
- strictly_async()¶