docs(dm): specify media protocol and worker lifetime
This commit is contained in:
1 parent
1cfafc43a4
commit
ad577318d9
2 files changed
+69
-18
No files matched your search
+58
-14
@@ -1,10 +1,13 @@
|
||||
/* dm_media — файлы личных бесед и ограниченное ciphertext-хранилище M.
|
||||
* Шифрование/проверка/публикация файлов в media_async; БД и сеть в uasync.
|
||||
* Шифрование/проверка/публикация файлов в 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
|
||||
@@ -15,10 +18,17 @@
|
||||
|
||||
struct UTUN_INSTANCE;
|
||||
|
||||
#define DM_MEDIA_DESC_SIZE 56 /* UUID:16, plaintext_size:8, SHA256(ciphertext):32 */
|
||||
#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
|
||||
@@ -28,47 +38,81 @@ struct UTUN_INSTANCE;
|
||||
#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);
|
||||
/* quiesce до media_async_destroy; destroy после workers, до групп/core/mailbox. */
|
||||
/* Идемпотентно запретить новые задачи, отменить таймер/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.
|
||||
* remove_source=1 передаёт worker собственный временный файл приложения для удаления; при -1 его убирает caller. */
|
||||
* готовность/ошибка подготовки сообщается 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;
|
||||
char conv[64];
|
||||
uint64_t generation;
|
||||
char path[1024];
|
||||
struct attachment_info info;
|
||||
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, 0=записано/точный повтор. Для text — пустая операция. */
|
||||
/* Внутри транзакции 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);
|
||||
|
||||
/* Удаление: prepare внутри транзакции, committed после commit (callbacks отмены синхронны). */
|
||||
/* Внутри транзакции 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);
|
||||
/* Владение путями worker: hold до запуска, release после завершения. Уборка ждёт busy=0. */
|
||||
/* Зарегистрировать принадлежащий приложению 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);
|
||||
|
||||
/* Общие операции control для endpoint/M и mailbox/S. Все пакеты подписаны. */
|
||||
/* Отправить 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
|
||||
+11
-4
@@ -1,4 +1,7 @@
|
||||
/* Внутренние SQL/control операции двух владельцев DM media; снаружи не использовать. */
|
||||
/* Внутренние SQL/control операции dm_media и dm_mailbox_media; снаружи не использовать.
|
||||
* Все вызовы в uasync с живыми inst/topo_sqlite_db. Workers не обращаются к этим helpers.
|
||||
* Соединением SQLite владеет ядро; вызовы не закрывают его и не меняют внешнее владение транзакцией.
|
||||
* Из C++ включать внутри extern "C". */
|
||||
#ifndef DM_MEDIA_PRIV_H
|
||||
#define DM_MEDIA_PRIV_H
|
||||
|
||||
@@ -6,17 +9,21 @@
|
||||
#include "dm_core.h"
|
||||
#include <sqlite3.h>
|
||||
|
||||
/* Верхняя граница канонического тела с ct<=255, CCM tag, descriptor и подписью; без cmd/router-заголовка. */
|
||||
#define DM_MEDIA_BODY_MAX (DM_MSG_FIXED_HDR + 255 + 2 + DM_DATA_MAX + 16 + DM_MEDIA_DESC_SIZE + DM_MSG_SIG_SIZE)
|
||||
|
||||
/* SQLite ядра, только uasync: prepare возвращает statement либо NULL с логом ошибки.
|
||||
* inst/db/sql обязательны; вызывающий связывает параметры и освобождает statement. */
|
||||
* inst/db/sql обязательны; вызывающий проверяет bind/step для чтения и всегда освобождает statement.
|
||||
* Для записи владение можно передать dm_media_step; prepare сам транзакцию не начинает. */
|
||||
sqlite3_stmt* dm_media_prepare(struct UTUN_INSTANCE* inst, const char* sql);
|
||||
/* Шаг записи, затем finalize (включая ошибку): statement передаётся во владение helper.
|
||||
* 0 только при SQLITE_DONE и успешном finalize, иначе -1 с логом; внутри транзакции rollback делает вызывающий. */
|
||||
* 0 только при SQLITE_DONE и успешном finalize, иначе -1 с логом; NULL даёт -1 после ошибки prepare.
|
||||
* Не предназначен для SELECT; bind проверяет вызывающий, внутри транзакции rollback делает вызывающий. */
|
||||
int dm_media_step(struct UTUN_INSTANCE* inst, sqlite3_stmt* st);
|
||||
/* Выполнить SQL без результата: 0/-1 с логом. Владение транзакцией определяется SQL вызывающего. */
|
||||
int dm_media_exec(struct UTUN_INSTANCE* inst, const char* sql);
|
||||
/* Заимствованный координатор mailbox либо NULL при остановленном/отсутствующем inst. */
|
||||
/* Заимствованный координатор mailbox либо NULL при остановленном/отсутствующем inst.
|
||||
* Не освобождать; действителен до dm_mailbox_destroy в том же uasync-потоке. */
|
||||
struct dm_mb_media* dm_mailbox_get_media(struct UTUN_INSTANCE* inst);
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user