chat: автоподключение к узлам группы (вкл/выкл) + ручной connect к узлу (desktop+android); фикс reinit при QR-join

This commit is contained in:
evgeny committed 2026-09-11 19:46:02 +03:00
1 parent 9ef501a2fb
commit d7bb58c6fb
20 files changed
+241 -5

No files matched your search

+60
View File
@@ -6,6 +6,7 @@
#include "chat_core_priv.h"
#include "chat_event.h"
#include "chat_setting.h"
#include "../utun_instance.h"
#include "../ntp_time.h"
@@ -224,6 +225,12 @@ void chat_core_connect_channel(const char* ch_id) {
return;
}
if (!chat_setting_get_int("group_autoconnect", 1)) {
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel ch=%s — group_autoconnect disabled, skip auto-connect loop",
CC_ID, ch_id);
return;
}
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel ch=%s gid=%016llx group_type=%d — starting connect_init", CC_ID, ch_id, (unsigned long long)gid, group->group_type);
topo_group_connect_init(group);
}
@@ -235,3 +242,56 @@ void chat_core_connect_channel_trampoline(void* arg) {
chat_core_connect_channel(ch_id);
u_free(ch_id);
}
/* ─── однократное подключение к конкретному узлу канала (GUI → uasync) ─── */
void chat_core_connect_node(const char* ch_id, uint64_t node_id) {
if (!g_cc.initialized || !g_cc.inst || !ch_id || !ch_id[0] || !node_id) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_node — skip (not ready or invalid args)", CC_ID);
return;
}
if (node_id == g_cc.inst->node_id) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_node — skip self node=0x%016llx", CC_ID, (unsigned long long)node_id);
return;
}
chat_core_ensure_channel_ready(ch_id);
uint64_t gid = strtoull(ch_id, NULL, 10);
struct TOPO_GROUP* group = topo_groups_find(g_cc.inst->topo_groups, gid);
if (!group) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_node — group not found ch=%s", CC_ID, ch_id);
return;
}
topo_group_connect_node_once(group, node_id);
}
void chat_core_connect_node_trampoline(void* arg) {
struct chat_connect_node_req* r = (struct chat_connect_node_req*)arg;
if (!r) return;
chat_core_connect_node(r->ch_id, r->node_id);
u_free(r);
}
/* ─── применение настройки group_autoconnect ко всем CHAT-группам ─── */
void chat_core_apply_group_autoconnect(void) {
int enabled = chat_setting_get_int("group_autoconnect", 1);
struct UTUN_INSTANCE* inst = g_cc.inst;
if (!inst || !inst->topo_groups || !inst->topo_groups->group_list) return;
struct ll_entry* e = inst->topo_groups->group_list->head;
while (e) {
struct TOPO_GROUP* g = (struct TOPO_GROUP*)e;
if (g->group_type == TOPO_GROUP_TYPE_CHAT) {
if (enabled && !g->connect) {
topo_group_connect_init(g);
} else if (!enabled && g->connect) {
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: group_autoconnect OFF — stop auto-connect ch=%s", CC_ID, g->channel_id);
topo_group_connect_destroy(g);
}
}
e = e->next;
}
}
+1
View File
@@ -260,6 +260,7 @@ int chat_core_is_initialized(void) { return g_cc.initialized; }
void chat_core_set_setting(const char* name, const char* value) {
chat_setting_set(name, value);
if (name && strcmp(name, "group_autoconnect") == 0) chat_core_apply_group_autoconnect();
}
struct chat_setting_arg { char data[256]; };
+9
View File
@@ -96,6 +96,15 @@ void chat_core_set_setting_trampoline(void* arg);
void chat_core_connect_channel(const char* ch_id);
void chat_core_connect_channel_trampoline(void* arg);
/* Однократная попытка подключения к конкретному узлу канала (GUI → uasync) */
void chat_core_connect_node(const char* ch_id, uint64_t node_id);
void chat_core_connect_node_trampoline(void* arg);
struct chat_connect_node_req {
char ch_id[64];
uint64_t node_id;
};
/* Трамплин для gui_bridge_post_uasync (GUI → uasync) */
void chat_core_submit_trampoline(void* arg);
+4
View File
@@ -105,4 +105,8 @@ void si_register(struct DB_SYNC_INSTANCE* si, const char* ch_id);
void on_msg_inserted(struct DB_SYNC_INSTANCE* si, uint64_t record_ts, const char* data, size_t len, uint64_t author, void* arg);
/* ── применить настройку group_autoconnect ко всем CHAT-группам (chat_channel.c) ── */
void chat_core_apply_group_autoconnect(void);
#endif /* CHAT_CORE_PRIV_H */
+1
View File
@@ -53,6 +53,7 @@ static const struct chat_setting_def g_setting_defs[] = {
{"join_policy", CHAT_SETTING_INT, 1, 0, 2}, /* 0=autojoin, 1=ask, 2=deny */
{"whisper_enabled", CHAT_SETTING_BOOL, 0, 0, 1},
{"whisper_model_path", CHAT_SETTING_STRING, 0, 0, 0},
{"group_autoconnect", CHAT_SETTING_BOOL, 1, 0, 1},
};
#define CHAT_SETTING_COUNT (sizeof(g_setting_defs) / sizeof(g_setting_defs[0]))
+2 -1
View File
@@ -26,6 +26,7 @@
#include "topo_group_connect.h"
#include "topo_recovery.h"
#include "broadcast.h"
#include "../chat/chat_setting.h"
#define TOPO_GROUP_UTUN 0x8000000000000000ULL
@@ -522,7 +523,7 @@ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t grou
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Group created: group_id=%016llx type=%u ch_id=%s", (unsigned long long)group_id, group_type, group->channel_id);
if (group_type == TOPO_GROUP_TYPE_CHAT) topo_group_connect_init(group);
if (group_type == TOPO_GROUP_TYPE_CHAT && chat_setting_get_int("group_autoconnect", 1)) topo_group_connect_init(group);
return group;
}
+57
View File
@@ -26,6 +26,7 @@
#include "topo_group.h"
#include "topo_node.h"
#include "topo_node_sqlite.h"
#include "../utun_instance.h"
#include "../transport_layer/node_conn_direct.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
@@ -523,3 +524,59 @@ static void tgc_cycle_restart(struct TOPO_GROUP_CONNECT* gc) {
gc->phase_timer = uasync_set_timeout(gc->group->instance->ua,
TGC_DIRECT_TIMEOUT_MS * 10, gc, tgc_phase1_timeout, "tgc_phase1");
}
/* ═══════════════════════════════════════════════════════════════════════
* Однократное подключение к конкретному узлу (ручной "Connect" из GUI)
* ══════════════════════════════════════════════════════════════════════ */
struct tgc_once_ctx {
struct TOPO_GROUP* group;
uint64_t node_id;
struct NODE_CONN_DIRECT* h;
};
static void tgc_once_cb(struct NODE_CONN_DIRECT* h, enum ncd_event ev, void* arg) {
struct tgc_once_ctx* c = (struct tgc_once_ctx*)arg;
struct ETCP_CONN* conn = node_conn_direct_get_conn(h);
if (ev == NCD_EVENT_UP && conn) {
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(c->group, c->node_id);
if (nq) nq->handle = h;
node_conn_direct_set_callback(h, NULL, NULL);
topo_group_new_conn(c->group, conn);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "%s: once-connect UP node=0x%016llx ch=%s",
TGC_ID, (unsigned long long)c->node_id, c->group->channel_id);
} else if (ev == NCD_EVENT_TIMEOUT) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "%s: once-connect TIMEOUT node=0x%016llx ch=%s",
TGC_ID, (unsigned long long)c->node_id, c->group->channel_id);
node_conn_direct_close(h);
} else if (ev == NCD_EVENT_DOWN) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "%s: once-connect DOWN node=0x%016llx ch=%s",
TGC_ID, (unsigned long long)c->node_id, c->group->channel_id);
node_conn_direct_close(h);
}
u_free(c);
}
int topo_group_connect_node_once(struct TOPO_GROUP* group, uint64_t node_id) {
if (!group || group->group_type != TOPO_GROUP_TYPE_CHAT || !node_id) return -1;
if (node_id == group->instance->node_id) return -1;
struct ETCP_CONN* ex = instance_find_conn(group->instance, node_id);
if (ex && ex->links_up && ex->initialized) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "%s: once-connect node=0x%016llx already connected — add to group ch=%s",
TGC_ID, (unsigned long long)node_id, group->channel_id);
topo_group_new_conn(group, ex);
return 0;
}
struct tgc_once_ctx* c = u_calloc(1, sizeof(*c));
if (!c) return -1;
c->group = group; c->node_id = node_id;
int r = node_conn_direct_open(group->instance, node_id, tgc_once_cb, c, &c->h, NULL);
if (r == NCD_ERR || !c->h) { u_free(c); return -1; }
DEBUG_INFO(DEBUG_CATEGORY_BGP, "%s: once-connect node=0x%016llx ch=%s started (rc=%d)",
TGC_ID, (unsigned long long)node_id, group->channel_id, r);
return 0;
}
+5
View File
@@ -33,4 +33,9 @@ void topo_group_connect_on_down(struct TOPO_GROUP* group, struct ETCP_CONN* conn
int topo_group_connect_active_count(struct TOPO_GROUP* group);
void topo_group_connect_restart(struct TOPO_GROUP* group);
/* Однократная попытка подключения к конкретному узлу группы (без бесконечного
* цикла). При успехе соединение добавляется в BGP-группу (topo_group_new_conn),
* handle сохраняется в nq->handle. Используется для ручного "Connect" из GUI. */
int topo_group_connect_node_once(struct TOPO_GROUP* group, uint64_t node_id);
#endif
+3 -2
View File
@@ -640,10 +640,11 @@ void etcp_conn_reinit_id(struct ETCP_CONN* etcp, const char* reason, uint64_t re
// Применение чужого reset_id (эпохи ресета пира). Симметрично:
// если uid пира изменился — сбрасываем своё состояние (свой uid сохраняем).
void etcp_conn_apply_peer_reset_id(struct ETCP_CONN* conn, uint64_t peer_reset_id) {
if (!conn) return;
if (!conn || peer_reset_id == 0) return; /* 0 = неизвестно (STCP-сервер ещё не создал conn) */
if (peer_reset_id == conn->peer_reset_id) return; // uid пира не изменился
uint64_t old = conn->peer_reset_id;
conn->peer_reset_id = peer_reset_id;
if (conn->got_initial_pkt) {
if (old != 0 && conn->got_initial_pkt) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] peer reset id changed to %016llx — resetting self",
conn->log_name, (unsigned long long)peer_reset_id);
etcp_conn_reinit(conn, "peer reset epoch");