# База прошивок как в SETGUI Это общий сервис **базы файлов прошивок**: получить список опубликованных образов, выбрать изделие/версию/транспорт, скачать файл, проверить SHA-256 и передать его загрузчику. Также можно опубликовать новый образ в эту же базу. Модуль не зависит от версии самого приложения и от `c/firmware-info`. ## Состав | Файл | Ответственность | |---|---| | [`firmware_database.py`](../../python/setprotocol/firmware_database.py) | Готовый HTTPS-клиент, чтение базы, кэш скачанных образов, публикация в Gitea | | [`firmware_catalog.py`](../../python/setprotocol/firmware_catalog.py) | Общий формат записей базы, используемый SETGUI | | [`firmware_publish.py`](../../python/setprotocol/firmware_publish.py) | Метаданные образа, SHA-256, объединение записей каталога | | [`firmware_db.py`](firmware_db.py) | Самостоятельный консольный запуск без SETGUI | Требования: Python 3.10+ и стандартная библиотека. Qt, Windows Credential Manager, установленный SETGUI и библиотеки МК не требуются. Это сервис и CLI; готовое Qt-окно остаётся в SETGUI, а другой GUI подключает сервис по API ниже. ## Как устроена база В текущей конфигурации SETGUI файлы находятся в Gitea Releases репозитория `setcorp/SETRD12-Releases` на `https://git.rd12.ru`. Список файлов лежит в `firmware.releases` файла `update.json` ветки `main`. Запись содержит изделие, версию, транспорт, адрес образа, имя файла, SHA-256, описание и необязательный адрес приложения во Flash. Это файловый каталог; SQL-сервер не нужен. Новый сервис использует тот же JSON-контракт, поэтому выпуски видны клиентам SETGUI, поддерживающим указанный транспорт. В текущем SETGUI транспорт `tms` фильтруется; общий сервис его сохраняет. Публикация не добавляет новый загрузочный протокол в приложение или МК. ```text публикация .hex/.bin → Gitea release asset → скачать и проверить SHA-256 ↓ обновить firmware.releases ↓ GUI: «Обновить каталог» → выбрать запись → «Скачать и выбрать» → загрузчик МК ``` Для своего сервера задайте `server`, `owner`, `repository`, `branch` и `manifest_path`. Репозиторий, ветка и JSON-файл должны уже существовать. Для пустой базы достаточно файла `{"firmware":{"catalogVersion":0,"releases":[]}}`. Если `update.json` общий с обновлениями приложения, его другие разделы сохраняются при добавлении прошивки. ## Консоль: проверить, опубликовать, посмотреть, скачать Из корня `templates` в PowerShell (параметры сервера стоят перед командой): ```powershell $db = @('--server', 'https://git.rd12.ru', '--owner', 'setcorp', '--repo', 'SETRD12-Releases') # Без сети: проверить файл и сформировать запись каталога. python tools/firmware-publish/firmware_db.py @db preflight --file C:/build/device.hex --product MY_DEVICE --version 1.2.3 --version-code 0x010203 --transport can --base-address 0x08003000 # Публикация образа в базу (изменяет сервер). python tools/firmware-publish/firmware_db.py @db publish --file C:/build/device.hex --product MY_DEVICE --version 1.2.3 --version-code 0x010203 --transport can --base-address 0x08003000 # Получить список записей и скачать конкретную. python tools/firmware-publish/firmware_db.py @db list --product MY_DEVICE python tools/firmware-publish/firmware_db.py @db download --product MY_DEVICE --version-code 0x010203 --transport can --cache C:/firmware-cache ``` `MY_DEVICE`, версия, транспорт и адрес — примеры, замените их данными изделия. SCI8 для TMS публикуйте как `.bin` с `--transport tms`, без `--base-address`. Инструмент не конвертирует `.axf/.out` и не проверяет пригодность образа для МК. CLI читает логин и пароль/токен из переменных окружения `FIRMWARE_DB_LOGIN` и `FIRMWARE_DB_PASSWORD`. Задавайте их средствами своего секрет-хранилища/CI, а не в файлах проекта и не в аргументах командной строки. Для интерактивного ввода в PowerShell можно использовать: ```powershell $fwCredential = Get-Credential -Message 'Gitea: логин и пароль либо токен вместо пароля' $env:FIRMWARE_DB_LOGIN = $fwCredential.UserName $env:FIRMWARE_DB_PASSWORD = $fwCredential.GetNetworkCredential().Password # Выполнить нужные команды; после работы убрать переменные из текущего процесса. Remove-Item Env:FIRMWARE_DB_LOGIN, Env:FIRMWARE_DB_PASSWORD ``` Публичный каталог можно читать без входа. Публикация через CLI требует обе переменные. Сервис не извлекает сохранённый пароль SETGUI автоматически. Команда `publish` явно разрешает запись и не запрашивает дополнительного подтверждения; `preflight` ничего не загружает. Старый BAT и конфигурации `firmware-release.cmd` продолжают использовать прежний путь через SETGUI. ## Портирование в другое Python-приложение Подключите `templates/python` в import path приложения; переносите зависимость целиком, не одну копию файла. Сеть и кэш реализованы в сервисе, UI и хранение учётных данных задаёт приложение: ```python from pathlib import Path from setprotocol.firmware_database import ( Credentials, FirmwareDatabase, GiteaRepository, GiteaFirmwarePublisher, ) from setprotocol.firmware_publish import FirmwarePublication repo = GiteaRepository('https://git.rd12.ru', 'setcorp', 'SETRD12-Releases') # login и password получает ваше приложение из формы/хранилища. credentials = Credentials(login, password) database = FirmwareDatabase(repo.manifest_url, Path('firmware'), credentials=credentials) # «Обновить каталог»: результат заполнит список в вашем UI. releases = database.read_catalog(product='MY_DEVICE', transport='can') # После выбора пользователем строки списка: selected = releases[selected_index] path = database.download(selected, progress=lambda percent: print(percent)) # Передайте path, selected.transport и selected.base_address своему загрузчику. # Публикация нового образа: отдельное действие оператора. publisher = GiteaFirmwarePublisher(repo, credentials) publication = FirmwarePublication( Path('build/device.hex'), 'MY_DEVICE', '1.2.3', 0x010203, 'can', 0x08003000, 'Описание выпуска', ) preview = publisher.preflight(publication) # можно показать перед выпуском entry = publisher.publish(publication) ``` Для публичного каталога передайте `credentials=None`. Для чтения каталога, расположенного вне стандартного Gitea URL, передайте его HTTPS-адрес прямо в `FirmwareDatabase`; `GiteaRepository` нужен сетевому публикатору. В Qt выполняйте `read_catalog`, `download`, `publish` в worker/QThread, передавайте прогресс сигналами в главный поток. По аналогии с SETGUI: 1. Кнопка «Обновить каталог» вызывает `read_catalog`, заполняет combo/table. 2. В строке показываются `product`, `version`, `transport`; в деталях — `file_name`, `notes`, `base_address`. 3. «Скачать и выбрать» вызывает `download`, возвращает проверенный путь. 4. Сигнал в основное окно передаёт путь и выбранную `FirmwareRelease`; окно выставляет файл и транспорт на вкладке прошивки. Скачивание не запускает прошивку устройства автоматически. Для C++/Android можно использовать CLI как отдельный процесс на ПК или реализовать клиент этого JSON-контракта на языке платформы; Python-модуль не является C-библиотекой. ## Поведение и ошибки - Кэш: `//`. Одинаковые имена разных образов не конфликтуют. Проверенный кэш используется повторно; незавершённые временные файлы удаляются. Результат появляется только после совпадения SHA-256. - Только HTTPS. Учётные данные отправляются лишь исходному origin (схема, хост, порт); на сторонний CDN и при смене origin в redirect не передаются. Redirect для запросов записи отклоняется. - Публикация использует asset с SHA-256 в имени: новые байты не заменяют файл, на который ещё ссылается старый каталог. `fileName` в каталоге остаётся исходным именем. В этом деталь реализации отличается от старого публикатора SETGUI, но формат каталога совместим. - Каталог меняется только после обратного скачивания образа. Запись проверяет ревизию файла (`sha`). При конфликте операция завершается ошибкой: повторите выпуск после проверки причины. Загруженный asset может остаться без записи каталога; повторный запуск использует его и снова проверит скачивание. - Повтор той же записи не увеличивает `catalogVersion`. Обновление одного `product + versionCode + transport` заменяет запись. Полный rollback и автоматическая очистка старых assets не выполняются. - Текущий upload держит образ в памяти (лимит 128 MiB), чтобы параллельная пересборка не подменила байты между вычислением хэша и отправкой. ## Проверка Из `templates`: ```powershell $env:PYTHONPATH = "$PWD/python" python -m unittest discover -s python/tests -p test_firmware_database.py -v python -m unittest discover -s python/tests -p test_firmware_publish.py -v ``` Тесты используют сервер в памяти: каталог → публикация → скачивание, повторный выпуск, сохранение других разделов, ошибки SHA-256 и конфликты ревизии, изоляцию авторизации при redirect. Проверка реальной Gitea и загрузка на МК в эти тесты не входят. Перед производственным подключением проверьте выпуск в тестовом репозитории вашей Gitea и чтение каталога целевым GUI.