microdot.websocket — obsługa WebSocket

WebSockety to dwukierunkowe, trwałe połączenie poprzez HTTP – po uzgodnieniu uaktualnienia (handshake) klient i serwer wysyłają oraz odbierają ramkowane komunikaty na tym samym gnieździe. Używaj ich, gdy kamera i aplikacja po stronie przeglądarki potrzebują ruchu w trybie pełnego dupleksu, którego SSE (jednokierunkowe wypychanie) ani zwykłe odpytywanie HTTP nie zapewnią tanim kosztem.

class WebSocket

class microdot.websocket.WebSocket(request)

Uchwyt, który otrzymuje trasa. Przekazywany do procedur obsługi jako drugi argument, gdy używany jest with_websocket(); nie konstruuj go bezpośrednio.

Atrybuty klasy

max_message_length: int

Maksymalny rozmiar ładunku, jaki zaakceptuje receive(). Komunikaty większe niż ten powodują zgłoszenie WebSocketError i zamknięcie połączenia. 0 wyłącza tę kontrolę (miej świadomość ataków polegających na wyczerpaniu pamięci, jeśli to ustawisz). -1 (wartość domyślna) używa Request.max_body_length.

CONT: int

Opcode ramki kontynuacji, 0x0. Oznacza ramkę kontynuującą ładunek poprzedniej ramki tego samego komunikatu. Microdot sam nie generuje ramek kontynuacji (każdy komunikat jest wysyłany jako pojedyncza ramka) i odrzuca je przy odbiorze, ale stała jest udostępniona dla aplikacji implementujących własne ramkowanie.

TEXT: int

Opcode ramki tekstowej, 0x1. Opcode, który send() wybiera automatycznie, gdy data jest typu str; ładunek jest przy wysyłaniu kodowany w UTF-8.

BINARY: int

Opcode ramki binarnej, 0x2. Opcode, który send() wybiera automatycznie, gdy data jest typu bytes / bytearray; ładunek jest wysyłany dosłownie.

CLOSE: int

Opcode ramki zamknięcia, 0x8. Wysyłany przez close(); jego odebranie powoduje zgłoszenie WebSocketError („Websocket connection closed”) z receive().

PING: int

Opcode ramki ping, 0x9. Microdot automatycznie odpowiada na przychodzące pingi pasującym PONG wewnątrz receive(); aplikacja zwykle ich nie obserwuje.

PONG: int

Opcode ramki pong, 0xA. Wysyłany automatycznie w odpowiedzi na PING. Przychodzące pongi są po cichu odrzucane.

Atrybuty instancji

request: microdot.Request

Źródłowy microdot.Request – ten sam obiekt, który otrzymała procedura obsługi trasy.

closed: bool

True, gdy close() zostało już wykonane. Sprawdzaj, aby uniknąć podwójnego zamknięcia w ścieżkach sprzątających.

Metody

async receive()

Czeka na następny komunikat od klienta i zwraca go. Typ zwracany odpowiada opcode’owi ramki: str dla ramek tekstowych, bytes dla ramek binarnych. Na ramki ping odpowiada się automatycznie ramką pong; ramki pong są po cichu odrzucane; ramka close powoduje zgłoszenie WebSocketError („Websocket connection closed”).

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

Wysyła data do klienta. Łańcuchy znaków są wysyłane jako ramki tekstowe, bajty jako ramki binarne; przekaż opcode jawnie, aby to nadpisać.

async close()

Wysyła ramkę zamknięcia i oznacza połączenie jako zamknięte. Wywoływane automatycznie, gdy kończy się wrapper with_websocket().

class WebSocketError

exception microdot.websocket.WebSocketError

Zgłaszany wewnątrz WebSocket.receive(), gdy połączenie się kończy lub gdy protokół zostaje naruszony. Użyj go w trasie, aby wykrywać normalne rozłączenia klienta:

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

Dekoratory na poziomie modułu

microdot.websocket.with_websocket(f)

Dekorator, który zamienia trasę w punkt końcowy WebSocket. Procedura obsługi otrzymuje żądanie oraz obiekt 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)

Czas życia procedury obsługi jest równy czasowi życia połączenia. Powrót, zgłoszenie wyjątku lub rozłączenie klienta poprawnie zamyka WebSocket.

async microdot.websocket.websocket_upgrade(request)

Niskopoziomowa funkcja pomocnicza uaktualnienia. Użyj jej wewnątrz trasy, gdy uaktualnienie powinno nastąpić warunkowo – np. dopiero po pomyślnym przejściu kontroli autoryzacji:

@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())

Zwraca uaktualniony WebSocket. Procedura obsługi musi zwrócić microdot.Response.already_handled (lub zgłosić wyjątek), gdy zakończy pracę – microdot przejął już kontrolę nad gniazdem.

Implementacja obsługuje standardowe opcode’y tekstowe i binarne, ping / pong oraz czyste zamknięcie. Pofragmentowane ramki (kontynuacji) nie są obsługiwane – każdy komunikat jest wysyłany jako pojedyncza ramka, co jest odpowiednie dla typowych aplikacji kamerowych operujących małymi komunikatami.