Own desktop file commands and report cancellation through Qt
This commit is contained in:
1 parent
142278d651
commit
7d789f68d4
2 files changed
+115
-2
No files matched your search
@@ -76,7 +76,7 @@ void gui_bridge_set_uasync(struct UASYNC* ua);
|
||||
/* Опубликовать готовый instance из uasync после set_uasync. NULL снимается в uasync до destroy,
|
||||
* вне callbacks: синхронно отменяет ожидающие команды и освобождает аргументы owned-запросов.
|
||||
* Начатый callback завершается до остановки poll; отмена post_uasync_* не вызывает fn.
|
||||
* Специализированные API (member_edit.h) могут доставить результат отмены в GUI. */
|
||||
* Специализированные API (member_edit.h, member_files_*) доставляют результат отмены в GUI. */
|
||||
void gui_bridge_set_inst(struct UTUN_INSTANCE* inst);
|
||||
|
||||
/* Текущий заимствованный UTUN_INSTANCE (NULL пока не создан/после сброса моста). */
|
||||
@@ -283,6 +283,18 @@ void gui_bridge_set_dm_delete_result_cb(gui_dm_messages_fn cb);
|
||||
/* Файловый браузер: wire-ответы и прогресс общих передач, в GUI-потоке. */
|
||||
void gui_bridge_set_member_files_response_cb(gui_dm_messages_fn cb);
|
||||
void gui_bridge_set_member_files_transfer_cb(gui_dm_messages_fn cb);
|
||||
struct mf_message;
|
||||
struct mf_transfer_request;
|
||||
/* Скопировать команду/передачу и привязать instance под mutex моста. Исходные данные после возврата не нужны.
|
||||
* Ненулевые group/server и request_id/id обязательны; transfer требует owner, поле inst входа игнорируется.
|
||||
* 0 — принято: обычный RESPONSE/TRANSFER, в том числе MF_CANCELLED при отмене до trampoline.
|
||||
* -1 — не принято: результата не будет, память не остаётся, вызывающий немедленно завершает операцию с ошибкой.
|
||||
* Нужны gui_bridge_init и опубликованное работающее ядро; UI callbacks всегда через очередь Qt. */
|
||||
int gui_bridge_member_files_request(uint64_t group, uint64_t server, const struct mf_message* message);
|
||||
int gui_bridge_member_files_transfer(const struct mf_transfer_request* request);
|
||||
/* Запросить отмену ненулевого ID у текущего ядра; 0 — принято, -1 — отказ с логом.
|
||||
* Память команды принадлежит мосту. Итог операции приходит по её RESPONSE/TRANSFER, отдельного ответа cancel нет. */
|
||||
int gui_bridge_member_files_cancel(uint64_t id);
|
||||
void gui_bridge_set_avatar_result_cb(gui_dm_messages_fn cb);
|
||||
void gui_bridge_set_group_avatar_result_cb(gui_dm_messages_fn cb);
|
||||
/* Опросы/реакции: адресное изменение и коррелированный ответ команды, в GUI-потоке. */
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
#include "../../../lib/debug_config.h"
|
||||
#include "../../../src/routing_layer/topo_node.h"
|
||||
#include "../../../src/routing_layer/topo_group.h"
|
||||
#include "../../../src/member_files/protocol.h"
|
||||
#include "../../../src/member_files/member_files.h"
|
||||
#include "../../../src/chat/chat_member.h"
|
||||
#include "../../../src/chat/chat_core.h"
|
||||
#include "../../../src/chat/chat_sync.h"
|
||||
@@ -667,6 +667,32 @@ void GuiBridgeReceiver::processPost(int eventType, QByteArray data) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Отмена post сообщает результат через Qt, не вызывая код клиента/старого instance под bridge_mutex. */
|
||||
static void cancel_member_files_request(void* arg) {
|
||||
auto* request = static_cast<mf_gui_request*>(arg);
|
||||
auto& message = request->message;
|
||||
message.kind = MF_RESPONSE; message.status = MF_CANCELLED; message.data_len = 0; message.more = 0;
|
||||
uint8_t event[16 + MF_WIRE_MAX];
|
||||
mf_put64(event, request->group); mf_put64(event + 8, request->server);
|
||||
int length = mf_encode(&message, event + 16, MF_WIRE_MAX);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file bridge: request cancelled id=%llu command=%s group=%llu server=%llu path=%s",
|
||||
(unsigned long long)message.request_id, mf_command_text(message.command), (unsigned long long)request->group,
|
||||
(unsigned long long)request->server, message.path);
|
||||
if (length > 0) gui_bridge_post(CHAT_EVT_MEMBER_FILES_RESPONSE, event, length + 16);
|
||||
}
|
||||
|
||||
/* До trampoline дисковый I/O ещё не начат: достаточно одного финального события, payload освободит мост. */
|
||||
static void cancel_member_files_transfer(void* arg) {
|
||||
auto* request = static_cast<mf_transfer_request*>(arg);
|
||||
uint8_t event[51]{};
|
||||
mf_put64(event, request->id); mf_put64(event + 8, request->group); mf_put64(event + 16, request->server);
|
||||
mf_put64(event + 24, request->owner); event[48] = MF_CANCELLED; event[50] = 2;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file bridge: transfer cancelled id=%llu group=%llu server=%llu owner=%llu upload=%d remote=%s",
|
||||
(unsigned long long)request->id, (unsigned long long)request->group, (unsigned long long)request->server,
|
||||
(unsigned long long)request->owner, request->upload, request->remote);
|
||||
gui_bridge_post(CHAT_EVT_MEMBER_FILES_TRANSFER, event, sizeof(event));
|
||||
}
|
||||
|
||||
/* ── C API ── */
|
||||
|
||||
extern "C" {
|
||||
@@ -745,6 +771,81 @@ int gui_bridge_post_uasync_owned_fn(void (*fn)(void*), void* arg) {
|
||||
return post_command(fn, arg, true);
|
||||
}
|
||||
|
||||
/* Копия команды и её post принимаются одной операцией с привязкой к живому ядру. */
|
||||
int gui_bridge_member_files_request(uint64_t group, uint64_t server, const struct mf_message* message) {
|
||||
if (!group || !server || !message || !message->request_id || message->command < MF_LIST || message->command > MF_QUOTA ||
|
||||
message->data_len > MF_BLOCK_SIZE || strnlen(message->path, sizeof(message->path)) > MF_PATH_MAX ||
|
||||
strnlen(message->target, sizeof(message->target)) > MF_PATH_MAX) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: invalid request group=%llu server=%llu",
|
||||
(unsigned long long)group, (unsigned long long)server); return -1;
|
||||
}
|
||||
std::lock_guard<std::mutex> guard(bridge_mutex);
|
||||
if (!g_receiver || !g_inst || !g_ua || !uasync_is_running(g_ua)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file bridge: request rejected, core unavailable id=%llu command=%s",
|
||||
(unsigned long long)message->request_id, mf_command_text(message->command)); return -1;
|
||||
}
|
||||
auto* request = static_cast<mf_gui_request*>(u_calloc(1, sizeof(mf_gui_request)));
|
||||
if (!request) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: request snapshot allocation failed id=%llu",
|
||||
(unsigned long long)message->request_id); return -1;
|
||||
}
|
||||
request->inst = g_inst; request->group = group; request->server = server; request->message = *message;
|
||||
if (post_command(member_files_gui_request, request, true, cancel_member_files_request) < 0) {
|
||||
u_free(request); DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: request queue rejected id=%llu",
|
||||
(unsigned long long)message->request_id); return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "file bridge: request queued id=%llu command=%s group=%llu server=%llu owner=%llu path=%s",
|
||||
(unsigned long long)message->request_id, mf_command_text(message->command), (unsigned long long)group,
|
||||
(unsigned long long)server, (unsigned long long)message->owner, message->path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Поле inst входа не используется: GUI не получает указатель, способный устареть до enqueue. */
|
||||
int gui_bridge_member_files_transfer(const struct mf_transfer_request* source) {
|
||||
if (!source || !source->id || !source->group || !source->server || !source->owner || !mf_path_valid(source->remote, 0) ||
|
||||
!source->local[0] || strnlen(source->local, sizeof(source->local)) > MF_PATH_MAX) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: invalid transfer snapshot"); return -1;
|
||||
}
|
||||
std::lock_guard<std::mutex> guard(bridge_mutex);
|
||||
if (!g_receiver || !g_inst || !g_ua || !uasync_is_running(g_ua)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file bridge: transfer rejected, core unavailable id=%llu",
|
||||
(unsigned long long)source->id); return -1;
|
||||
}
|
||||
auto* request = static_cast<mf_transfer_request*>(u_calloc(1, sizeof(mf_transfer_request)));
|
||||
if (!request) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: transfer snapshot allocation failed id=%llu",
|
||||
(unsigned long long)source->id); return -1;
|
||||
}
|
||||
*request = *source; request->inst = g_inst;
|
||||
if (post_command(member_files_gui_transfer, request, true, cancel_member_files_transfer) < 0) {
|
||||
u_free(request); DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: transfer queue rejected id=%llu",
|
||||
(unsigned long long)source->id); return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "file bridge: transfer queued id=%llu group=%llu server=%llu owner=%llu upload=%d remote=%s local=%s",
|
||||
(unsigned long long)source->id, (unsigned long long)source->group, (unsigned long long)source->server,
|
||||
(unsigned long long)source->owner, source->upload, source->remote, source->local);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* После исполнения отменяет native handle; при detach до исполнения payload просто освобождается. */
|
||||
int gui_bridge_member_files_cancel(uint64_t id) {
|
||||
std::lock_guard<std::mutex> guard(bridge_mutex);
|
||||
if (!id || !g_inst || !g_ua || !uasync_is_running(g_ua)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file bridge: cancel rejected id=%llu core_available=%d",
|
||||
(unsigned long long)id, g_inst && g_ua && uasync_is_running(g_ua)); return -1;
|
||||
}
|
||||
auto* request = static_cast<mf_cancel_request*>(u_calloc(1, sizeof(mf_cancel_request)));
|
||||
if (!request) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: cancel snapshot allocation failed id=%llu", (unsigned long long)id); return -1;
|
||||
}
|
||||
request->inst = g_inst; request->id = id;
|
||||
if (post_command(member_files_gui_cancel, request, true) < 0) {
|
||||
u_free(request); DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file bridge: cancel queue rejected id=%llu", (unsigned long long)id); return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "file bridge: cancel queued id=%llu", (unsigned long long)id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Сериализация и публикация образуют одну границу владения с detach ядра. */
|
||||
int gui_bridge_post_setting(enum gui_setting_target target, const char* key, const char* value) {
|
||||
if ((target != GUI_SETTING_UI_STATE && target != GUI_SETTING_CHAT) || !key || !key[0] || !value) {
|
||||
|
||||
Reference in new issue
Block a user