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.