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.