111 lines
11 KiB
C
111 lines
11 KiB
C
/* chat_attachment — вложения канала с шифрованием и ручной выдачей ключа автором.
|
||
* send готовит контейнер и публикует сообщение; downloaded/want запускают получение ключа и расшифровку.
|
||
* Автор отвечает на запрос через decide. Ключи и очередь доставки сохраняются в локальной БД.
|
||
* Все вызовы, кроме identity, — uasync. init после media_async; quiesce до остановки workers, destroy после них.
|
||
* Обмен ключами подписан и зашифрован; для доставки нужен живой маршрут обеих сторон.
|
||
* Ответы REQUEST_ACK/GRANT/DENY/RESULT_ACK атомарно меняют ключ, запрос и outbox собственной транзакцией.
|
||
* Внешняя транзакция для ответов запрещена. GRANT/DENY подтверждаются только после проверенного commit;
|
||
* повтор с тем же результатом допустим, конфликтующий ключ/решение отклоняется. Отказ SQL сохраняет прежнее состояние.
|
||
* Приём REQUEST владеет собственной транзакцией проверки идентичности/прав и сохранения запроса/повтора ответа.
|
||
* Внешняя транзакция отклоняется без изменений; ACK/событие — после commit. Дубликат сохраняет решение и дату:
|
||
* state=0 ждёт автора, 2/4 повторяют GRANT, 3 повторяет DENY; чужое направление и другие состояния отклоняются.
|
||
* Исходящий REQUEST сохраняется собственной транзакцией request+outbox после повторной проверки состояния.
|
||
* Уведомление/отправка следуют после commit; внешняя транзакция откладывает весь проход файлов и очереди.
|
||
* Перед сетевой попыткой отдельно фиксируется retry_at; отказ SQL не отправляет команду и сохраняет очередь/дату.
|
||
* Пустая очередь завершается без commit hook. retry_at отодвигается на5с; tick каждые10с, до16 команд за проход.
|
||
* Расшифровка стартует после commit decrypting=1. До commit метаданных завершение остаётся у модуля:
|
||
* таймер повторяет SQL без нового worker; не более 16 активных/ожидающих завершения файлов на instance.
|
||
* quiesce останавливает повторы, destroy после workers освобождает также отложенные завершения.
|
||
* Незавершённый rollback отключает модуль и запрашивает остановку ядра владельцем вне callback. */
|
||
#ifndef CHAT_ATTACHMENT_H
|
||
#define CHAT_ATTACHMENT_H
|
||
#include "../media_async/attachment.h"
|
||
#include "../media_async/encrypted_file.h"
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
struct UTUN_INSTANCE;
|
||
|
||
// ── Жизненный цикл модуля ──
|
||
|
||
// Подключить таблицы, router-сервис и обработку сохранённых задач; 0/-1. Внешняя транзакция запрещена.
|
||
int chat_attachment_init(struct UTUN_INSTANCE* inst);
|
||
|
||
// Запретить новые подготовки и остановить таймер; запущенные workers завершаются отдельно.
|
||
void chat_attachment_quiesce(struct UTUN_INSTANCE* inst);
|
||
|
||
// После workers убрать незавершённые подготовки; открытая транзакция откладывает recovery, сохраняя файлы.
|
||
void chat_attachment_destroy(struct UTUN_INSTANCE* inst);
|
||
|
||
// ── Отправка и учёт вложений ──
|
||
|
||
/* Асинхронно отправить подготовленный файл; channel — десятичный ID, reply — 32 байта ID ответа либо нули.
|
||
* Аргументы копируются. 0 — задача принята, source передан задаче и будет удалён даже при ошибке подготовки.
|
||
* -1 — отказ до принятия, source остаётся у вызывающего, события MSG_SUBMITTED здесь нет.
|
||
* Ключ/UUID/метаданные фиксируются собственной SQL-транзакцией до передачи source и запуска worker.
|
||
* Внешняя транзакция запрещена и остаётся нетронутой при отказе. Ошибка rollback с открытой транзакцией
|
||
* запрещает новые задачи модуля и запрашивает остановку ядра; уничтожение выполняет владелец вне callback.
|
||
* Ненулевой request возвращается в единственном CHAT_EVT_MSG_SUBMITTED; отказ media_async_submit может
|
||
* дать его синхронно, до возврата 0. Commit не усиливает установленную ядром политику SQLite synchronous. */
|
||
/* type проверяется encrypted_file_validate_type до выделения задачи, генерации UUID/ключа и записи в БД. */
|
||
int chat_attachment_send(struct UTUN_INSTANCE* inst, const char* channel, const char* source,
|
||
const struct attachment_info* info, const char* type, const uint8_t reply[32], uint64_t request);
|
||
|
||
// Прочитать UUID из канонического base64-префикса тела медиа; 0/-1, id меняется только при успехе. Подпись проверяет вызывающий.
|
||
int chat_attachment_identity(const char* body, size_t length, uint8_t id[16]);
|
||
|
||
/* Собственной транзакцией связать авторский ключ с ID сообщения и SHA256 контейнера до публикации; 0/-1.
|
||
* Массивы копируются в БД. Повтор той же пары допустим, её изменение запрещено; отказ сохраняет прежние поля.
|
||
* Внешняя транзакция отклоняется без изменений; все SQL-этапы и commit проверяются. */
|
||
int chat_attachment_bind(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t id[16],
|
||
const uint8_t message[32], const uint8_t hash[32]);
|
||
|
||
/* Учесть проверенное db_sync сообщение собственной транзакцией, не меняя ключ/состояние существующей идентичности.
|
||
* 0 — записано/точный дубликат/обычное сообщение, -1 — SQL/OOM-отказ для повтора, -2 — неверный manifest/коллизия.
|
||
* Внешняя транзакция запрещена. Подпись проверяет вызывающий; JSON заимствован до возврата. */
|
||
int chat_attachment_observe(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32],
|
||
uint64_t author, const char* json, size_t length);
|
||
|
||
// ── Получение файла и выдача доступа ──
|
||
|
||
/* После загрузки/наличия сохранённого контейнера: своей транзакцией сохранить downloaded и policy wanted.
|
||
* 0/-1; запись observe обязательна. Повтор неизменного состояния не даёт события. Криптографию проверит worker.
|
||
* verified_download!=0 — новая проверенная передача, также сбрасывает прежний error; 0 — найденный cache, error сохраняется.
|
||
* Внешняя транзакция запрещена, SQL-отказ сохраняет прежние поля, событие — после commit. */
|
||
int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32], int verified_download);
|
||
|
||
/* Ручная загрузка, включая storage: одной транзакцией установить wanted, сбросить error и ready отсутствующего cache.
|
||
* 0/-1; запись observe обязательна. Внешняя транзакция запрещена, отказ сохраняет прежние поля. */
|
||
int chat_attachment_want(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32]);
|
||
|
||
/* Сохранить решение автора по ожидающему запросу peer: approve!=0 — выдать ключ, 0 — отказать.
|
||
* 0 — собственная транзакция решения+outbox завершена, затем послано одно уведомление изменения;
|
||
* -1 — ошибка/нет прав или ожидающего запроса, прежнее состояние сохранено. Доставка идёт позже.
|
||
* Внешняя транзакция отклоняется без изменений; проверка прав выполняется внутри собственной.
|
||
* Открытая после отказа rollback транзакция требует остановки/закрытия БД владельцем после poll. */
|
||
int chat_attachment_decide(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32], uint64_t peer, int approve);
|
||
|
||
// ── Команда интерфейса ──
|
||
|
||
struct chat_attachment_decision {
|
||
struct UTUN_INSTANCE* inst;
|
||
char channel[32];
|
||
uint8_t message[32];
|
||
uint64_t peer;
|
||
int approve;
|
||
};
|
||
// arg — u_malloc/u_calloc chat_attachment_decision, освобождается здесь; успех уже уведомлён decide, ошибка — событие с success=0.
|
||
void chat_attachment_decision_trampoline(void* arg);
|
||
|
||
// ── Локальное удаление канала ──
|
||
|
||
/* После commit удаления канала убрать собственные UUID.file; 0/-1, при I/O-ошибке можно повторить.
|
||
* Ключи/запросы/outbox удаляет SQLite-trigger атомарно с channels; SQL-отказ сохраняет все записи.
|
||
* Внешняя транзакция или существующий канал запрещают файловую очистку; завершения workers видят удаление через БД. */
|
||
int chat_attachment_delete_channel(struct UTUN_INSTANCE* inst, const char* channel);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif
|