10.1. Vaša prva krajnja točka

Prije nego kamera može učiniti išta zanimljivo, ostatak mreže mora moći doprijeti do nje. Najjeftinija stvar koja dokazuje da je poslužitelj živ jest HTTP krajnja točka s jednom rutom koja vraća nešto JSON-a:

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)

Pokrenite je u IDE-u. S bilo kojeg drugog računala na LAN-u otvorite http://<cam-ip>/status. Preglednik prikazuje:

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

Brojači su rezervirana mjesta – ništa ih još ne dira – ali zahtjev je prešao mrežu, kamera ga je usmjerila, pokrenula rukovatelj i poslala JSON natrag.

10.1.1. Što svaki redak radi

Jedna instanca microdot.Microdot po skripti. Instanca posjeduje tablicu usmjeravanja, rukovatelje pogreškama i životni ciklus (pokretanje, posluživanje, zaustavljanje). Velike aplikacije dijele se na više Python modula, ali i dalje dijele jedan app objekt.

@app.get('/status') je dekorator rute. Ovdje koristimo samo microdot.Microdot.get(); post(), put() i delete() pojavljuju se na kasnijim stranicama kada kamera počne prihvaćati upise.

Svaki rukovatelj rute je asyncio korutina i prima zahtjev kao svoj prvi argument. Rukovatelj ne mora koristiti request – ovaj ga ignorira – ali parametar je uvijek tu pa je potpis dosljedan.

Vraćanje rječnika (dict) najkraći je način slanja JSON-a. Microdot automatski serijalizira rječnik u JSON i postavlja Content-Type: application/json na odgovoru. Vraćanje niza znakova šalje text/plain. Eksplicitno vraćanje microdot.Response dugi je oblik – potreban kada je tijelo binarno ili kada odgovor zahtijeva prilagođena zaglavlja.

app.run(host='0.0.0.0', port=80) pokreće poslužitelj. 0.0.0.0 znači slušaj na svakom sučelju koje kamera ima – i žičanom ethernetu i wifi STA, ako su oba aktivna. Vrata 80 zadana su za HTTP, pa preglednici ne moraju upisivati broj vrata.

10.1.2. Jedan zahtjev, od početka do kraja

The phone opens a TCP connection to the cam, sends an HTTP request, the cam parses, routes, runs the handler, then writes a response back.

Telefon otvara TCP vezu, zapisuje redak zahtjeva i zaglavlja te čeka. Kamera čita bajtove sa socketa, raščlanjuje ih u microdot.Request objekt, uspoređuje putanju i metodu s tablicom usmjeravanja, čeka korutinu rukovatelja (await), serijalizira što god je ona vratila, zapisuje redak statusa, zaglavlja i tijelo natrag kroz socket, a zatim zatvara vezu (zadano HTTP/1.0) ili je reciklira (HTTP/1.1 s Connection: keep-alive). Cijela razmjena traje otprilike koliko mrežni put naprijed-natrag plus što god je rukovatelj učinio.

10.1.3. Napomena o blokiranju

run() blokira – nikada se ne vraća dok se poslužitelj ne zaustavi. To je u redu za poslužitelj s jednom svrhom. Aplikacija koja također snima sličice ili pokreće druge korutine umjesto toga koristi start_server() unutar asyncio.run(), kako bi HTTP poslužitelj mogao dijeliti petlju sa svime ostalim.

Aplikacija odgovara na jedan URL.