10.1. Az első végpontod

Mielőtt a kamera bármi érdekeset csinálhatna, a hálózat többi részének el kell tudnia érni. A legolcsóbb dolog, amely bizonyítja, hogy a szerver él, egy egyetlen útvonalból álló HTTP-végpont, amely némi JSON-t ad vissza:

from microdot import Microdot

app = Microdot()

frame_count = 0
trigger_count = 0

@app.get('/status')
async def status(request):
    return {'frames': frame_count, 'triggers': trigger_count}

app.run(host='0.0.0.0', port=80)

Futtasd az IDE-ben. A LAN bármely másik gépéről nyisd meg a http://<cam-ip>/status címet. A böngésző ezt mutatja:

{"frames": 0, "triggers": 0}

A számlálók helykitöltők – még semmi sem nyúl hozzájuk –, de a kérés átment a hálózaton, a kamera továbbította, lefuttatott egy kezelőt, és visszaküldte a JSON-t.

10.1.1. Mit csinál az egyes sorok

Szkriptenként egyetlen microdot.Microdot példány. A példányé az útválasztó tábla, a hibakezelők és az életciklus (indítás, kiszolgálás, leállítás). A nagy alkalmazások több Python-modulra oszlanak, de továbbra is egyetlen app objektumon osztoznak.

Az @app.get('/status') az útvonal-dekorátor. Itt csak a microdot.Microdot.get() metódust használjuk; a post(), a put() és a delete() később, a kamera írásműveleteit tárgyaló oldalakon jelenik meg.

Minden útvonalkezelő egy asyncio coroutine, és a kérést kapja meg első argumentumként. A kezelőnek nem kell használnia a request-et – ez itt figyelmen kívül hagyja –, de a paraméter mindig jelen van, így a szignatúra egységes.

Egy dict visszaadása a legrövidebb módja a JSON küldésének. A Microdot automatikusan JSON-ná szerializálja a dict-et, és beállítja a Content-Type: application/json fejlécet a válaszban. Egy string visszaadása text/plain típust küld. Egy microdot.Response explicit visszaadása a hosszú forma – akkor van rá szükség, ha a törzs bináris, vagy ha a válaszhoz egyedi fejlécek kellenek.

Az app.run(host='0.0.0.0', port=80) indítja el a szervert. A 0.0.0.0 azt jelenti, hogy figyelj a kamera minden interfészén – mind a vezetékes ethernet, mind a wifi STA esetén, ha mindkettő fent van. A 80-as port a HTTP alapértelmezése, így a böngészőknek nem kell portszámot beírniuk.

10.1.2. Egy kérés, elejétől a végéig

A telefon megnyit egy TCP-kapcsolatot a kamera felé, küld egy HTTP- kérést, a kamera elemzi, útválasztja, lefuttatja a kezelőt, majd visszaír egy választ.

A telefon megnyit egy TCP-kapcsolatot, kiírja a kérés sorát és fejléceit, majd vár. A kamera kiolvassa a bájtokat a socketről, microdot.Request objektummá elemzi őket, illeszti az útvonalat és a metódust az útválasztó táblához, megvárja a kezelő coroutine-t, szerializálja, amit visszaadott, kiír egy állapotsort, fejléceket és törzset a socketre, majd lezárja a kapcsolatot (HTTP/1.0 alapértelmezés) vagy újrahasznosítja (HTTP/1.1 a Connection: keep-alive fejléccel). Az egész csere nagyjából annyi ideig tart, mint a hálózati körbefordulás plusz amit a kezelő végzett.

10.1.3. Megjegyzés a blokkolásról

A run() blokkoló – soha nem tér vissza, amíg a szerver le nem áll. Ez rendben van egyetlen célt szolgáló szervernél. Egy olyan alkalmazás, amely képkockákat is rögzít vagy más coroutine-okat is futtat, helyette a start_server() metódust használja egy asyncio.run() belsejében, így a HTTP-szerver megoszthatja az eseményhurkot minden mással.

Az alkalmazás egyetlen URL-re válaszol.