microdot.websocket — поддержка WebSocket

WebSocket – это двустороннее постоянное соединение поверх HTTP: после рукопожатия с переходом на новый протокол клиент и сервер отправляют и принимают сообщения в виде кадров через один и тот же сокет. Используйте их, когда камере и приложению на стороне браузера требуется полнодуплексный трафик, который SSE (односторонняя отправка) и обычный опрос по HTTP не могут обеспечить дёшево.

class WebSocket

class microdot.websocket.WebSocket(request)

Объект-обработчик, который получает маршрут. Передаётся обработчикам в качестве второго аргумента, когда используется with_websocket(); не создавайте его напрямую.

Атрибуты класса

max_message_length: int

Максимальный размер полезной нагрузки, который примет receive(). Сообщения больше этого значения вызывают WebSocketError и закрывают соединение. 0 отключает проверку (учитывайте атаки с исчерпанием памяти, если устанавливаете это значение). -1 (по умолчанию) использует Request.max_body_length.

CONT: int

Опкод кадра продолжения, 0x0. Помечает кадр, который продолжает полезную нагрузку предыдущего кадра того же сообщения. Microdot сам не генерирует кадры продолжения (каждое сообщение отправляется как один кадр) и отклоняет их при приёме, но константа предоставляется для приложений, реализующих собственную фрагментацию.

TEXT: int

Опкод текстового кадра, 0x1. Опкод, который send() выбирает автоматически, когда data является str; при отправке полезная нагрузка кодируется в UTF-8.

BINARY: int

Опкод бинарного кадра, 0x2. Опкод, который send() выбирает автоматически, когда data является bytes / bytearray; полезная нагрузка отправляется без изменений.

CLOSE: int

Опкод кадра закрытия, 0x8. Отправляется методом close(); при получении такого кадра receive() вызывает WebSocketError («Websocket connection closed»).

PING: int

Опкод ping-кадра, 0x9. Microdot автоматически отвечает на входящие ping-кадры соответствующим PONG внутри receive(); обычно приложение их не замечает.

PONG: int

Опкод pong-кадра, 0xA. Отправляется автоматически в ответ на PING. Входящие pong-кадры молча отбрасываются.

Атрибуты экземпляра

request: microdot.Request

Исходный объект microdot.Request – тот же объект, который получил обработчик маршрута.

closed: bool

True после того, как был выполнен close(). Проверяйте, чтобы избежать повторного закрытия в путях очистки.

Методы

async receive()

Ожидает и возвращает следующее сообщение от клиента. Тип возвращаемого значения соответствует опкоду кадра: str для текстовых кадров, bytes для бинарных кадров. На ping-кадры автоматически отвечается pong; pong-кадры молча отбрасываются; close-кадр вызывает WebSocketError («Websocket connection closed»).

async send(data, opcode: int | None = None)

Отправляет data клиенту. Строки отправляются как текстовые кадры, байты – как бинарные кадры; передайте opcode явно, чтобы переопределить это поведение.

async close()

Отправляет кадр закрытия и помечает соединение как закрытое. Вызывается автоматически при выходе из обёртки with_websocket().

class WebSocketError

exception microdot.websocket.WebSocketError

Вызывается внутри WebSocket.receive(), когда соединение завершается или нарушается протокол. Используйте это в маршруте для обнаружения обычных отключений клиента:

try:
    message = await ws.receive()
except WebSocketError:
    # client closed the connection

Декораторы уровня модуля

microdot.websocket.with_websocket(f)

Декоратор, превращающий маршрут в конечную точку WebSocket. Обработчик получает запрос и объект WebSocket:

from microdot import Microdot
from microdot.websocket import with_websocket

app = Microdot()

@app.get('/echo')
@with_websocket
async def echo(request, ws):
    while True:
        msg = await ws.receive()
        await ws.send(msg)

Время жизни обработчика равно времени жизни соединения. Возврат, исключение или отключение клиента корректно закрывают WebSocket.

async microdot.websocket.websocket_upgrade(request)

Низкоуровневый помощник для перехода на новый протокол. Используйте его внутри маршрута, когда переход должен происходить условно – например, только после успешной проверки авторизации:

@app.get('/private')
async def private(request):
    if not authenticate(request):
        abort(401)
    ws = await websocket_upgrade(request)
    while True:
        msg = await ws.receive()
        await ws.send(msg.upper())

Возвращает обновлённый объект WebSocket. Обработчик должен вернуть microdot.Response.already_handled (или вызвать исключение) после завершения работы – microdot уже взял управление сокетом на себя.

Реализация поддерживает стандартные текстовые и бинарные опкоды, ping / pong и корректное закрытие. Фрагментированные кадры (кадры продолжения) не поддерживаются – каждое сообщение отправляется как один кадр, что подходит для типичных камерных приложений с небольшими сообщениями.