Files
utun2/src/dm/dm_media.h
T

119 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* dm_media — файлы личных бесед и ограниченное ciphertext-хранилище M.
* Шифрование/проверка/публикация файлов в media_async; все API ниже, БД и сеть — в uasync.
* dm_core вызывает track внутри своей транзакции. Квитанция файла независима
* от квитанции сообщения; публикуется после проверки, публикации файла и commit.
* Суперузлом и заданиями удаления владеет dm_mailbox_media.
* Квота M проверяется после успешного чтения занятого места и finalize SQL-запроса.
* Ошибки SQL логируются без REJECT, сохраняя штатный повтор STORE со стороны S.
* Instance/SQLite/группы должны пережить workers и их callbacks; остановка — quiesce, drain, destroy.
* Входные строки/буферы заимствуются до возврата, кроме явно переданного временного файла.
* Из C++ этот C API включать внутри extern "C", как в клиентах Qt/JNI.
*/
#ifndef DM_MEDIA_H
#define DM_MEDIA_H
#include <stdint.h>
#include <stddef.h>
#include "../media_async/attachment.h"
struct UTUN_INSTANCE;
#define DM_MEDIA_DESC_SIZE 56 /* UUID:16, plaintext_size:8 native-endian, SHA256(ciphertext):32. */
#define DM_MEDIA_RECEIPT_SIZE 152
#define DM_MEDIA_MAX_SIZE (1024ULL * 1024 * 1024)
/* ETCP_RT_ID_DM_MEDIA=0x38: [cmd:1][body], router-подпись обязательна; числа native-endian.
* OFFER: [recipient:8][holder:8][expires:8][каноническое file-сообщение]. A предлагает себя с expires=0.
* STORE: [recipient:8][file-сообщение] от S к M; STORED: [UUID:16][expires:8].
* RECEIPT/DELETE: ["DMFILE01":8][conv:8][seq:8][author:8][recipient:8][UUID:16][SHA256(message):32][sig_B:64].
* B подписывает первые 88 байт; DELETE переносит ту же квитанцию, не создаёт новую.
* DELETE_ACK/EXPIRED: [UUID:16]; REJECT: [UUID:16][reason:1], reason=1 — недостаток квоты.
* EXPIRED завершает промежуточное хранение, а не подтверждает доставку B. */
#define DM_MEDIA_OFFER 1
#define DM_MEDIA_STORE 2
#define DM_MEDIA_STORED 3
#define DM_MEDIA_RECEIPT 4
#define DM_MEDIA_DELETE 5
#define DM_MEDIA_DELETE_ACK 6
#define DM_MEDIA_EXPIRED 7
#define DM_MEDIA_REJECT 8
/* После dm_core_init с SQLite/config/router/ua и media_async ядра: таблицы, каталоги, file_transfer, bind и таймер.
* 0=успех, -1=ошибка, в том числе повторный init живого owner. При отказе созданные таблицы/каталоги остаются.
* Корень: db_path/dm_media и db_path/dm_pending; без db_path используется текущий каталог.
* После restart сбрасываются downloading/retry_at; история, custody и квитанции сохраняются. */
int dm_media_init(struct UTUN_INSTANCE* inst);
/* Идемпотентно запретить новые задачи, отменить таймер/bind и file_transfer с его CM handles.
* Вызвать до media_async_destroy; callbacks отмены ещё используют живые owner/SQLite/группы. NULL допустим. */
void dm_media_quiesce(struct UTUN_INSTANCE* inst);
/* После drain/destroy media_async, до групп/core/mailbox: освободить owner, сохранить durable данные.
* При живых jobs/cleanup_active логирует ошибку и оставляет owner для повторного destroy. NULL допустим. */
void dm_media_destroy(struct UTUN_INSTANCE* inst);
/* Передать подготовку копии и enqueue file-сообщения в media_async.
* Строки conv/path и info копируются при вызове; сам файл должен быть доступен worker до завершения.
* 0=submit вызван, -1=отказ до submit. Submit может синхронно завершиться ошибкой через callback;
* готовность/ошибка подготовки сообщается CHAT_EVT_ATTACHMENT_PREPARATION, включая до возврата 0.
* Беседа должна быть видимой; до 4 одновременных подготовок, plaintext до DM_MEDIA_MAX_SIZE.
* remove_source=1 передаёт worker собственный временный файл приложения для удаления; при -1 его убирает caller.
* Успех подготовки означает commit file-сообщения, не доставку. Пользовательский исходник: remove_source=0. */
int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info,
int remove_source);
struct dm_file_req {
struct UTUN_INSTANCE* inst; /* Заимствованное ядро до callback. */
char conv[64]; /* Десятичный ID беседы с NUL. */
uint64_t generation; /* Ожидаемое поколение; 0=захватить при входе в uasync. */
char path[1024]; /* Путь исходника с NUL; копируется при принятии. */
struct attachment_info info; /* Проверенные метаданные вложения. */
int remove_source; /* Только принадлежащий приложению временный файл. */
};
/* arg — один блок u_malloc/u_calloc(dm_file_req); трамплин освобождает его, также при отказе.
* Проверяет generation до submit; непринятый remove_source удаляет через worker. */
void dm_send_file_trampoline(void* arg);
/* Внутри транзакции dm_core после проверки канонического msg/len; dir: 0=входящее, 1=исходящее.
* 0=записано/точный повтор UUID и тела, -1=ошибка/конфликт; rollback делает вызывающий.
* Для не-file — пустая операция. Исходящий file требует уже подготовленного .file нужного размера. */
int dm_media_track(struct UTUN_INSTANCE* inst, int dir, const uint8_t* msg, size_t len);
/* Заимствованный descriptor внутри точного канонического file-тела либо NULL.
* Проверяет только формат/длину, не подпись и не размер/хеш файла; указатель живёт вместе с msg. */
const uint8_t* dm_message_media(const uint8_t* msg, size_t len);
/* Ciphertext bytes для plain_size<=DM_MEDIA_MAX_SIZE: plaintext плюс 16 байт на порцию 32768 (для пустого — 16). */
uint64_t dm_media_cipher_size(uint64_t plain_size);
/* receipt — обязательные 152 доступных байта; подпись B/идентичность проверяются по nodes SQLite.
* При msg!=NULL проверяется соответствие каноническому file-телу msg/len, UUID и полному SHA256.
* 0=корректно, -1=отказ. Ничего не записывает, факт скачивания этим вызовом не устанавливается. */
int dm_media_verify_receipt(struct UTUN_INSTANCE* inst, const uint8_t* receipt, const uint8_t* msg, size_t len);
/* Для локального A проверить 152-байтовую квитанцию и сохранить её в точном исходящем dm_files.
* 0=сохранена/повтор либо точное подтверждение уже удалённого файла; -1=ошибка/неизвестное тело.
* Историю и собственный файл A не удаляет; text outbox от этой квитанции не меняется. */
int dm_media_accept_receipt(struct UTUN_INSTANCE* inst, const uint8_t* receipt);
/* Внутри транзакции dm_history_delete: сохранить свои пути в манифесте поколения и удалить dm_files беседы.
* 0=успех, -1=ошибка; требует живого dm_media, commit/rollback делает вызывающий. Не удаляет файлы/transfer. */
int dm_media_forget_prepare(struct UTUN_INSTANCE* inst, const char* conv, uint64_t generation);
/* Только после commit: отменить transfer удалённых UUID и начать асинхронную уборку старых поколений.
* Callback отмены transfer синхронен; ожидания workers здесь нет, busy защищает их пути. */
void dm_media_forget_committed(struct UTUN_INSTANCE* inst, const char* conv);
/* Зарегистрировать принадлежащий приложению path и увеличить busy до запуска worker/transfer.
* conv/generation должны быть текущими и видимыми; 0=захват, -1=ошибка/чужое поколение пути. */
int dm_media_file_hold(struct UTUN_INSTANCE* inst, const char* conv, uint64_t generation, const char* path);
/* Освободить один успешный hold после callback; SQL/нарушение счётчика логируются.
* Уборка старого поколения ждёт освобождения всех holds; busy=-1 означает захват уборщиком. */
void dm_media_file_release(struct UTUN_INSTANCE* inst, const char* path);
/* Отправить cmd/body/len через подписанный router в group к peer; нужен живой dm_media.
* 0=пакет принят транспортом, ненулевое значение=ошибка/backpressure. Durable очередь не создаёт.
* Локальный peer обрабатывается синхронно: 0 означает вызов обработчика, не его durable успех.
* body заимствован до возврата; вызывающий соблюдает формат команды, size<=DM_MEDIA_BODY_MAX+24. */
int dm_media_send(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t peer,
uint8_t cmd, const uint8_t* body, size_t len);
/* 1, если node/author/recipient — живые мемберы group и node имеет role=yes в adm_tags.
* role=NULL проверяет только членство; 0 при отсутствии полномочий/ошибке SQL. Не проверяет сетевой путь. */
int dm_media_scope(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t node,
const char* role, uint64_t author, uint64_t recipient);
/* Опубликовать CHAT_EVT_DM_MSG_RECEIVED [conv_len:1][conv:decimal][local_node:8] для обновления снимка UI. */
void dm_media_notify(struct UTUN_INSTANCE* inst, uint64_t conv);
#endif