chatgui: create group, unified logging, fix uasync_post epoll bug
- Add CreateGroupDialog with group name input
- Generate X25519+Ed25519 keypairs, random uint64 channel_id,
Ed25519 signature, write to DB via uasync thread
- chat_core_create_channel(): create msg table, topo_node_sqlite_channel_put()
- GUI_EVT_CHANNEL_UPDATED notification to reload channel list
- Per-category debug config: debug_level= + debug_categories= in [gui]
- Unified logging via debug_config: all threads write to same file/console
- debug_enable_console(1) to mirror file output to stderr
- DEBUG_LEVEL_DISABLED=-1: truly disable category, NONE=0 fallback to global
- Fix uasync_post under epoll: process_posted_tasks was never called
- Fix MainWindow constructor parameter ordering (dbPath vs debugFile)
- debug_ui.h: append mode ('a' instead of 'w')
This commit is contained in:
1 parent
a9a6b6bb10
commit
de7841f33a
26 files changed
+761
-265
No files matched your search
@@ -5,6 +5,7 @@
|
||||
#include "invitedialog.h"
|
||||
#include "joindialog.h"
|
||||
#include "settingsdialog.h"
|
||||
#include "creategroupdialog.h"
|
||||
#include "invite_link.h"
|
||||
#include "../db/db_manager.h"
|
||||
#include "../transport/utun_node.h"
|
||||
@@ -16,6 +17,14 @@
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
|
||||
extern "C" {
|
||||
#include "../transport/chat_core.h"
|
||||
#include "../../lib/mem.h"
|
||||
#include "../../lib/debug_config.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
}
|
||||
|
||||
static MainWindow* s_mainWindow = nullptr;
|
||||
|
||||
static void onMsgReceivedCallback(const char* ch_id, int ch_id_len) {
|
||||
@@ -24,8 +33,16 @@ static void onMsgReceivedCallback(const char* ch_id, int ch_id_len) {
|
||||
s_mainWindow->onMessageReceived(ch_id);
|
||||
}
|
||||
|
||||
static void onChannelUpdatedCallback(const char* ch_id, int ch_id_len) {
|
||||
Q_UNUSED(ch_id_len);
|
||||
Q_UNUSED(ch_id);
|
||||
if (s_mainWindow)
|
||||
s_mainWindow->reloadChannels();
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
|
||||
const QString& dbPath, const QString& debugFile)
|
||||
const QString& dbPath, const QString& debugFile,
|
||||
const QString& debugLevel, const QString& debugCategories)
|
||||
: QMainWindow(parent)
|
||||
, m_channelList(nullptr)
|
||||
, m_messageList(nullptr)
|
||||
@@ -36,6 +53,8 @@ MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
|
||||
, m_cfgPath(cfgPath)
|
||||
, m_cfgDbPath(dbPath)
|
||||
, m_cfgDebugFile(debugFile)
|
||||
, m_cfgDebugLevel(debugLevel)
|
||||
, m_cfgDebugCategories(debugCategories)
|
||||
{
|
||||
setWindowTitle("Chat");
|
||||
resize(900, 600);
|
||||
@@ -45,6 +64,7 @@ MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
|
||||
if (m_db && m_db->isOpen()) {
|
||||
s_mainWindow = this;
|
||||
gui_bridge_set_msg_received_cb(onMsgReceivedCallback);
|
||||
gui_bridge_set_channel_updated_cb(onChannelUpdatedCallback);
|
||||
|
||||
setupNode();
|
||||
setupMessaging();
|
||||
@@ -59,6 +79,8 @@ MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
|
||||
this, &MainWindow::showInviteDialog);
|
||||
connect(m_channelList, &ChannelList::joinRequested,
|
||||
this, &MainWindow::showJoinDialog);
|
||||
connect(m_channelList, &ChannelList::createGroupRequested,
|
||||
this, &MainWindow::onCreateGroupRequested);
|
||||
connect(m_channelList, &ChannelList::settingsRequested,
|
||||
this, &MainWindow::showSettings);
|
||||
|
||||
@@ -109,6 +131,10 @@ void MainWindow::setupNode() {
|
||||
|
||||
if (!m_cfgDebugFile.isEmpty())
|
||||
m_node->setDebugFile(m_cfgDebugFile);
|
||||
if (!m_cfgDebugLevel.isEmpty())
|
||||
m_node->setDebugLevel(m_cfgDebugLevel);
|
||||
if (!m_cfgDebugCategories.isEmpty())
|
||||
m_node->setDebugCategories(m_cfgDebugCategories);
|
||||
|
||||
if (!m_cfgDbPath.isEmpty())
|
||||
m_node->setDbPath(m_cfgDbPath);
|
||||
@@ -208,7 +234,117 @@ void MainWindow::showSettings() {
|
||||
}
|
||||
|
||||
void MainWindow::onMessageReceived(const char* ch_id) {
|
||||
qDebug("MainWindow: msg received ch=%s", ch_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "MainWindow: msg received ch=%s", ch_id);
|
||||
if (m_messageList)
|
||||
m_messageList->refresh();
|
||||
}
|
||||
|
||||
void MainWindow::reloadChannels() {
|
||||
if (m_channelList)
|
||||
m_channelList->loadChannels();
|
||||
}
|
||||
|
||||
void MainWindow::onCreateGroupRequested() {
|
||||
if (!m_node || !m_node->isRunning()) {
|
||||
QMessageBox::warning(this, "Error", "Node is not running.");
|
||||
return;
|
||||
}
|
||||
if (!gui_bridge_is_uasync_ready()) {
|
||||
QMessageBox::warning(this, "Error", "uTun thread is not ready yet. Please wait and try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
CreateGroupDialog dlg(this);
|
||||
if (dlg.exec() != QDialog::Accepted) return;
|
||||
|
||||
QString name = dlg.groupName();
|
||||
if (name.isEmpty()) return;
|
||||
|
||||
/* генерация X25519 ключей */
|
||||
uint8_t x25519_pub[32] = {0}, x25519_priv[32] = {0};
|
||||
{
|
||||
EVP_PKEY* pkey = nullptr;
|
||||
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, nullptr);
|
||||
if (ctx) {
|
||||
EVP_PKEY_keygen_init(ctx);
|
||||
EVP_PKEY_generate(ctx, &pkey);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
if (pkey) {
|
||||
size_t pkLen = 32, skLen = 32;
|
||||
EVP_PKEY_get_raw_public_key(pkey, x25519_pub, &pkLen);
|
||||
EVP_PKEY_get_raw_private_key(pkey, x25519_priv, &skLen);
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
}
|
||||
|
||||
/* генерация Ed25519 ключей */
|
||||
uint8_t ed25519_pub[32] = {0}, ed25519_priv[32] = {0};
|
||||
EVP_PKEY* ed_pkey = nullptr;
|
||||
{
|
||||
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr);
|
||||
if (ctx) {
|
||||
EVP_PKEY_keygen_init(ctx);
|
||||
EVP_PKEY_generate(ctx, &ed_pkey);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
if (ed_pkey) {
|
||||
size_t pkLen = 32, skLen = 32;
|
||||
EVP_PKEY_get_raw_public_key(ed_pkey, ed25519_pub, &pkLen);
|
||||
EVP_PKEY_get_raw_private_key(ed_pkey, ed25519_priv, &skLen);
|
||||
}
|
||||
}
|
||||
|
||||
/* случайный channel_id (uint64 → decimal string) */
|
||||
uint64_t chId = 0;
|
||||
RAND_bytes((uint8_t*)&chId, sizeof(chId));
|
||||
QString channelId = QString::number(chId);
|
||||
|
||||
/* owner_node_id из instance */
|
||||
uint64_t ownerNodeId = m_node->nodeIdHex().toULongLong(nullptr, 16);
|
||||
|
||||
/* Ed25519 подпись: channel_id || name || owner_node_id(8 LE) || x25519_pub(32) || ed25519_pub(32) */
|
||||
uint8_t sig[64] = {0};
|
||||
if (ed_pkey) {
|
||||
QByteArray nameUtf8 = name.toUtf8();
|
||||
QByteArray chIdUtf8 = channelId.toUtf8();
|
||||
size_t msgLen = chIdUtf8.size() + 1 + nameUtf8.size() + 1 + 8 + 32 + 32;
|
||||
uint8_t* msg = (uint8_t*)malloc(msgLen);
|
||||
if (msg) {
|
||||
uint8_t* p = msg;
|
||||
memcpy(p, chIdUtf8.constData(), chIdUtf8.size()); p += chIdUtf8.size(); *p++ = '\0';
|
||||
memcpy(p, nameUtf8.constData(), nameUtf8.size()); p += nameUtf8.size(); *p++ = '\0';
|
||||
memcpy(p, &ownerNodeId, 8); p += 8;
|
||||
memcpy(p, x25519_pub, 32); p += 32;
|
||||
memcpy(p, ed25519_pub, 32); p += 32;
|
||||
|
||||
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
|
||||
if (mdctx) {
|
||||
EVP_DigestSignInit(mdctx, nullptr, nullptr, nullptr, ed_pkey);
|
||||
size_t siglen = 64;
|
||||
EVP_DigestSign(mdctx, sig, &siglen, msg, msgLen);
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
EVP_PKEY_free(ed_pkey);
|
||||
}
|
||||
|
||||
/* отправляем в uasync-поток */
|
||||
struct chat_channel_create* req = (struct chat_channel_create*)u_malloc(sizeof(*req));
|
||||
memset(req, 0, sizeof(*req));
|
||||
snprintf(req->channel_id, sizeof(req->channel_id), "%s", qPrintable(channelId));
|
||||
snprintf(req->name, sizeof(req->name), "%s", qPrintable(name));
|
||||
req->owner_node_id = ownerNodeId;
|
||||
req->is_dm = 0;
|
||||
memcpy(req->x25519_pubkey, x25519_pub, 32);
|
||||
memcpy(req->x25519_privkey, x25519_priv, 32);
|
||||
memcpy(req->ed25519_pubkey, ed25519_pub, 32);
|
||||
memcpy(req->ed25519_privkey, ed25519_priv, 32);
|
||||
memcpy(req->signature, sig, 64);
|
||||
|
||||
gui_bridge_post_uasync_fn(chat_core_create_channel_trampoline, req);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "MainWindow: create group request posted ch=%s name=%s",
|
||||
qPrintable(channelId), qPrintable(name));
|
||||
}
|
||||
Reference in new issue
Block a user