- debug_ui.h: remove NDEBUG guard so GUI_ERROR works in Release builds - invite_link.h/cpp: add error field to InviteData with specific failure reason - joindialog: show exact decode error in QLabel instead of generic message - chat_sync: implement invite connect flow (CHANNEL_INFO_REQ/RESP, JOIN, WELCOME) - topo_node_sqlite: node/address table init and lookup - utun_node: getInviteAddresses fallback from ETCP sockets - minor fixes in mainwindow, chat_core, gui_bridge
145 lines
4.7 KiB
C++
145 lines
4.7 KiB
C++
#include "gui_bridge.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"
|
|
}
|
|
|
|
/* ── Внутренний объект-приёмник в 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 struct UASYNC* g_ua = nullptr;
|
|
|
|
/* ── GuiBridgeReceiver implementation ── */
|
|
|
|
void GuiBridgeReceiver::processPost(int eventType, QByteArray data) {
|
|
const uint8_t* d = (const uint8_t*)data.constData();
|
|
int dlen = data.size();
|
|
|
|
switch (eventType) {
|
|
case GUI_EVT_MSG_RECEIVED:
|
|
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_DEBUG, "gui_bridge: MSG_RECEIVED ch=%s", qPrintable(chId));
|
|
if (g_msg_received_cb) g_msg_received_cb((const char*)d + 1, chLen);
|
|
} 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_DEBUG, "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_DEBUG, "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_DEBUG, "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;
|
|
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_post(int event_type, const uint8_t* data, int data_len) {
|
|
if (!g_receiver) 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);
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "gui_bridge_post_uasync_fn: posted fn=%p arg=%p", (void*)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;
|
|
}
|
|
|
|
} /* extern "C" */
|
|
|
|
#include "gui_bridge_impl.moc"
|