fix: invite не затирает имя узла, имя читается из member_sync peers.userinfo
- conn_mgr_core.c: убрана запись node_name из cm_handle_invite_info_resp - topo_node_sqlite.c: name в nodes не перезаписывается пустой строкой - android_jni_bridge.c: bridge_get_node_name читает peers_<ch>.userinfo если nodes.name пуст
This commit is contained in:
1 parent
253129cb27
commit
e1e54df4f4
14 files changed
+234
-125
No files matched your search
@@ -183,7 +183,7 @@ void utun_bridge_send_message(const char* channel_id, const char* text) {
|
||||
if (!channel_id || !text) return;
|
||||
|
||||
struct UASYNC* ua = instance_lite_get_uasync();
|
||||
if (!ua) { bridge_log(BLEV_ERROR, "send: ua not ready"); return; }
|
||||
if (!uasync_is_running(ua)) return;
|
||||
|
||||
size_t datalen = strlen(text);
|
||||
struct chat_msg_submit* req = u_calloc(1, sizeof(struct chat_msg_submit) + datalen);
|
||||
@@ -236,10 +236,7 @@ void utun_bridge_connect_channel(const char* channel_id) {
|
||||
return;
|
||||
}
|
||||
struct UASYNC* ua = instance_lite_get_uasync();
|
||||
if (!ua) {
|
||||
bridge_log(BLEV_ERROR, "connect_channel: ua not ready, ch=%s", channel_id);
|
||||
return;
|
||||
}
|
||||
if (!uasync_is_running(ua)) return;
|
||||
char* cid = u_strdup(channel_id);
|
||||
if (!cid) return;
|
||||
bridge_log(BLEV_INFO, "connect_channel ch=%s", channel_id);
|
||||
@@ -267,15 +264,30 @@ static char* json_escape_alloc(const char* str) {
|
||||
return out;
|
||||
}
|
||||
|
||||
static void bridge_get_node_name(sqlite3* db, uint64_t node_id, char* out, size_t sz) {
|
||||
static void bridge_get_node_name(sqlite3* db, uint64_t node_id, const char* channel_id, char* out, size_t sz) {
|
||||
out[0] = '\0';
|
||||
if (!db || node_id == 0) return;
|
||||
sqlite3_stmt* st = NULL;
|
||||
if (sqlite3_prepare_v2(db, "SELECT name FROM nodes WHERE node_id=?", -1, &st, NULL) != SQLITE_OK) return;
|
||||
if (sqlite3_prepare_v2(db, "SELECT name FROM nodes WHERE node_id=?", -1, &st, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id);
|
||||
if (sqlite3_step(st) == SQLITE_ROW) {
|
||||
const char* n = (const char*)sqlite3_column_text(st, 0);
|
||||
if (n && n[0]) { snprintf(out, sz, "%s", n); sqlite3_finalize(st); return; }
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
}
|
||||
if (!channel_id || !channel_id[0]) return;
|
||||
char peers_tbl[80], sql[256];
|
||||
peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
|
||||
snprintf(sql, sizeof(sql), "SELECT userinfo FROM \"%s\" WHERE node_id=?", peers_tbl);
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) return;
|
||||
sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id);
|
||||
if (sqlite3_step(st) == SQLITE_ROW) {
|
||||
const char* n = (const char*)sqlite3_column_text(st, 0);
|
||||
if (n && n[0]) snprintf(out, sz, "%s", n);
|
||||
const char* ui = (const char*)sqlite3_column_text(st, 0);
|
||||
if (ui && ui[0]) {
|
||||
const char* ns = strstr(ui, "\"name\":\"");
|
||||
if (ns) { ns += 8; const char* ne = strchr(ns, '"'); if (ne && ne > ns) { size_t nl = (size_t)(ne - ns); if (nl >= sz) nl = sz - 1; memcpy(out, ns, nl); out[nl] = '\0'; } }
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
}
|
||||
@@ -323,7 +335,7 @@ char* utun_bridge_get_channels_json(void) {
|
||||
if (ds) { ds += 5; char* de = strchr((char*)ds, '"'); if (de) { size_t tl = (size_t)(de - ds); if (tl > 120) tl = 120; memcpy(txt, ds, tl); txt[tl] = '\0'; } }
|
||||
}
|
||||
char author_name[128];
|
||||
bridge_get_node_name(db, (uint64_t)author, author_name, sizeof(author_name));
|
||||
bridge_get_node_name(db, (uint64_t)author, ch_id, author_name, sizeof(author_name));
|
||||
if (!author_name[0])
|
||||
snprintf(author_name, sizeof(author_name), "0x%016llx", (unsigned long long)author);
|
||||
snprintf(last_msg, sizeof(last_msg), "%s: %s", author_name, txt);
|
||||
@@ -408,7 +420,7 @@ char* utun_bridge_get_messages_json(const char* channel_id, int limit) {
|
||||
first = 0;
|
||||
|
||||
char author_name[128];
|
||||
bridge_get_node_name(db, (uint64_t)node_id, author_name, sizeof(author_name));
|
||||
bridge_get_node_name(db, (uint64_t)node_id, channel_id, author_name, sizeof(author_name));
|
||||
if (!author_name[0])
|
||||
snprintf(author_name, sizeof(author_name), "0x%016llx", (unsigned long long)node_id);
|
||||
|
||||
@@ -840,7 +852,7 @@ int utun_bridge_attachment_send(const char* channel_id, const char* file_path, c
|
||||
int utun_bridge_attachment_download(const char* channel_id, int64_t msg_id) {
|
||||
if (!channel_id || msg_id <= 0) { bridge_log(BLEV_ERROR, "attachment_download: invalid args"); return -1; }
|
||||
struct UASYNC* ua = instance_lite_get_uasync();
|
||||
if (!ua) { bridge_log(BLEV_ERROR, "attachment_download: no uasync"); return -1; }
|
||||
if (!uasync_is_running(ua)) return -1;
|
||||
struct attachment_dl_req* req = u_calloc(1, sizeof(*req));
|
||||
if (!req) return -1;
|
||||
snprintf(req->channel_id, sizeof(req->channel_id), "%s", channel_id);
|
||||
|
||||
@@ -17,18 +17,19 @@
|
||||
#include "chat/chat_core.h"
|
||||
#include "chat/chat_sync.h"
|
||||
#include "chat/chat_event.h"
|
||||
#include "chat/db_sync.h"
|
||||
#include "u_async.h"
|
||||
#include "sqlite3.h"
|
||||
#include "mem.h"
|
||||
#include "debug_config.h"
|
||||
#include "transport_layer/etcp_connections.h"
|
||||
#include "transport_layer/stcp_link.h"
|
||||
#include "../jni_bridge/android_udp_log.h"
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
@@ -49,6 +50,8 @@ static struct UTUN_INSTANCE* g_inst = NULL;
|
||||
static pthread_t g_thread;
|
||||
static volatile int g_running = 0;
|
||||
static volatile int g_stop = 0;
|
||||
static volatile int g_do_restart = 0;
|
||||
static char* g_restart_config = NULL;
|
||||
static char g_db_path[512];
|
||||
static instance_lite_event_fn g_event_handler = NULL;
|
||||
static char g_generated_pub[65];
|
||||
@@ -148,6 +151,35 @@ static void nodeinfo_event_cb(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE*
|
||||
g_event_handler(CHAT_EVT_NODEINFO_UPDATED, data, sizeof(data));
|
||||
}
|
||||
|
||||
/* ── Crash handler ── */
|
||||
|
||||
static volatile int g_signal_caught = 0;
|
||||
static volatile int g_signal_num = 0;
|
||||
|
||||
static void crash_signal_handler(int sig, siginfo_t* info, void* ctx) {
|
||||
(void)ctx;
|
||||
g_signal_caught = 1; g_signal_num = sig;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "CRASH signal=%d code=%d addr=%p thread still alive", sig, info->si_code, info->si_addr);
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
static void install_crash_handlers(void) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = crash_signal_handler;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
}
|
||||
|
||||
static void heartbeat_cb(void* arg) {
|
||||
(void)arg;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "heartbeat alive");
|
||||
uasync_set_timeout(g_ua, 100000, NULL, heartbeat_cb, "hb");
|
||||
}
|
||||
|
||||
/* ── Thread function ── */
|
||||
|
||||
static void* instance_thread(void* arg) {
|
||||
@@ -157,6 +189,8 @@ static void* instance_thread(void* arg) {
|
||||
u_free(config_text);
|
||||
if (!config) { IL_LOGE("parse_config_from_buf failed"); return NULL; }
|
||||
|
||||
install_crash_handlers();
|
||||
|
||||
g_ua = uasync_create();
|
||||
if (!g_ua) { IL_LOGE("uasync_create failed"); free_config(config); return NULL; }
|
||||
|
||||
@@ -232,13 +266,67 @@ static void* instance_thread(void* arg) {
|
||||
}
|
||||
|
||||
g_running = 1;
|
||||
uasync_mark_running(g_ua);
|
||||
chat_event_post(CHAT_EVT_SERVICE_STARTED, NULL, 0);
|
||||
|
||||
uasync_set_timeout(g_ua, 100000, NULL, heartbeat_cb, "hb");
|
||||
|
||||
while (!g_stop) {
|
||||
uasync_poll(g_ua, 100);
|
||||
}
|
||||
|
||||
IL_LOGI("poll loop exit, cleaning up");
|
||||
while (g_do_restart && g_restart_config) {
|
||||
IL_LOGI("poll exit: restart requested, destroying old instance");
|
||||
uasync_mark_stopped(g_ua);
|
||||
utun_instance_destroy(g_inst);
|
||||
g_inst = NULL;
|
||||
uasync_print_resources(g_ua, "AFTER_DESTROY");
|
||||
u_report_unfreed_blocks();
|
||||
uasync_destroy(g_ua, 0);
|
||||
g_ua = uasync_create();
|
||||
if (!g_ua) { IL_LOGE("poll exit: uasync_create failed"); break; }
|
||||
|
||||
char* cfg = g_restart_config;
|
||||
g_restart_config = NULL;
|
||||
g_do_restart = 0;
|
||||
g_stop = 0;
|
||||
|
||||
IL_LOGI("poll exit: creating new instance from restart config");
|
||||
struct utun_config* config = parse_config_from_buf(cfg, strlen(cfg), "android");
|
||||
u_free(cfg);
|
||||
if (!config) { IL_LOGE("poll exit: parse_config failed"); break; }
|
||||
|
||||
g_inst = utun_instance_create_from_config(g_ua, config);
|
||||
if (!g_inst) { IL_LOGE("poll exit: create_from_config failed"); break; }
|
||||
|
||||
char db_file[512];
|
||||
snprintf(db_file, sizeof(db_file), "%s/chats.db", g_db_path);
|
||||
int rc = sqlite3_open_v2(db_file, &g_inst->topo_sqlite_db,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL);
|
||||
if (rc == SQLITE_OK && g_inst->topo_sqlite_db) {
|
||||
sqlite3_exec(g_inst->topo_sqlite_db, "PRAGMA journal_mode=WAL", NULL, NULL, NULL);
|
||||
sqlite3_exec(g_inst->topo_sqlite_db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
|
||||
sqlite3_exec(g_inst->topo_sqlite_db, "PRAGMA synchronous=NORMAL", NULL, NULL, NULL);
|
||||
topo_node_sqlite_init(g_inst->topo_sqlite_db);
|
||||
} else { IL_LOGE("poll exit: SQLite open failed rc=%d", rc); break; }
|
||||
|
||||
if (utun_instance_init(g_inst) != 0) { IL_LOGE("poll exit: utun_instance_init failed"); break; }
|
||||
chat_core_sync_my_addresses();
|
||||
if (g_inst->config->global.name[0]) chat_core_update_my_name(g_inst->config->global.name);
|
||||
etcp_router_bind(g_inst, ETCP_RT_ID_CHAT_SYNC, NULL);
|
||||
utun_add_nodeinfo_cbk(g_inst, nodeinfo_event_cb, NULL);
|
||||
chat_event_post(CHAT_EVT_KEYS_GENERATED, (const uint8_t*)config->global.my_public_key_hex, 64);
|
||||
|
||||
uasync_set_timeout(g_ua, 100000, NULL, heartbeat_cb, "hb");
|
||||
g_running = 1;
|
||||
uasync_mark_running(g_ua);
|
||||
chat_event_post(CHAT_EVT_SERVICE_STARTED, NULL, 0);
|
||||
|
||||
IL_LOGI("poll exit: restart done, entering new poll loop");
|
||||
while (!g_stop) uasync_poll(g_ua, 100);
|
||||
}
|
||||
|
||||
IL_LOGI("poll exit: final cleanup");
|
||||
|
||||
if (g_inst) {
|
||||
utun_instance_destroy(g_inst);
|
||||
@@ -248,6 +336,7 @@ static void* instance_thread(void* arg) {
|
||||
uasync_destroy(g_ua, 0);
|
||||
g_ua = NULL;
|
||||
}
|
||||
if (g_restart_config) { u_free(g_restart_config); g_restart_config = NULL; }
|
||||
u_report_unfreed_blocks();
|
||||
chat_event_post(CHAT_EVT_SERVICE_STOPPED, NULL, 0);
|
||||
g_event_handler = NULL;
|
||||
@@ -264,6 +353,8 @@ int instance_lite_start(const char* config_text) {
|
||||
|
||||
debug_config_init();
|
||||
debug_set_level(DEBUG_LEVEL_INFO);
|
||||
debug_set_category_level(DEBUG_CATEGORY_UASYNC, DEBUG_LEVEL_INFO);
|
||||
debug_set_category_level(DEBUG_CATEGORY_MEMORY, DEBUG_LEVEL_INFO);
|
||||
debug_enable_function_name(0);
|
||||
|
||||
cfg_get_val(config_text, "db_path", g_db_path, sizeof(g_db_path));
|
||||
@@ -286,6 +377,7 @@ int instance_lite_start(const char* config_text) {
|
||||
void instance_lite_stop(void) {
|
||||
if (!g_inst) return;
|
||||
IL_LOGI("stopping...");
|
||||
uasync_mark_stopped(g_ua);
|
||||
g_stop = 1;
|
||||
if (g_ua) uasync_wakeup(g_ua);
|
||||
for (int i = 0; i < 500 && g_inst != NULL; i++) usleep(10000);
|
||||
@@ -297,86 +389,6 @@ void instance_lite_stop(void) {
|
||||
g_running = 0;
|
||||
}
|
||||
|
||||
static void restart_trampoline(void* arg) {
|
||||
char* config_text = (char*)arg;
|
||||
IL_LOGI("restart: begin");
|
||||
|
||||
chat_sync_destroy(g_inst);
|
||||
chat_core_destroy(g_inst);
|
||||
|
||||
if (g_inst->topo_sqlite_db) {
|
||||
sqlite3_close(g_inst->topo_sqlite_db);
|
||||
g_inst->topo_sqlite_db = NULL;
|
||||
}
|
||||
|
||||
struct utun_config* new_config = parse_config_from_buf(config_text, strlen(config_text), "android");
|
||||
u_free(config_text);
|
||||
if (!new_config) {
|
||||
IL_LOGE("restart: parse_config failed");
|
||||
g_running = 0;
|
||||
g_inst = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
free_config(g_inst->config);
|
||||
g_inst->config = new_config;
|
||||
|
||||
ensure_keys(new_config);
|
||||
|
||||
uint8_t pk_bin[32];
|
||||
for (int i = 0; i < 32; i++) { unsigned int b; sscanf(new_config->global.my_public_key_hex + i * 2, "%2x", &b); pk_bin[i] = (uint8_t)b; }
|
||||
g_inst->node_id = sc_derive_node_id_from_pubkey(pk_bin);
|
||||
sc_init_local_keys(&g_inst->my_keys, new_config->global.my_public_key_hex, new_config->global.my_private_key_hex);
|
||||
|
||||
if (new_config->global.log_udp_ip[0] && new_config->global.log_udp_port > 0) {
|
||||
udp_log_set_target(new_config->global.log_udp_ip, new_config->global.log_udp_port);
|
||||
uasync_set_timeout(g_ua, 2000, NULL, udp_trampoline, "udp_log_flush");
|
||||
} else {
|
||||
udp_log_stop();
|
||||
}
|
||||
|
||||
char db_file[512];
|
||||
snprintf(db_file, sizeof(db_file), "%s/chats.db", g_db_path);
|
||||
int rc = sqlite3_open_v2(db_file, &g_inst->topo_sqlite_db,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL);
|
||||
if (rc == SQLITE_OK && g_inst->topo_sqlite_db) {
|
||||
sqlite3_exec(g_inst->topo_sqlite_db, "PRAGMA journal_mode=WAL", NULL, NULL, NULL);
|
||||
sqlite3_exec(g_inst->topo_sqlite_db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
|
||||
sqlite3_exec(g_inst->topo_sqlite_db, "PRAGMA synchronous=NORMAL", NULL, NULL, NULL);
|
||||
topo_node_sqlite_init(g_inst->topo_sqlite_db);
|
||||
IL_LOGI("restart: SQLite reopened %s", db_file);
|
||||
} else {
|
||||
IL_LOGE("restart: SQLite reopen failed rc=%d", rc);
|
||||
g_running = 0;
|
||||
g_inst = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clean up old sockets so init_connections reads new config */
|
||||
while (g_inst->etcp_sockets) etcp_socket_remove(g_inst->etcp_sockets);
|
||||
g_inst->etcp_sockets = NULL;
|
||||
while (g_inst->tcp_sockets) tcp_socket_remove(g_inst->tcp_sockets);
|
||||
g_inst->tcp_sockets = NULL;
|
||||
if (g_inst->stcp_server) { stcp_link_server_destroy(g_inst->stcp_server); g_inst->stcp_server = NULL; }
|
||||
g_inst->socket_init_status = 0;
|
||||
|
||||
if (utun_instance_init(g_inst) != 0) {
|
||||
IL_LOGE("restart: utun_instance_init failed");
|
||||
g_running = 0;
|
||||
g_inst = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
chat_core_sync_my_addresses();
|
||||
|
||||
if (g_inst->config->global.name[0]) {
|
||||
chat_core_update_my_name(g_inst->config->global.name);
|
||||
IL_LOGI("restart: my_name set to '%s'", g_inst->config->global.name);
|
||||
}
|
||||
|
||||
IL_LOGI("restart: done");
|
||||
}
|
||||
|
||||
void instance_lite_restart(const char* new_config_text) {
|
||||
if (!new_config_text) return;
|
||||
if (!g_ua || !g_inst || !g_running) {
|
||||
@@ -385,10 +397,14 @@ void instance_lite_restart(const char* new_config_text) {
|
||||
instance_lite_start(new_config_text);
|
||||
return;
|
||||
}
|
||||
IL_LOGI("restart: posting to uasync");
|
||||
IL_LOGI("restart: signaling poll loop to exit");
|
||||
char* copy = u_strdup(new_config_text);
|
||||
if (!copy) return;
|
||||
uasync_post(g_ua, restart_trampoline, copy);
|
||||
if (g_restart_config) u_free(g_restart_config);
|
||||
g_restart_config = copy;
|
||||
g_do_restart = 1;
|
||||
g_stop = 1;
|
||||
uasync_wakeup(g_ua);
|
||||
}
|
||||
|
||||
/* ── Health check ping ── */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "renamedialog.h"
|
||||
#include "../db/db_manager.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QSplitter>
|
||||
#include <QLabel>
|
||||
#include <QDateTime>
|
||||
#include <QFont>
|
||||
@@ -67,8 +68,6 @@ AccountList::AccountList(DbManager* db, QWidget *parent)
|
||||
m_listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
m_listView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
layout->addWidget(m_listView, 3);
|
||||
|
||||
m_detailText = new QTextEdit(this);
|
||||
m_detailText->setReadOnly(true);
|
||||
m_detailText->setFont(QFont("monospace", 10));
|
||||
@@ -76,7 +75,14 @@ AccountList::AccountList(DbManager* db, QWidget *parent)
|
||||
"QTextEdit { border-top: 1px solid palette(mid); border-bottom: none;"
|
||||
" border-left: none; border-right: none; padding: 6px; background: palette(base); }");
|
||||
m_detailText->setPlaceholderText("Select a member");
|
||||
layout->addWidget(m_detailText, 2);
|
||||
|
||||
auto *memberSplitter = new QSplitter(Qt::Vertical, this);
|
||||
memberSplitter->addWidget(m_listView);
|
||||
memberSplitter->addWidget(m_detailText);
|
||||
memberSplitter->setStretchFactor(0, 3);
|
||||
memberSplitter->setStretchFactor(1, 2);
|
||||
memberSplitter->setSizes({360, 240});
|
||||
layout->addWidget(memberSplitter, 1);
|
||||
|
||||
connect(m_listView, &QListView::clicked, this, &AccountList::onMemberClicked);
|
||||
connect(m_listView, &QListView::doubleClicked, this, &AccountList::onMemberDoubleClicked);
|
||||
|
||||
Reference in new issue
Block a user