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-канали). Канали застосунку у цьому не потребують. |
Це повний інтерфейс бекенду. Дванадцять імен методів, усі необов’язкові, і бібліотека протоколу вирішує, що може робити кожен канал, на основі присутніх методів.