10.1. Ensimmäinen päätepisteesi

Ennen kuin kamera voi tehdä mitään kiinnostavaa, muun verkon on pystyttävä tavoittamaan se. Halvin tapa todistaa, että palvelin on hengissä, on yhden reitin HTTP-päätepiste, joka palauttaa hieman JSON-dataa:

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)

Aja se IDE:ssä. Avaa miltä tahansa muulta lähiverkon koneelta http://<cam-ip>/status. Selain näyttää:

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

Laskurit ovat paikanvaraajia – mikään ei vielä koske niihin – mutta pyyntö ylitti verkon, kamera reititti sen, ajoi käsittelijän ja lähetti JSON-datan takaisin.

10.1.1. Mitä kukin rivi tekee

Yksi microdot.Microdot -instanssi skriptiä kohden. Instanssi omistaa reititystaulun, virheenkäsittelijät ja elinkaaren (käynnistys, palvelu, pysäytys). Suuret sovellukset jaetaan useaan Python-moduuliin, mutta ne jakavat silti yhden app-objektin.

@app.get('/status') on reittidekoraattori. Käytämme tässä vain metodia microdot.Microdot.get(); post(), put() ja delete() tulevat esiin myöhemmillä sivuilla, kun kamera alkaa hyväksyä kirjoituksia.

Jokainen reitin käsittelijä on asyncio-korutiini ja saa pyynnön ensimmäisenä argumenttinaan. Käsittelijän ei ole pakko käyttää request-parametria – tämä jättää sen huomiotta – mutta parametri on aina paikalla, joten allekirjoitus pysyy yhtenäisenä.

Sanakirjan palauttaminen on lyhin tapa lähettää JSON-dataa. Microdot sarjallistaa sanakirjan automaattisesti JSON-muotoon ja asettaa vastaukseen Content-Type: application/json. Merkkijonon palauttaminen lähettää text/plain-tyypin. microdot.Response-objektin nimenomainen palauttaminen on pitkä muoto – tarpeen silloin, kun runko on binäärimuotoa tai kun vastaukseen halutaan mukautettuja otsakkeita.

app.run(host='0.0.0.0', port=80) käynnistää palvelimen. 0.0.0.0 tarkoittaa kuuntele jokaista kameran rajapintaa – sekä langallista ethernetiä että wifi STA:ta, jos molemmat ovat käytössä. Portti 80 on HTTP:n oletus, joten selainten ei tarvitse kirjoittaa porttinumeroa.

10.1.2. Yksi pyyntö, päästä päähän

Puhelin avaa TCP-yhteyden kameraan, lähettää HTTP- pyynnön, kamera jäsentää, reitittää, ajaa käsittelijän ja sitten kirjoittaa vastauksen takaisin.

Puhelin avaa TCP-yhteyden, kirjoittaa pyyntörivin ja otsakkeet ja odottaa. Kamera lukee tavut socketista, jäsentää ne microdot.Request-objektiksi, vertaa polkua ja metodia reititystauluun, odottaa käsittelijäkorutiinia, sarjallistaa sen palauttaman arvon, kirjoittaa tilarivin, otsakkeet ja rungon takaisin socketiin ja sulkee sitten yhteyden (HTTP/1.0:n oletus) tai kierrättää sen (HTTP/1.1 Connection: keep-alive -otsakkeella). Koko vaihto kestää suunnilleen yhtä kauan kuin verkon edestakainen matka plus se, mitä käsittelijä teki.

10.1.3. Huomautus estämisestä

run() on estävä – se ei koskaan palaa ennen kuin palvelin pysähtyy. Se on hyvä yhden tarkoituksen palvelimelle. Sovellus, joka myös kaappaa kehyksiä tai ajaa muita korutiineja, käyttää sen sijaan metodia start_server() asyncio.run()-kutsun sisällä, jotta HTTP-palvelin voi jakaa silmukan kaiken muun kanssa.

Sovellus vastaa yhteen URL-osoitteeseen.