From 4f96926f6b27aa3bc9dda9468c1a644d8628ebb2 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 18:15:29 +0200 Subject: [PATCH] docs(member-files): complete public request and transfer contracts --- src/member_files/member_files.h | 31 +++++++++++++++++++++++-------- src/member_files/protocol.h | 3 ++- src/member_files/worker.h | 3 ++- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/member_files/member_files.h b/src/member_files/member_files.h index ab150b79..909e862c 100644 --- a/src/member_files/member_files.h +++ b/src/member_files/member_files.h @@ -17,7 +17,8 @@ typedef void (*mf_response_fn)(void* arg, const struct mf_message* response); // ── Жизненный цикл модуля ── -// Создать состояние сервера/клиента и запустить дисковый worker; 0/-1. +// Создать состояние сервера/клиента и worker; 0/-1. Требует живые ua/config/router/chat/SQLite, повторный init — ошибка. +// Стартовый scan асинхронный: init=0 ещё не означает готовность локального storage; remote client остаётся доступен. int member_files_init(struct UTUN_INSTANCE* inst); // Запретить новые команды и начать отмену запросов/передач; запущенный дисковый I/O завершается отдельно. @@ -26,7 +27,7 @@ void member_files_quiesce(struct UTUN_INSTANCE* inst); // Дождаться дискового worker и освободить контекст; вне callbacks, до удаления CHAT-групп. void member_files_destroy(struct UTUN_INSTANCE* inst); -// Отменить запросы и передачи одной группы перед её удалением. +// Отменить свои запросы/передачи одной группы перед её удалением; дерево storage этим не удаляется. void member_files_cancel_group(struct UTUN_INSTANCE* inst, uint64_t group); // ── Команды файлового сервера ── @@ -39,6 +40,7 @@ struct mf_pending* member_files_request(struct UTUN_INSTANCE* inst, uint64_t gro const struct mf_message* request, mf_response_fn callback, void* arg); // Синхронно завершить свой запрос ответом MF_CANCELLED; handle после вызова недействителен, NULL допустим. +// Это отмена локального ожидания; уже запущенная серверная мутация не откатывается. void member_files_cancel(struct mf_pending* pending); // Отменить pending-запрос с этим request_id; не отменяет потоковую передачу файла. @@ -46,14 +48,20 @@ void member_files_cancel_request_id(struct UTUN_INSTANCE* inst, uint64_t id); // ── Проверка доступа ── -// 1 — действующий мембер; storage!=0 дополнительно требует подписанную роль хранителя. +// 1 — полная source=0/deleted=0 запись мембера в локальной CHAT-таблице, иначе0. +// storage!=0 требует adm_tags.storage=yes и сохранённую64-байтную подпись; peers.storage не даёт полномочий. int member_files_member(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t node, int storage); // ── Команда интерфейса ── -struct mf_gui_request { struct UTUN_INSTANCE* inst; uint64_t group, server; struct mf_message message; }; +struct mf_gui_request { + struct UTUN_INSTANCE* inst; // Заимствованное ядро до ответа. + uint64_t group, server; // CHAT-группа и явно выбранный storage, в том числе self. + struct mf_message message; // Команда; для корреляции GUI выбирает ненулевой request_id. +}; -// arg — u_malloc/u_calloc mf_gui_request; освобождается после ответа CHAT_EVT_MEMBER_FILES_RESPONSE. +// arg — u_malloc/u_calloc mf_gui_request; владение переходит при вызове trampoline, освобождается после ответа. +// CHAT_EVT_MEMBER_FILES_RESPONSE: group:8LE/server:8LE, затем mf_encode(response). Отказ запуска даёт ACCESS_DENIED. void member_files_gui_request(void* arg); // ── Потоковая передача файлов ── @@ -65,12 +73,17 @@ struct mf_transfer_request { // download: по ответу STAT, до открытия локального temp и передачи данных. uint64_t max_bytes; int upload; // ненулевой — загрузить local на сервер, 0 — скачать remote - uint8_t version[16]; // версия из STAT; нули при создании нового серверного файла + uint8_t version[16]; // Upload:ожидаемая версия/нули для создания; download:ожидаемая версия/нули для текущей. char remote[MF_PATH_MAX + 1], local[MF_PATH_MAX + 1]; // путь в каталоге owner и локальный путь приложения }; struct mf_transfer; -struct mf_transfer_progress { uint64_t id, done, total; uint16_t status; uint8_t finished; }; +struct mf_transfer_progress { + uint64_t id; // Фактический ID handle, включая автоматически выбранный. + uint64_t done, total; // Upload:принятые router байты; download:записанные на диск, до финального sync/publish. + uint16_t status; // mf_status; результат окончательный только при finished. + uint8_t finished; // 0 progress (может отсутствовать),1 ровно одно завершение. +}; typedef void (*mf_transfer_fn)(void* arg, const struct mf_transfer_progress* progress); // Один handle на файл; до 16 клиентских передач одновременно, включая upload/download к одному пиру. @@ -79,6 +92,8 @@ typedef void (*mf_transfer_fn)(void* arg, const struct mf_transfer_progress* pro // Прогресс заимствован на время callback. Cancel асинхронно ждёт свой I/O и не затрагивает другие handles. // Request копируется; исходную структуру можно освободить сразу, arg должен жить до finished. // Download заменяет local только после проверки/закрытия своего temp; отказ/отмена до создания не удаляет чужой temp. +// Совпадение строк local двух download запрещено; aliases/подмену локальных файлов исключает caller. +// Upload требует стабильный regular source; изменение снимка даёт STALE. Пустой файл допустим. struct mf_transfer* member_files_transfer_start(const struct mf_transfer_request* request, mf_transfer_fn callback, void* arg); // Запросить отмену своей передачи; завершение приходит через finished после закрытия её файлового I/O. @@ -91,7 +106,7 @@ void member_files_transfer_cancel(struct mf_transfer* transfer); * state=1 progress, 2 finished. arg — u_malloc/u_calloc mf_transfer_request, освобождается после finished. */ void member_files_gui_transfer(void* arg); -struct mf_cancel_request { struct UTUN_INSTANCE* inst; uint64_t id; }; +struct mf_cancel_request { struct UTUN_INSTANCE* inst; uint64_t id; }; // Заимствованное ядро и фактический ID команды/передачи. // arg — u_malloc/u_calloc mf_cancel_request, освобождается здесь; отменяет передачу либо одиночный запрос по id. void member_files_gui_cancel(void* arg); diff --git a/src/member_files/protocol.h b/src/member_files/protocol.h index 8a5ecfa0..97316817 100644 --- a/src/member_files/protocol.h +++ b/src/member_files/protocol.h @@ -73,7 +73,8 @@ void mf_put64(uint8_t* p, uint64_t value); /* 1 — все n байт нулевые, иначе0. */ int mf_zero(const uint8_t* p, size_t n); /* 1/0: строгий UTF-8, путь<=1024 байт, до60 компонентов по1..255 байт; root_allowed разрешает пустую строку. - * Отвергает leading '.', trailing '.'/' ', ASCII C0/DEL, Windows device names и \\: *?"<>| (без разрешения пробела после двоеточия). */ + * Отвергает leading '.', trailing '.'/' ', ASCII C0/DEL и Windows device names. + * Запрещены обратная косая черта, двоеточие, '*', '?', '"', '<', '>', '|'. */ int mf_path_valid(const char* path, int root_allowed); /* Записать wire: длина>0 либо-1 при переполнении; выход не меняется при отказе длины. * Проверяет размеры, но не семантику command/ID/path. message/wire обязательны и не перекрываются. */ diff --git a/src/member_files/worker.h b/src/member_files/worker.h index a9e16d9a..2591b7c5 100644 --- a/src/member_files/worker.h +++ b/src/member_files/worker.h @@ -21,10 +21,11 @@ void mf_worker_unreserve(struct mf_work* work); /* До64 обычных задач, включая ожидающие done. При отказе done(-1) синхронно, work не вызывается. */ void mf_worker_submit(struct mf_worker* worker, mf_work_fn work, void* data, mf_done_fn done, void* arg); /* Передать резерв worker без проверки лимита64: только обязательные cleanup continuations. - * После вызова резерв нельзя освобождать/использовать повторно. FIFO, done ровно один раз. */ + * После вызова резерв нельзя освобождать/использовать повторно. Work выполняется FIFO, done ровно один раз. */ void mf_worker_submit_reserved(struct mf_worker* worker, struct mf_work* reserved, mf_work_fn work, void* data, mf_done_fn done, void* arg); // После quiesce владельца, вне callbacks: дождаться работ и их cleanup continuations, не останавливая pthread. +// Не запускает uasync рекурсивно; порядок done при drain не обещается. NULL допустим. void mf_worker_drain(struct mf_worker* worker); /* Drain, затем join и освобождение. Работы не прерываются и получают обычный done(0); NULL допустим. */ void mf_worker_destroy(struct mf_worker* worker);