Open Stream Deck

Архитектура

Как связаны интерфейс, бэкенд на Rust, связь с устройством и плагины.

Приложение состоит из двух больших частей: интерфейса на Preact и бэкенда на Rust. Они обмениваются командами Tauri и событиями. Интерфейс отвечает за состояние профилей и отрисовку, бэкенд за работу с железом и процессами.

Интерфейс

  • src/store.ts загружает и сохраняет состояние в локальное хранилище webview. Ключ состояния версионирован, миграции старых форматов выполняются при загрузке.
  • src/data.ts содержит каталог встроенных модулей и константы: 15 кнопок в сетке, три слота боковой полосы, до 10 страниц.
  • src/deck/ рисует кнопки в буфер, превращает его в команды OSD1 и ставит их в очередь. animator.ts отвечает за анимации, link.ts за связь с бэкендом.
  • src/widgets/ описывает виджеты и их отрисовку.
  • src/plugins/ исполняет плагины и реализует сторону приложения в протоколе SDK:
    • runtime.ts создаёт для каждого плагина скрытый iframe с sandbox="allow-scripts", следит за ним сторожевым таймером и перезапускает после сбоя;
    • harness.ts это код внутри iframe, который запускает воркер плагина и связывает его с приложением через MessagePort;
    • host.ts проверяет команды плагинов, ведёт контексты кнопок и отправляет события;
    • gestures.ts считает tap, longPress и удержание, visuals.ts хранит подписи и картинки, которые нарисовал плагин.
  • src/i18n/ хранит тексты в тройках [ru, en, zh]. Отсутствующий перевод становится ошибкой типов.

Бэкенд

  • deck.rs открывает два HID-дескриптора к устройству. Один поток читает входные отчёты и отправляет события deck-key. Второй собирает команды в отчёты по 1024 байта. Супервизор переподключает устройство и отправляет deck-status, чтобы интерфейс заново передал страницы.
  • firmware.rs переводит устройство в загрузчик, записывает образ и ждёт возврата устройства. Ход записи уходит в интерфейс событием firmware-progress.
  • plugins/mod.rs устанавливает пакеты .opensd через крейт opensd-package и ведёт список плагинов. Код плагинов в процессе бэкенда не исполняется.
  • plugins/files.rs отдаёт файлы плагинов по схеме osd-plugin:// со строгой политикой безопасности и мост /_opensd/inspector.js для страниц настроек.
  • plugins/grants.rs хранит согласие пользователя на разрешения, broker.rs выполняет операции брокеров: loopback, запуск приложений и буфер обмена.
  • plugins/logs.rs пишет журналы плагинов, dev.rs принимает сеансы opensd dev.
  • stats.rs собирает данные для виджетов нагрузки.

Команды Tauri

Основные команды, которые вызывает интерфейс:

КомандаНазначение
deck_statusТекущий статус устройства
deck_sendОтправка потока команд OSD1 с подтверждением записи в USB
firmware_flashЗапись образа прошивки
run_actionВыполнение встроенного действия
plugins_list, plugin_install, plugin_uninstallСписок, установка и удаление плагинов
plugin_permissions_review, _approve, _revokeСогласие на разрешения
plugin_broker, plugin_session_endОперации брокеров и их завершение при остановке плагина
plugin_log, plugin_log_pathЖурнал плагина
plugin_settings_windowОткрытие окна настроек плагина
plugin_dev_enable, plugin_dev_statusРежим разработчика
system_statsДанные для виджетов нагрузки

Поток нажатия

  1. Устройство отправляет входной отчёт с битовой картой кнопок.
  2. Бэкенд превращает изменения в событие deck-key с номером кнопки и состоянием.
  3. Интерфейс находит действие кнопки. Встроенное действие выполняется через run_action. Действие плагина уходит в его воркер событиями keyDown, keyUp и жестами вроде tap.
  4. Плагин отвечает подписью или картинкой. Интерфейс перерисовывает кнопку и отправляет обновлённый поток команд.

Устройство и отрисовка

Все кнопки и боковая полоса рисуются в растр, который потом передаётся в устройство. Страницы кэшируются в SDRAM деки, поэтому переключение страниц не требует полной перезаписи, если содержимое уже лежит в памяти устройства. Подробности протокола в разделе прошивки.