12.7. Зворотні виклики каналу¶
Об’єкт бекенду, переданий до protocol.register(), є класом Python. Бібліотека протоколу не запитує клас про те, які методи він реалізує; вона перевіряє екземпляр і підключає ті, які знаходить. Саме ця інтроспекція робить інтерфейс бекенду гнучким: найменший корисний бекенд складається з двох методів, найбільш розгорнутий – з дванадцяти, а застосунок підключається до кожної можливості по одному методу за раз.
12.7.1. Правила інтроспекції¶
Коли protocol.register() виконується, бібліотека проходить фіксований список викликуваних імен і прив’язує кожне, яке знаходить на екземплярі бекенду:
Додавання
readдо класу вмикаєCHANNEL_FLAG_READ. Виклик хоста доchannel_read()досягає бекенду лише якщо цей прапор встановлено.Додавання
writeвмикаєCHANNEL_FLAG_WRITE, дозволяючиchannel_write().Додавання
lockтаunlockвмикаєCHANNEL_FLAG_LOCK, дозволяючи хосту заблокувати канал для атомарного зчитування з кількох пакетів.Додавання
pollдозволяє хосту дешево запитати «чи є щось готове?», без необхідності виконувати повне зчитування.
Відсутні методи не є помилками – бібліотека протоколу просто залишає відповідну можливість вимкненою. Бекенд лише з size та read є цілком допустимим; це канал даних лише для читання.
12.7.2. Канал датчика лише для читання¶
Канал датчика, який публікує нові показники кожного разу, коли хост запитує, відхиляючи запити на запис від хоста, задіює чотири зворотні виклики:
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))
Розглянемо, що робить кожен метод:
pollповертає прапор актуальності. Хост викликає його перед зчитуванням і пропускає зчитування, якщо він повертаєFalse. Це економить витрати на зворотний зв’язок у разі «нових даних ще немає».sizeрегенерує буфер на вимогу і повідомляє його довжину. Виконання вимірювання тут означає, що бекенду не потрібне фонове завдання – кожен виклик хоста ініціює нове вимірювання.readповертає зріз буфера. Бібліотека протоколу може викликати його кілька разів, якщо буфер більший за узгоджений максимальний розмір корисного навантаження; аргументoffsetпроходить по фрагментах.Відсутність
writeозначає, що запис від хоста відхиляється на рівні кадрування, до залучення бекенду.
12.7.3. Повний набір зворотних викликів¶
Для довідки – кожен метод, який бібліотека шукає на бекенді:
Метод |
Повертає |
Призначення |
|---|---|---|
|
object |
Необов’язкова одноразова ініціалізація, коли канал вперше прив’язується до хоста. Поверніть будь-яке значення, відмінне від |
|
bool |
Повертає |
|
bool |
Захоплює канал для атомарного багатопакетного передавання. |
|
bool |
Звільняє попередньо встановлений |
|
int |
Кількість байтів, доступних для зчитування з каналу на поточний момент. |
|
tuple |
До чотирьох цілих чисел, що описують структуру даних (наприклад, висота зображення, ширина, кількість байтів). Використовується хостом для розпакування типізованих буферів. |
|
bytes |
Повертає до size байтів починаючи з offset. Викликається по одному разу на фрагмент, коли корисне навантаження перевищує узгоджений максимум. |
|
bytes |
Варіант |
|
int |
Хост записав data за адресою offset. |
|
int |
Код операції, визначений застосунком, поза моделлю читання/запису. Від’ємне повернене значення є помилкою. |
|
object |
Скидає всі буферизовані дані. Викликається, коли хост хоче скинути канал. |
|
bool |
Має значення лише для бекендів, що представляють фізичний транспорт (вбудовані USB-канали). Канали застосунку у цьому не потребують. |
Це повний інтерфейс бекенду. Дванадцять імен методів, усі необов’язкові, і бібліотека протоколу вирішує, що може робити кожен канал, на основі присутніх методів.