Add battery optimization controls and configurable boot startup. Keep message sounds in the application and render general settings lazily to avoid ANRs. Add animated emoji controls and live BGP availability for direct-message calls on Android and desktop.
590 lines
22 KiB
C++
590 lines
22 KiB
C++
#include "gui_bridge.h"
|
|
#include "chat/chat_event.h"
|
|
|
|
#include <QObject>
|
|
#include <QMetaObject>
|
|
#include <QByteArray>
|
|
#include <cstring>
|
|
|
|
extern "C" {
|
|
#include "../../../lib/u_async.h"
|
|
#include "../../../lib/mem.h"
|
|
#include "../../../lib/debug_config.h"
|
|
#include "../../../src/routing_layer/topo_node.h"
|
|
#include "../../../src/routing_layer/topo_group.h"
|
|
}
|
|
|
|
/* ── Внутренний объект-приёмник в GUI-потоке ── */
|
|
|
|
class GuiBridgeReceiver : public QObject {
|
|
Q_OBJECT
|
|
public:
|
|
void* ua = nullptr;
|
|
|
|
GuiBridgeReceiver(QObject* parent = nullptr) : QObject(parent) {}
|
|
|
|
Q_INVOKABLE void processPost(int eventType, QByteArray data);
|
|
};
|
|
|
|
static GuiBridgeReceiver* g_receiver = nullptr;
|
|
static gui_connect_result_fn g_connect_result_cb = nullptr;
|
|
static gui_msg_received_fn g_msg_received_cb = nullptr;
|
|
static gui_channel_updated_fn g_channel_updated_cb = nullptr;
|
|
static gui_my_node_id_fn g_my_node_id_cb = nullptr;
|
|
static gui_auto_connect_status_fn g_auto_connect_status_cb = nullptr;
|
|
static gui_channel_peers_online_fn g_channel_peers_online_cb = nullptr;
|
|
static gui_db_ready_fn g_db_ready_cb = nullptr;
|
|
static gui_status_refresh_fn g_status_refresh_cb = nullptr;
|
|
static gui_attachment_downloaded_fn g_attachment_downloaded_cb = nullptr;
|
|
static gui_download_progress_fn g_download_progress_cb = nullptr;
|
|
static gui_nodeinfo_update_fn g_nodeinfo_update_cb = nullptr;
|
|
static gui_invite_received_fn g_invite_received_cb = nullptr;
|
|
static gui_conn_list_fn g_conn_list_cb = nullptr;
|
|
static gui_conn_metrics_fn g_conn_metrics_cb = nullptr;
|
|
static gui_member_detail_fn g_member_detail_cb = nullptr;
|
|
static gui_member_list_fn g_member_list_cb = nullptr;
|
|
static gui_member_updated_fn g_member_updated_cb = nullptr;
|
|
static gui_member_removed_fn g_member_removed_cb = nullptr;
|
|
static gui_bgp_info_fn g_bgp_info_cb = nullptr;
|
|
static gui_admin_key_received_fn g_admin_key_received_cb = nullptr;
|
|
static gui_invite_link_ready_fn g_invite_link_ready_cb = nullptr;
|
|
static gui_invite_candidates_fn g_invite_candidates_cb = nullptr;
|
|
static gui_call_incoming_fn g_call_incoming_cb = nullptr;
|
|
static gui_call_id_fn g_call_ringing_cb = nullptr;
|
|
static gui_call_id_fn g_call_accepted_cb = nullptr;
|
|
static gui_call_ended_fn g_call_ended_cb = nullptr;
|
|
static gui_call_ended_fn g_call_declined_cb = nullptr;
|
|
static gui_call_error_fn g_call_error_cb = nullptr;
|
|
static gui_call_stats_fn g_call_stats_cb = nullptr;
|
|
static gui_call_path_fn g_call_path_cb = nullptr;
|
|
static gui_call_connection_fn g_call_connection_cb = nullptr;
|
|
static gui_radio_talk_fn g_radio_talk_cb = nullptr;
|
|
static gui_dm_msg_received_fn g_dm_msg_received_cb = nullptr;
|
|
static gui_dm_conv_updated_fn g_dm_conv_updated_cb = nullptr;
|
|
static gui_dm_messages_fn g_dm_messages_cb = nullptr;
|
|
static gui_dm_messages_fn g_attachment_preparation_cb = nullptr;
|
|
static gui_dm_messages_fn g_dm_call_route_cb = nullptr;
|
|
static gui_network_changed_fn g_network_changed_cb = nullptr;
|
|
static struct UASYNC* g_ua = nullptr;
|
|
static struct UTUN_INSTANCE* g_inst = nullptr;
|
|
|
|
/* ── GuiBridgeReceiver implementation ── */
|
|
|
|
void GuiBridgeReceiver::processPost(int eventType, QByteArray data) {
|
|
const uint8_t* d = (const uint8_t*)data.constData();
|
|
int dlen = data.size();
|
|
|
|
if (g_network_changed_cb && (eventType == 4 || eventType == 5 || eventType == 12 || eventType == 13 ||
|
|
eventType == 16 || eventType == 17 || eventType == 24 || eventType == 25 || eventType == 31 || eventType == 33))
|
|
g_network_changed_cb(eventType);
|
|
switch (eventType) {
|
|
case CHAT_EVT_DM_CALL_ROUTE:
|
|
if (g_dm_call_route_cb) g_dm_call_route_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_MSG_RECEIVED:
|
|
if (dlen >= 2) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen + 8) {
|
|
uint64_t author = 0;
|
|
memcpy(&author, d + 1 + chLen, 8);
|
|
QString chId = QString::fromUtf8((const char*)d + 1, chLen);
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: MSG_RECEIVED ch=%s author=%llu",
|
|
qPrintable(chId), (unsigned long long)author);
|
|
if (g_msg_received_cb) g_msg_received_cb((const char*)d + 1, chLen, author);
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: MSG_RECEIVED invalid data length %d", dlen);
|
|
}
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: MSG_RECEIVED data too short %d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_CONNECT_RESULT:
|
|
if (dlen >= 20) {
|
|
uint64_t nodeId, channelId; int result;
|
|
memcpy(&nodeId, d, 8); memcpy(&result, d + 8, 4); memcpy(&channelId, d + 12, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "gui_bridge: CONNECT_RESULT node=0x%016llx ch=%llu result=%d",
|
|
(unsigned long long)nodeId, (unsigned long long)channelId, result);
|
|
if (g_connect_result_cb) g_connect_result_cb(nodeId, channelId, result);
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: CONNECT_RESULT data too short %d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_NEW_PEER:
|
|
if (dlen >= 8) {
|
|
uint64_t nodeId; memcpy(&nodeId, d, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "gui_bridge: NEW_PEER node=0x%016llx", (unsigned long long)nodeId);
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: NEW_PEER data too short %d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_CHANNEL_UPDATED:
|
|
if (dlen >= 2) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen) {
|
|
QString chId = QString::fromUtf8((const char*)d + 1, chLen);
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: CHANNEL_UPDATED ch=%s", qPrintable(chId));
|
|
if (g_channel_updated_cb) g_channel_updated_cb((const char*)d + 1, chLen);
|
|
}
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: CHANNEL_UPDATED data too short %d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_MY_NODE_ID:
|
|
if (dlen >= 8) {
|
|
uint64_t nid; memcpy(&nid, d, 8);
|
|
if (g_my_node_id_cb) g_my_node_id_cb(nid);
|
|
}
|
|
break;
|
|
case GUI_EVT_AUTO_CONNECT_STATUS:
|
|
if (dlen >= 7) {
|
|
uint8_t status = d[0];
|
|
uint16_t total_tried; memcpy(&total_tried, d + 1, 2);
|
|
uint16_t node_count; memcpy(&node_count, d + 3, 2);
|
|
uint16_t connected; memcpy(&connected, d + 5, 2);
|
|
const char* st_str = status == 0 ? "in_progress" : status == 1 ? "done" : "stopped";
|
|
if (status != 0) DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "gui_bridge: AUTO_CONNECT %s tried=%u/%u connected=%u", st_str, total_tried, node_count, connected);
|
|
if (g_auto_connect_status_cb) g_auto_connect_status_cb(status, total_tried, node_count, connected);
|
|
}
|
|
break;
|
|
case GUI_EVT_CHANNEL_PEERS_ONLINE:
|
|
if (dlen >= 3) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 3 + chLen) {
|
|
uint16_t online; memcpy(&online, d + 1 + chLen, 2);
|
|
static char lastChId[256] = {0};
|
|
static uint16_t lastOnline = 0xFFFF;
|
|
if (chLen != (uint8_t)strlen(lastChId) || memcmp(lastChId, d + 1, chLen) != 0 || online != lastOnline) {
|
|
memcpy(lastChId, d + 1, chLen); lastChId[chLen] = '\0';
|
|
lastOnline = online;
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: CHANNEL_PEERS_ONLINE ch=%.*s online=%u", chLen, (const char*)d + 1, online);
|
|
}
|
|
if (g_channel_peers_online_cb) g_channel_peers_online_cb((const char*)d + 1, chLen, online);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_DB_READY:
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: DB_READY (chat DB tables created)");
|
|
if (g_db_ready_cb) g_db_ready_cb();
|
|
break;
|
|
case GUI_EVT_STATUS_REFRESH:
|
|
if (g_status_refresh_cb) g_status_refresh_cb((const char*)d, dlen);
|
|
break;
|
|
case GUI_EVT_NODE_CHANGED:
|
|
if (dlen >= 8) {
|
|
uint64_t nodeId; memcpy(&nodeId, d, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "gui_bridge: NODE_CHANGED node=0x%016llx — pubkey changed, connection closed", (unsigned long long)nodeId);
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: NODE_CHANGED data too short %d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_ATTACHMENT_DOWNLOADED:
|
|
if (dlen >= 2) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen + 8) {
|
|
int64_t msgId = 0; memcpy(&msgId, d + 1 + chLen, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "gui_bridge: ATTACHMENT_DOWNLOADED ch=%.*s msgId=%lld", chLen, (const char*)d + 1, (long long)msgId);
|
|
if (g_attachment_downloaded_cb) g_attachment_downloaded_cb((const char*)d + 1, chLen, msgId);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_DOWNLOAD_PROGRESS:
|
|
if (dlen >= 2) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen + 16) {
|
|
int64_t msgId = 0; memcpy(&msgId, d + 1 + chLen, 8);
|
|
int32_t bd = 0, nb = 0; memcpy(&bd, d + 1 + chLen + 8, 4); memcpy(&nb, d + 1 + chLen + 12, 4);
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "gui_bridge: DOWNLOAD_PROGRESS ch=%.*s msgId=%lld %d/%d", chLen, (const char*)d + 1, (long long)msgId, bd, nb);
|
|
if (g_download_progress_cb) g_download_progress_cb((const char*)d + 1, chLen, msgId, bd, nb);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_NODEINFO_UPDATE:
|
|
if (g_nodeinfo_update_cb) g_nodeinfo_update_cb(d, dlen);
|
|
break;
|
|
case 18: /* CHAT_EVT_INVITE_RECEIVED */
|
|
if (g_invite_received_cb) g_invite_received_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_CONN_LIST:
|
|
if (g_conn_list_cb) g_conn_list_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_CONN_METRICS:
|
|
if (g_conn_metrics_cb) g_conn_metrics_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_MEMBER_DETAIL:
|
|
if (g_member_detail_cb) g_member_detail_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_MEMBER_LIST:
|
|
if (g_member_list_cb) g_member_list_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_MEMBER_UPDATED:
|
|
if (g_member_updated_cb) g_member_updated_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_MEMBER_REMOVED:
|
|
if (g_member_removed_cb) g_member_removed_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_BGP_INFO:
|
|
if (g_bgp_info_cb) g_bgp_info_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_ADMIN_KEY_RECEIVED:
|
|
if (dlen >= 2) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen + 8) {
|
|
uint64_t from; memcpy(&from, d + 1 + chLen, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: ADMIN_KEY_RECEIVED ch=%.*s from=0x%016llx",
|
|
chLen, (const char*)d + 1, (unsigned long long)from);
|
|
if (g_admin_key_received_cb) g_admin_key_received_cb(d, dlen);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_INVITE_LINK_READY:
|
|
if (dlen >= 11) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen < 1 + chLen + 10) break;
|
|
uint64_t requestId; memcpy(&requestId, d + 1 + chLen, 8);
|
|
uint16_t linkLen; memcpy(&linkLen, d + 1 + chLen + 8, 2);
|
|
if (dlen >= 1 + chLen + 10 + linkLen) {
|
|
QByteArray link((const char*)d + 1 + chLen + 10, linkLen);
|
|
if (g_invite_link_ready_cb) g_invite_link_ready_cb((const char*)d + 1, chLen, requestId, link.constData());
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_INVITE_CANDIDATES:
|
|
if (dlen >= 2) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen + 10) {
|
|
if (g_invite_candidates_cb) g_invite_candidates_cb((const char*)d + 1, chLen, d + 1 + chLen, dlen - 1 - chLen);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_DM_MSG_RECEIVED:
|
|
if (dlen >= 2) {
|
|
uint8_t cl = d[0];
|
|
if (dlen >= 1 + cl + 8) {
|
|
uint64_t author; memcpy(&author, d + 1 + cl, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: DM_MSG_RECEIVED conv=%.*s author=%llu",
|
|
cl, (const char*)d + 1, (unsigned long long)author);
|
|
if (g_dm_msg_received_cb) g_dm_msg_received_cb((const char*)d + 1, cl, author);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_DM_CONV_UPDATED:
|
|
if (dlen >= 2) {
|
|
uint8_t cl = d[0];
|
|
if (dlen >= 1 + cl) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: DM_CONV_UPDATED conv=%.*s",
|
|
cl, (const char*)d + 1);
|
|
if (g_dm_conv_updated_cb) g_dm_conv_updated_cb((const char*)d + 1, cl);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_DM_MESSAGES:
|
|
if (g_dm_messages_cb) g_dm_messages_cb(d, dlen);
|
|
break;
|
|
case CHAT_EVT_ATTACHMENT_PREPARATION:
|
|
if (g_attachment_preparation_cb) g_attachment_preparation_cb(d, dlen);
|
|
break;
|
|
case GUI_EVT_CALL_INCOMING:
|
|
if (dlen >= 1 + 8 + 8) {
|
|
uint8_t chLen = d[0];
|
|
if (dlen >= 1 + chLen + 8 + 8) {
|
|
uint64_t caller, callId;
|
|
memcpy(&caller, d + 1 + chLen, 8);
|
|
memcpy(&callId, d + 1 + chLen + 8, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: CALL_INCOMING ch=%.*s caller=0x%016llx id=0x%016llx",
|
|
chLen, (const char*)d + 1, (unsigned long long)caller, (unsigned long long)callId);
|
|
if (g_call_incoming_cb) g_call_incoming_cb((const char*)d + 1, chLen, caller, callId);
|
|
}
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_RINGING:
|
|
if (dlen >= 8) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
if (g_call_ringing_cb) g_call_ringing_cb(callId);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_ACCEPTED:
|
|
if (dlen >= 8) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
if (g_call_accepted_cb) g_call_accepted_cb(callId);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_ENDED:
|
|
if (dlen >= 9) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
if (g_call_ended_cb) g_call_ended_cb(callId, d[8]);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_DECLINED:
|
|
if (dlen >= 9) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
if (g_call_declined_cb) g_call_declined_cb(callId, d[8]);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_ERROR:
|
|
if (dlen >= 9) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
uint8_t err = d[8];
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: CALL_ERROR id=0x%016llx err=%u text=%.*s",
|
|
(unsigned long long)callId, (unsigned)err, dlen - 9, (const char*)d + 9);
|
|
if (g_call_error_cb) g_call_error_cb(callId, err, (const char*)d + 9, dlen - 9);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_PATH:
|
|
if (dlen >= 9) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "gui_bridge: CALL_PATH id=0x%016llx text=%.*s",
|
|
(unsigned long long)callId, dlen - 8, (const char*)d + 8);
|
|
if (g_call_path_cb) g_call_path_cb(callId, (const char*)d + 8, dlen - 8);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_CONNECTION:
|
|
if (dlen == 17 && d[8] <= 3) {
|
|
uint64_t callId, nextHop;
|
|
memcpy(&callId, d, 8); memcpy(&nextHop, d + 9, 8);
|
|
if (g_call_connection_cb) g_call_connection_cb(callId, d[8], nextHop);
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_CALL, "gui_bridge: invalid CALL_CONNECTION size=%d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_CALL_STATS:
|
|
if (dlen == 24) {
|
|
uint64_t callId; memcpy(&callId, d, 8);
|
|
int values[8];
|
|
for (int i = 0; i < 8; i++) values[i] = (d[8 + i * 2] << 8) | d[9 + i * 2];
|
|
if (g_call_stats_cb) g_call_stats_cb(callId, values[0], values[1], values[2], values[3],
|
|
values[4], values[5], values[6], values[7]);
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_CALL, "gui_bridge: invalid CALL_STATS size=%d", dlen);
|
|
}
|
|
break;
|
|
case GUI_EVT_RADIO_TALK:
|
|
if (dlen >= 19) {
|
|
uint64_t groupId, src;
|
|
memcpy(&groupId, d, 8);
|
|
memcpy(&src, d + 8, 8);
|
|
uint8_t on = d[18];
|
|
if (g_radio_talk_cb) g_radio_talk_cb(groupId, src, on);
|
|
}
|
|
break;
|
|
default:
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge: unknown event type %d", eventType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ── C API ── */
|
|
|
|
extern "C" {
|
|
|
|
void gui_bridge_init(void) {
|
|
g_receiver = new GuiBridgeReceiver();
|
|
g_receiver->ua = g_ua;
|
|
}
|
|
|
|
void gui_bridge_set_uasync(struct UASYNC* ua) {
|
|
g_ua = ua;
|
|
if (g_receiver) g_receiver->ua = ua;
|
|
}
|
|
|
|
void gui_bridge_set_inst(struct UTUN_INSTANCE* inst) {
|
|
g_inst = inst;
|
|
}
|
|
|
|
struct UTUN_INSTANCE* gui_bridge_get_inst(void) {
|
|
return g_inst;
|
|
}
|
|
|
|
void gui_bridge_post(int event_type, const uint8_t* data, int data_len) {
|
|
if (!g_receiver) { DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge_post: g_receiver=NULL, dropping event %d", event_type); return; }
|
|
|
|
QByteArray d;
|
|
if (data_len > 0) d = QByteArray((const char*)data, data_len);
|
|
|
|
QMetaObject::invokeMethod(g_receiver, "processPost",
|
|
Qt::QueuedConnection,
|
|
Q_ARG(int, event_type),
|
|
Q_ARG(QByteArray, d));
|
|
}
|
|
|
|
void gui_bridge_post_uasync_fn(void (*fn)(void*), void* arg) {
|
|
if (!g_ua) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "gui_bridge_post_uasync_fn: g_ua=NULL, post dropped");
|
|
return;
|
|
}
|
|
if (!fn) return;
|
|
uasync_post(g_ua, fn, arg);
|
|
}
|
|
|
|
int gui_bridge_is_uasync_ready(void) {
|
|
return g_ua != NULL ? 1 : 0;
|
|
}
|
|
|
|
void gui_bridge_set_connect_result_cb(gui_connect_result_fn cb) {
|
|
g_connect_result_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_msg_received_cb(gui_msg_received_fn cb) {
|
|
g_msg_received_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_channel_updated_cb(gui_channel_updated_fn cb) {
|
|
g_channel_updated_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_my_node_id_cb(gui_my_node_id_fn cb) {
|
|
g_my_node_id_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_auto_connect_status_cb(gui_auto_connect_status_fn cb) {
|
|
g_auto_connect_status_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_channel_peers_online_cb(gui_channel_peers_online_fn cb) {
|
|
g_channel_peers_online_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_db_ready_cb(gui_db_ready_fn cb) {
|
|
g_db_ready_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_status_refresh_cb(gui_status_refresh_fn cb) {
|
|
g_status_refresh_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_attachment_downloaded_cb(gui_attachment_downloaded_fn cb) {
|
|
g_attachment_downloaded_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_download_progress_cb(gui_download_progress_fn cb) {
|
|
g_download_progress_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_nodeinfo_update_cb(gui_nodeinfo_update_fn cb) {
|
|
g_nodeinfo_update_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_invite_received_cb(gui_invite_received_fn cb) {
|
|
g_invite_received_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_conn_list_cb(gui_conn_list_fn cb) {
|
|
g_conn_list_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_conn_metrics_cb(gui_conn_metrics_fn cb) {
|
|
g_conn_metrics_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_member_detail_cb(gui_member_detail_fn cb) {
|
|
g_member_detail_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_member_list_cb(gui_member_list_fn cb) {
|
|
g_member_list_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_member_updated_cb(gui_member_updated_fn cb) {
|
|
g_member_updated_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_member_removed_cb(gui_member_removed_fn cb) {
|
|
g_member_removed_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_bgp_info_cb(gui_bgp_info_fn cb) {
|
|
g_bgp_info_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_admin_key_received_cb(gui_admin_key_received_fn cb) {
|
|
g_admin_key_received_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_invite_link_ready_cb(gui_invite_link_ready_fn cb) {
|
|
g_invite_link_ready_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_invite_candidates_cb(gui_invite_candidates_fn cb) {
|
|
g_invite_candidates_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_incoming_cb(gui_call_incoming_fn cb) {
|
|
g_call_incoming_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_ringing_cb(gui_call_id_fn cb) {
|
|
g_call_ringing_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_accepted_cb(gui_call_id_fn cb) {
|
|
g_call_accepted_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_ended_cb(gui_call_ended_fn cb) {
|
|
g_call_ended_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_declined_cb(gui_call_ended_fn cb) {
|
|
g_call_declined_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_error_cb(gui_call_error_fn cb) {
|
|
g_call_error_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_path_cb(gui_call_path_fn cb) {
|
|
g_call_path_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_call_connection_cb(gui_call_connection_fn cb) {
|
|
g_call_connection_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_radio_talk_cb(gui_radio_talk_fn cb) {
|
|
g_radio_talk_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_dm_msg_received_cb(gui_dm_msg_received_fn cb) {
|
|
g_dm_msg_received_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_network_changed_cb(gui_network_changed_fn cb) { g_network_changed_cb = cb; }
|
|
void gui_bridge_set_dm_call_route_cb(gui_dm_messages_fn cb) { g_dm_call_route_cb = cb; }
|
|
|
|
void gui_bridge_set_dm_conv_updated_cb(gui_dm_conv_updated_fn cb) {
|
|
g_dm_conv_updated_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_dm_messages_cb(gui_dm_messages_fn cb) {
|
|
g_dm_messages_cb = cb;
|
|
}
|
|
|
|
void gui_bridge_set_attachment_preparation_cb(gui_dm_messages_fn cb) {
|
|
g_attachment_preparation_cb = cb;
|
|
}
|
|
|
|
} /* extern "C" */
|
|
|
|
/* ── uTun nodeinfo callback (called from uasync thread) ── */
|
|
|
|
extern "C" void gui_nodeinfo_cb_impl(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq, void* arg) {
|
|
(void)arg;
|
|
if (!nq) return;
|
|
uint16_t best_rtt = topo_get_chain_rtt(nq);
|
|
uint8_t hop_count = 0;
|
|
topo_node_best_hop_list(nq, &hop_count, NULL);
|
|
uint8_t data[16];
|
|
memcpy(data, &nq->node_id, 8);
|
|
data[8] = nq->conn_presence;
|
|
data[9] = nq->conn_up;
|
|
memcpy(data + 10, &best_rtt, 2);
|
|
data[12] = hop_count;
|
|
data[13] = 0;
|
|
uint16_t bgp_nodes = group ? (uint16_t)queue_entry_count(group->nodes) : 0;
|
|
memcpy(data + 14, &bgp_nodes, 2);
|
|
gui_bridge_post(GUI_EVT_NODEINFO_UPDATE, data, sizeof(data));
|
|
}
|
|
|
|
#include "gui_bridge_impl.moc"
|
|
|
|
void gui_bridge_set_call_stats_cb(gui_call_stats_fn cb) { g_call_stats_cb = cb; }
|