Files
utun2/doc/group_avatar.txt
T

103 lines
10 KiB
Plaintext

Аватарка CHAT-группы
===================
Модуль src/chat/group_avatar.c. Картинка — бинарный BLOB до 16384 байт в общей
SQLite каждого участника: channels.avatar_data/version/hash/signature.
Storage-сервер, каталоги файлов и пользовательские квоты не используются.
При старте добавляются отсутствующие колонки одной транзакцией, записи/ключи
каналов сохраняются. channel_put использует UPSERT и сохраняет аватарку,
UI-состояние и локальные приватные ключи; смена публичных ключей существующего
channel_id запрещена. Удаление группы удаляет и её аватарку.
Право публикации — приватный Ed25519 ключ группы плюс собственное действующее
членство. creator UID/admin-флаг не заменяют ключ. group_avatar_set подписывает:
ASCII "group-avatar-v1" без NUL, group:u64 LE, version:u64 LE, size:u16 LE, bytes.
Версия — max(NTP microseconds/1000, previous+1), ограничена INT64_MAX.
SHA256 считается по картинке; при одинаковой версии побеждает больший SHA256.
Обе конкурирующие записи должны иметь правильную подпись группы; конфликт — WARN.
Публикация одинаковой картинки не создаёт новую версию. Удаление — подписанная
запись с size=0 и новой версией; подпись/версия сохраняются, старый пир не может
восстановить удалённую картинку. Чтение проверяет сохранённый хеш и подпись.
Отказ SQL/проверки оставляет выход group_avatar_get неизменным. Приватный ключ
читается целиком:ровно32 байта BLOB,с проверкой bind/step/finalize;временные копии
очищаются на всех выходах. Сломанный/отсутствующий ключ не даёт права публикации.
set/apply владеют BEGIN IMMEDIATE:допуск,выбор/сравнение версии и UPDATE выполняются
под одной блокировкой. Все bind/step/changes=1/finalize и COMMIT проверяются.
Чужая транзакция отклоняется до действия,включая no-op;без изменения выполняется
ROLLBACK без commit hook. Ошибка сохраняет запись и не отправляет CHANNEL_UPDATED/
STATE. Если сам rollback оставляет транзакцию открытой,запрашивается stop;
владелец завершает остановку/закрытие БД вне callback. Миграция схемы использует
savepoint и допускает внешнюю транзакцию:ошибка ROLLBACK TO не сопровождается
RELEASE частичных ALTER;откат/закрытие остаются владельцу.
Транспорт
---------
ETCP_RT_ID_GROUP_AVATAR=0x3A, router wire version=1. Отправитель/группа берутся
из проверенного router-заголовка. Все пакеты подписаны ключом узла и зашифрованы
end-to-end; в DATA дополнительно передаётся подпись группы над всей картинкой.
Обмен только между READY-соседями CHAT-группы с действующим подписанным членством.
Любой участник пересылает сохранённую запись, владелец ключа может быть offline.
Все числа протокола LE. Общая часть, 44 байта:
version:u8=1, command:u8, avatar_version:u64, total_size:u16, SHA256:32.
STATE=1 объявляет локальную версию/хеш; начальное отсутствие — version=0, hash=0.
GET=2 запрашивает актуальную запись. Объявление не меняет БД без полной DATA.
DATA=3 добавляет group_signature:64, offset:u16, block_size:u16, bytes.
DATA header=112 байт. Картинка разбивается на блоки по 4096 байт; последний
короче. Полная картинка 16 КиБ — ровно четыре DATA. Удаление — один DATA без bytes.
Порядок блоков гарантирует router. Сборка проверяет offset, постоянные version,
total_size/hash/signature и допустимые размеры. До полной сборки прежняя картинка
остаётся в БД. После SHA256/Ed25519 вся запись заменяется одним committed UPDATE, затем
CHANNEL_UPDATED доставляет изменение GUI и STATE распространяется соседям.
Приём завершает работу со сборкой/peer и только затем уведомляет интерфейс:
обработчик вправе отменить задачи группы,не оставляя обращения к освобождённой сборке.
Промежуточные блоки не публикуются, ACK/retransmit каждого блока — только router.
Отправка заполняет router до нижнего порога send_q count<=0 и ждёт send_ready;
планировщик отправляет максимум четыре пакета за callback. Snapshot отправителя
не меняется при новом локальном обновлении. Максимум 16 tx и отдельно 16 rx
сборок на экземпляр, каждая до 16 КиБ. receive_ready при заполнении rx сохраняет
пакет в router recv_q без продвижения ACK; освобождение слота возобновляет приём.
Несовпадение эпох/закрытие router отменяет незавершённую сборку и начинает сверку.
Эпоха нового контекста берётся из текущей READY-сессии, не сбрасывает первый приём.
Обнаружение соседей/таймауты — таймер 1 с; STATE также раз в 30 с. Нет прогресса
15 с — отмена незавершённого snapshot, повтор запроса/сверки. Остановка сервиса
отменяет таймеры/waiters/call_soon до удаления группы/ядра.
ChatGUI
-------
Настройки группы: Upload group avatar/Remove group avatar, предпросмотр и статус.
Кнопки доступны только при локальном приватном ключе. Применение сразу, отдельно
от Save локальных настроек. Worker обрезает центральный квадрат, создаёт JPEG
128×128,при необходимости96×96/64×64,снижает JPEG quality85/70/50/35 до лимита16КиБ.
Вход ограничен16*1024*1024 пикселями;SVG отклоняется.
GUI отправляет байты в uasync; ядро повторно проверяет размер/членство/ключ.
SQLite — постоянный кеш. GroupAvatarManager хранит QImage до 32 МиБ, ключ кеша:
group/version/hash. Декодирование в отдельном worker, проверка SHA256, JPEG и
квадратных размеров до 128×128. Поздний результат старой версии не заменяет
новую. Готовая картинка обновляет только строку группы; без аватарки — инициалы.
Приватные ключи/байты картинки не выводятся в диагностику.
Проверки
--------
test_group_avatar: настоящие два ядра/UDP/router, 16 КиБ четырьмя блоками,
атомарность сборки, hash/signature/cross-group отказ, приостановка receive,
перезапуск канала, stale/conflict, редактор с ключом вне creator UID, подписанное
удаление, повторное описание группы и restart БД. Schema failure откатывает
частичные ALTER, сохраняет прежние данные/ключи, повторное добавление идемпотентно.
Приём также проверен с отменой peer-задач прямо из CHANNEL_UPDATED.
test_group_avatar_sql:27 SQL-отказов публикации и16 чтения аватарки/ключей,
9 отказов схемы;каждый с успешным повтором. Проверены bind подписи/хеша,signing,
ABORT/IGNORE/commit veto,чужая транзакция/no-op,предельная версия,неизменность
выходов/readonly-записи,ошибка rollback и закрытие владельцем. Ключи NULL/31/33/
TEXT отклоняются;неудачный ROLLBACK TO не фиксирует частичную схему.
test_group_avatars (Qt): нормализация, лимит/отображение, кеш, права кнопок и отказ
ядра без ключа, удаление. chat=debug показывает состояния и каждый 4КиБ блок;
chat=info — публикации и жизненный цикл. Ошибки содержат group/peer/version/offset.