75 lines
5.7 KiB
C
75 lines
5.7 KiB
C
/* group_avatar — общая подписанная аватарка CHAT-канала, хранение в SQLite и обмен между участниками.
|
|
* После init: get читает текущую версию, set публикует картинку владельца, apply принимает проверяемую запись пира.
|
|
* Картинка до 16 КиБ передаётся router-блоками до 4 КиБ; данные публикуются после проверки подписи канала.
|
|
* Все вызовы/callbacks — uasync. group — канонический числовой ID1..INT64_MAX существующего CHAT-канала.
|
|
* Изменение приходит CHAT_EVT_CHANNEL_UPDATED после commit. Обработчик вправе отменить задачи группы;
|
|
* остановку сервиса/destroy выполняют вне callbacks. Ключи и содержимое картинки в лог не выводятся. */
|
|
#ifndef GROUP_AVATAR_H
|
|
#define GROUP_AVATAR_H
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
struct UTUN_INSTANCE;
|
|
struct sqlite3;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// ── Схема хранения ──
|
|
|
|
/* Добавить отсутствующие поля channels одним savepoint; 0/-1, повтор допустим, БД заимствована.
|
|
* Внешняя транзакция остаётся у вызывающего. При отказе ROLLBACK TO не выполняет RELEASE частичной схемы;
|
|
* оставшуюся открытой транзакцию владелец должен откатить/закрыть. */
|
|
int group_avatar_schema_init(struct sqlite3* db);
|
|
|
|
#define GROUP_AVATAR_MAX 16384
|
|
#define GROUP_AVATAR_BLOCK 4096
|
|
struct group_avatar_record {
|
|
uint64_t version; // 0 — картинка ещё не публиковалась; иначе версия подписанной записи
|
|
uint16_t size; // байты картинки; size=0 при ненулевой версии — подписанное удаление
|
|
uint8_t hash[32], signature[64], data[GROUP_AVATAR_MAX]; // SHA256, подпись канала Ed25519 и готовая картинка
|
|
};
|
|
// ── Жизненный цикл модуля ──
|
|
|
|
// После chat_core_init создать контекст, router-service и таймер; 0/-1. Повтор допустим, ошибка снимает новые регистрации.
|
|
int group_avatar_init(struct UTUN_INSTANCE* inst);
|
|
|
|
// Остановить обмен и освободить контекст; сохранённая картинка остаётся в БД.
|
|
void group_avatar_destroy(struct UTUN_INSTANCE* inst);
|
|
|
|
// Отменить сборки/waiters/call_soon канала перед удалением группы; БД и router-сессия остаются у своих владельцев.
|
|
void group_avatar_cancel_group(struct UTUN_INSTANCE* inst, uint64_t group);
|
|
|
|
// ── Чтение и изменение аватарки ──
|
|
|
|
/* Скопировать запись и проверить SHA256/подпись:0 — прочитано (version=0, если не публиковалась), -1 — ошибка/нет канала.
|
|
* Проверяются bind/step/finalize и размеры полей; при любом отказе record не меняется. */
|
|
int group_avatar_get(struct UTUN_INSTANCE* inst, uint64_t group, struct group_avatar_record* record);
|
|
|
|
/* Проверить подпись и сохранить более новую запись:1 — committed,0 — прежняя/старая,-1 — ошибка.
|
|
* При одинаковой версии побеждает больший SHA256; запись заимствована. Проверка версии/запись защищены BEGIN IMMEDIATE.
|
|
* Внешняя транзакция запрещена даже для no-op; ошибка сохраняет прежнюю запись/события. Неудачный rollback
|
|
* с оставшейся транзакцией запрашивает stop/закрытие БД владельцем. Уведомление/STATE идут после commit. */
|
|
int group_avatar_apply(struct UTUN_INSTANCE* inst, uint64_t group, const struct group_avatar_record* record);
|
|
|
|
/* Подписать и сохранить картинку: нужен приватный Ed25519 ключ канала. size=0 — удаление; data копируется.
|
|
* 0 — committed или картинка прежняя, -1 — ошибка/нет прав. Членство/ключ/версия/запись читаются под одной блокировкой;
|
|
* внешняя транзакция запрещена, временный ключ очищается на всех выходах. Доставка пирам выполняется отдельно. */
|
|
int group_avatar_set(struct UTUN_INSTANCE* inst, uint64_t group, const uint8_t* data, size_t size);
|
|
|
|
// ── Команда интерфейса ──
|
|
|
|
struct group_avatar_gui_request {
|
|
struct UTUN_INSTANCE* inst; /* Заимствован до выполнения trampoline. */
|
|
uint64_t id, group; /* ID команды интерфейса и канала. */
|
|
uint16_t size; /* Размер data<=GROUP_AVATAR_MAX;0 — подписанное удаление. */
|
|
uint8_t data[GROUP_AVATAR_MAX]; /* Готовая картинка, скопированная интерфейсом. */
|
|
};
|
|
// arg — u_malloc/u_calloc group_avatar_gui_request, освобождается здесь; результат — CHAT_EVT_GROUP_AVATAR_RESULT.
|
|
void group_avatar_gui_set(void* arg);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif
|