12.7. Callbacky kanálu#
Backend objekt předaný funkci protocol.register() je třída v Pythonu. Knihovna protokolu se třídy neptá, které metody implementuje; prozkoumá instanci a propojí ty, které najde. Právě tato introspekce činí rozhraní backendu flexibilním: nejmenší užitečný backend má dvě metody, ten nejpropracovanější dvanáct, a aplikace si jednotlivé schopnosti zapíná metodu po metodě.
12.7.1. Pravidla introspekce#
Když se spustí protocol.register(), knihovna projde pevný seznam názvů volatelných metod a každou z nich, kterou na instanci backendu najde, naváže:
Přidání metody
readdo třídy zapne příznakCHANNEL_FLAG_READ. Voláníchannel_read()ze strany hostitele dosáhne backendu pouze tehdy, je-li tento příznak nastaven.Přidání metody
writezapne příznakCHANNEL_FLAG_WRITEa umožní takchannel_write().Přidání metod
lockaunlockzapne příznakCHANNEL_FLAG_LOCKa umožní hostiteli uzamknout kanál pro atomické čtení napříč více pakety.Přidání metody
pollumožní hostiteli levně se zeptat „je něco připraveno?“ bez nutnosti vynucovat plné čtení.
Chybějící metody nejsou chyby – knihovna protokolu jednoduše ponechá odpovídající schopnost vypnutou. Backend pouze s metodami size a read je naprosto platný; jde o datový kanál určený jen ke čtení.
12.7.2. Senzorový kanál určený jen ke čtení#
Senzorový kanál, který při každém dotazu hostitele publikuje čerstvé měření a odmítá zápisy ze strany hostitele, využívá čtyři z callbacků:
import protocol
import struct
class TempChannel:
def __init__(self, read_sensor):
self._read_sensor = read_sensor
self._buf = b''
self._fresh = False
def poll(self):
# Tell the host whether a reading is waiting.
return self._fresh
def size(self):
# Sample fresh data on every host-side size query.
value = self._read_sensor()
self._buf = struct.pack('<f', value)
self._fresh = True
return len(self._buf)
def read(self, offset, size):
end = offset + size
if end >= len(self._buf):
self._fresh = False
return self._buf[offset:end]
protocol.register(name='temp', backend=TempChannel(read_temperature))
Projděme si, co každá metoda dělá:
pollvrací příznak čerstvosti dat. Hostitel ji volá před čtením a čtení zcela přeskočí, když vrátíFalse. To šetří náklady na obousměrný přenos při „zatím žádná nová data“.sizena vyžádání znovu vygeneruje buffer a oznámí jeho délku. Provádění odběru vzorků právě zde znamená, že backend nepotřebuje úlohu běžící na pozadí – každé měření řídí volání hostitele.readvrací výřez bufferu. Knihovna protokolu ji může zavolat vícekrát, pokud je buffer větší než vyjednaná maximální užitečná zátěž; argumentoffsetprochází jednotlivými fragmenty.Absence metody
writeznamená, že zápisy ze strany hostitele jsou odmítnuty již na úrovni rámcování, dříve než se zapojí backend.
12.7.3. Kompletní sada callbacků#
Pro referenci uvádíme každou metodu, kterou knihovna na backendu hledá:
Metoda | Vrací | Účel |
|---|---|---|
| object | Volitelná jednorázová inicializace, když se kanál poprvé naváže na hostitele. Při úspěchu vraťte libovolnou hodnotu různou od |
| bool | Vrací |
| bool | Získá kanál pro atomický přenos napříč více pakety. |
| bool | Uvolní předchozí |
| int | Počet bajtů aktuálně čitelných z kanálu. |
| tuple | Až čtyři celá čísla popisující datovou strukturu (např. výšku obrazu, šířku, počet bajtů). Hostitel je používá k rozbalení typovaných bufferů. |
| bytes | Vrací až size bajtů počínaje pozicí offset. Voláno jednou na fragment, když užitečná zátěž překračuje vyjednané maximum. |
| bytes | Varianta metody |
| int | Hostitel zapsal data na pozici offset. |
| int | Aplikací definovaný operační kód mimo model čtení/zápisu. Záporná návratová hodnota značí chybu. |
| object | Zahodí veškerá data uložená v bufferu. Voláno, když chce hostitel kanál resetovat. |
| bool | Smysluplné pouze na backendech, které představují fyzický přenosový kanál (vestavěné USB kanály). Aplikační kanály toto nepotřebují. |
To je celé rozhraní backendu. Dvanáct názvů metod, všechny volitelné, a knihovna protokolu na základě toho, které z nich jsou přítomny, rozhodne, co může každý kanál dělat.