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

State

Int enum of connection state.

WebSocketView

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.IntEnum

Int 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.View

RFC 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:

Frame

Raises:
async run() None

Entry point for executing the WebSocket view.

This method runs the view’s main event loop (run_forever). It is expected that run_forever never returns under normal operation. If it does return without raising an exception, an ExpectingNoResponse error is raised, indicating an unexpected termination.

Raises:
  • ExpectingNoResponse – If run_forever completes 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_close to clean up resources.

async safe_close(disable_logging: bool = False, call_on_close_handler: bool = True)

Safely close the WebSocket connection and invoke on_close callback.

Ensures close logic is only run once.

Parameters:
  • disable_logging – Disables logging even on first attempt.

  • call_on_close_handler – Whether to call on_close method 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()