microdot.sse — Server-Sent Events

Server-Sent Events (SSE) is een eenvoudig eenrichtings-pushprotocol: de client opent een normaal HTTP-request naar Content-Type: text/event-stream, en de server houdt de verbinding open en schrijft geformatteerde events zodra ze plaatsvinden. De browser stelt de stream beschikbaar als een JavaScript EventSource-object. Vergeleken met WebSockets is SSE eenvoudiger wanneer alleen de server pusht; de client doet altijd het verzoek.

Het typische cameragebruik is het publiceren van detecties / sensoraflezingen / statusupdates naar een telefoon of dashboard met de snelheid waarmee ze plaatsvinden, zonder dat het dashboard hoeft te pollen.

class SSE

class microdot.sse.SSE

De handle die de route ontvangt. Wordt als tweede argument aan handlers doorgegeven wanneer with_sse() in gebruik is.

async send(data, event: str | None = None, event_id: str | None = None, retry: int | None = None, comment: bool = False)

Push een enkel event naar de client.

data

De event-payload. Strings en bytes worden as-is verzonden. Dicts en lists worden geserialiseerd naar JSON. Al het andere wordt geconverteerd met str().

event

Optionele eventnaam – de EventSource van de browser dispatcht naar een JavaScript-listener met dezelfde naam wanneer dit is ingesteld.

event_id

Optionele event-id – de browser stuurt deze terug als Last-Event-ID als de verbinding wegvalt en opnieuw verbinding maakt, waardoor de server kan hervatten waar hij was gebleven.

retry

Vertraging voor opnieuw verbinden in seconden; de browser gebruikt dit als de verbinding wegvalt.

comment

Indien True wordt de payload verzonden als een SSE-commentaarregel (genegeerd door de browser). Handig als keep-alive-hartslag om te voorkomen dat NAT-timeouts een verder inactieve stream sluiten.

Decorators op moduleniveau

microdot.sse.with_sse(f)

Decorator die een route omzet in een SSE-endpoint. De handler ontvangt het request en een SSE-object:

from microdot import Microdot
from microdot.sse import with_sse

app = Microdot()

@app.get('/events')
@with_sse
async def events(request, sse):
    import asyncio
    while True:
        await sse.send({'temp': read_sensor()}, event='reading')
        await asyncio.sleep(1)

De levensduur van de handler is gelijk aan de levensduur van de stream – hij draait zolang de client verbonden blijft. Annulering (de client verbreekt de verbinding, de server sluit af) propageert als asyncio.CancelledError, die het framework opvangt.

microdot.sse.sse_response(request, event_function, *args, **kwargs)

Laag-niveau-ingang: geeft de respons-tuple terug die with_sse() onder de motorkap teruggeeft. Handig wanneer een SSE-endpoint aangepaste headers of statuscodes nodig heeft die de decorator niet toestaat:

from microdot.sse import sse_response

@app.get('/events')
async def events(request):
    if not request.g.current_user:
        return 401
    async def emit(req, sse):
        await sse.send('hello')
    return sse_response(request, emit)

event_function neemt (request, sse, *args, **kwargs) en gebruikt await sse.send(...) om events te pushen.

De SSE-respons stelt Content-Type: text/event-stream in en houdt de verbinding open totdat event_function terugkeert of de client de verbinding verbreekt. Gebruik een while True-lus met een await asyncio.sleep tussen verzendingen om hot-looping te voorkomen.