From 0f36248d1ed0c82cfa90eb6460a3fd91d4f72cc8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 27 Oct 2026 23:15:38 +0100 Subject: [PATCH] Own and bind desktop radio call commands inside the bridge --- tools/chatgui/transport/gui_bridge.h | 11 ++++++ tools/chatgui/transport/gui_bridge_impl.cpp | 38 +++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tools/chatgui/transport/gui_bridge.h b/tools/chatgui/transport/gui_bridge.h index dff16990..f11aa4f5 100644 --- a/tools/chatgui/transport/gui_bridge.h +++ b/tools/chatgui/transport/gui_bridge.h @@ -102,6 +102,17 @@ enum gui_call_action { GUI_CALL_ACCEPT, GUI_CALL_DECLINE, GUI_CALL_HANGUP, GUI_C int gui_bridge_call_start(const char* channel, uint64_t peer, uint64_t call_id); // NUL-строка 1..63 байта, peer/id ненулевые. int gui_bridge_call_action(enum gui_call_action action, uint64_t call_id); // Только перечисленные действия, call_id ненулевой. +/* Приглашение в рацию: GUI передаёт значения без instance/heap-аргументов. + * START требует ненулевые id/group/peer; остальные действия — ненулевой id и group=peer=0. + * Под mutex привязывает копию к текущему running-ядру и передаёт владение очереди. + * 0 — принято, результат приходит через CHAT_EVT_RADIO_CALL; -1 — отказ с логом без оставшейся памяти. + * Detach до исполнения отменяет команду и освобождает её, не вызывая native API. */ +enum gui_radio_call_action { + GUI_RADIO_CALL_START, GUI_RADIO_CALL_READY, GUI_RADIO_CALL_ACCEPT, GUI_RADIO_CALL_DECLINE, + GUI_RADIO_CALL_CANCEL, GUI_RADIO_CALL_FAIL, GUI_RADIO_CALL_REJECT_BUSY, GUI_RADIO_CALL_CONTINUE +}; +int gui_bridge_radio_call(enum gui_radio_call_action action, uint64_t id, uint64_t group, uint64_t peer); + /* Назначение пары key/value: локальный ui_state SQLite либо live chat_setting ядра. */ enum gui_setting_target { GUI_SETTING_UI_STATE, GUI_SETTING_CHAT }; /* Скопировать NUL-строки key/value в собственный запрос и поставить его текущему ядру под mutex моста. diff --git a/tools/chatgui/transport/gui_bridge_impl.cpp b/tools/chatgui/transport/gui_bridge_impl.cpp index b4e8d530..4b47e4cf 100644 --- a/tools/chatgui/transport/gui_bridge_impl.cpp +++ b/tools/chatgui/transport/gui_bridge_impl.cpp @@ -26,6 +26,7 @@ extern "C" { #include "../../../src/chat/chat_join_port.h" #include "../../../src/dm/dm_core.h" #include "../../../src/call/call.h" +#include "../../../src/radio/radio_call.h" } /* ── Внутренний объект-приёмник в GUI-потоке ── */ @@ -828,6 +829,43 @@ int gui_bridge_call_action(enum gui_call_action action, uint64_t call_id) { return 0; } +/* Значения GUI становятся owned native-запросом одной операцией с проверкой ядра и enqueue. */ +int gui_bridge_radio_call(enum gui_radio_call_action action, uint64_t id, uint64_t group, uint64_t peer) { + int nativeAction = 0; + const char* name = nullptr; + switch (action) { + case GUI_RADIO_CALL_START: nativeAction = RADIO_CALL_START; name = "start"; break; + case GUI_RADIO_CALL_READY: nativeAction = RADIO_CALL_READY; name = "ready"; break; + case GUI_RADIO_CALL_ACCEPT: nativeAction = RADIO_CALL_ACCEPT; name = "accept"; break; + case GUI_RADIO_CALL_DECLINE: nativeAction = RADIO_CALL_DECLINE; name = "decline"; break; + case GUI_RADIO_CALL_CANCEL: nativeAction = RADIO_CALL_CANCEL; name = "cancel"; break; + case GUI_RADIO_CALL_FAIL: nativeAction = RADIO_CALL_FAIL; name = "fail"; break; + case GUI_RADIO_CALL_REJECT_BUSY: nativeAction = RADIO_CALL_REJECT_BUSY; name = "reject_busy"; break; + case GUI_RADIO_CALL_CONTINUE: nativeAction = RADIO_CALL_CONTINUE; name = "continue"; break; + } + if (!name || !id || (action == GUI_RADIO_CALL_START ? !group || !peer : group || peer)) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "radio call bridge: invalid command action=%d id=%llu group=%llu peer=%llu", + action, (unsigned long long)id, (unsigned long long)group, (unsigned long long)peer); return -1; + } + std::lock_guard guard(bridge_mutex); + if (!g_inst || !g_ua || !uasync_is_running(g_ua)) { + DEBUG_WARN(DEBUG_CATEGORY_RADIO, "radio call bridge: core unavailable action=%s id=%llu", name, (unsigned long long)id); return -1; + } + auto* request = static_cast(u_calloc(1, sizeof(radio_call_request))); + if (!request) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "radio call bridge: request allocation failed action=%s id=%llu", name, (unsigned long long)id); + return -1; + } + request->inst = g_inst; request->id = id; request->group = group; request->peer = peer; request->action = nativeAction; + if (post_command(radio_call_trampoline, request, true) < 0) { + u_free(request); + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "radio call bridge: queue rejected action=%s id=%llu", name, (unsigned long long)id); return -1; + } + DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "radio call bridge: queued action=%s id=%llu group=%llu peer=%llu", + name, (unsigned long long)id, (unsigned long long)group, (unsigned long long)peer); + return 0; +} + /* Копия команды и её 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 ||