diff --git a/tools/chatgui/transport/chat_core.c b/tools/chatgui/transport/chat_core.c index c1737e72..95f867cd 100644 --- a/tools/chatgui/transport/chat_core.c +++ b/tools/chatgui/transport/chat_core.c @@ -200,6 +200,20 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) { ); g_cc.initialized = 1; + + /* ensure infrastructure for all existing channels (survives restart) */ + { + sqlite3_stmt* stmt = NULL; + if (sqlite3_prepare_v2(g_cc.db, "SELECT channel_id FROM channels ORDER BY created_at ASC", + -1, &stmt, NULL) == SQLITE_OK) { + while (sqlite3_step(stmt) == SQLITE_ROW) { + const char* ch = (const char*)sqlite3_column_text(stmt, 0); + if (ch && ch[0]) chat_core_ensure_channel_ready(ch); + } + sqlite3_finalize(stmt); + } + } + DEBUG_INFO(DEBUG_CATEGORY_CONNECTIVITY, "%s: initialized, db=%s node_id=0x%016llx", CC_ID, db_path, (unsigned long long)g_cc.my_node_id); @@ -848,23 +862,16 @@ void chat_core_connect_from_invite(struct chat_invite* inv) { } } -/* ─── создание канала ─── */ - -void chat_core_create_channel(struct chat_channel_create* req) { - if (!g_cc.initialized) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: create_channel NOT INITIALIZED ch=%s", - CC_ID, req ? req->channel_id : "(null)"); - return; - } - if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: create_channel req=NULL", CC_ID); return; } +/* ─── подготовка инфраструктуры канала (msg-таблица + db_sync instance) ─── */ - DEBUG_INFO(DEBUG_CATEGORY_CONNECTIVITY, "%s: create_channel BEGIN ch=%s name=%s", - CC_ID, req->channel_id, req->name); +void chat_core_ensure_channel_ready(const char* ch_id) { + if (!g_cc.initialized || !ch_id || !ch_id[0]) return; + if (si_find(ch_id)) return; - char tbl_msg[80]; msg_table_name(req->channel_id, tbl_msg, sizeof(tbl_msg)); + char tbl_msg[80]; msg_table_name(ch_id, tbl_msg, sizeof(tbl_msg)); + char sql[512]; - /* создаём таблицу сообщений */ - char sql[512]; snprintf(sql, sizeof(sql), + snprintf(sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS \"%s\" (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " node_id INTEGER NOT NULL," @@ -879,26 +886,39 @@ void chat_core_create_channel(struct chat_channel_create* req) { " sync_flags INTEGER DEFAULT 0," " UNIQUE(timestamp, datahash))", tbl_msg); db_exec(sql); - snprintf(sql, sizeof(sql), "CREATE INDEX IF NOT EXISTS \"idx_%s_ts_dh\" ON \"%s\"(timestamp, datahash)", tbl_msg, tbl_msg); db_exec(sql); - /* Register with db_sync for message sync */ - { - /* Compute a deterministic hash from channel_id for db_sync instance id */ - uint64_t ch_hash = 0; - { const uint8_t* chd = (const uint8_t*)req->channel_id; size_t chl = strlen(req->channel_id); uint8_t sh[32]; SHA256(chd, chl, sh); memcpy(&ch_hash, sh, 8); } - struct DB_SYNC_INSTANCE* si = db_sync_instance_add(g_cc.inst, "chats", ch_hash); - if (si) { - si_register(si, req->channel_id); - db_sync_set_insert_cb(si, on_db_sync_insert, u_strdup(req->channel_id)); - DEBUG_INFO(DEBUG_CATEGORY_CONNECTIVITY, "%s: db_sync instance added for ch=%s hash=0x%016llx", CC_ID, req->channel_id, (unsigned long long)ch_hash); - } else { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: db_sync_instance_add failed for ch=%s", CC_ID, req->channel_id); - } + uint64_t ch_hash = 0; + { const uint8_t* chd = (const uint8_t*)ch_id; size_t chl = strlen(ch_id); uint8_t sh[32]; SHA256(chd, chl, sh); memcpy(&ch_hash, sh, 8); } + struct DB_SYNC_INSTANCE* si = db_sync_instance_add(g_cc.inst, "chats", ch_hash); + if (si) { + si_register(si, ch_id); + db_sync_set_insert_cb(si, on_db_sync_insert, u_strdup(ch_id)); + DEBUG_INFO(DEBUG_CATEGORY_CONNECTIVITY, "%s: channel ready ch=%s hash=0x%016llx", + CC_ID, ch_id, (unsigned long long)ch_hash); + } else { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: db_sync_instance_add failed for ch=%s", + CC_ID, ch_id); + } +} + +/* ─── создание канала ─── */ + +void chat_core_create_channel(struct chat_channel_create* req) { + if (!g_cc.initialized) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: create_channel NOT INITIALIZED ch=%s", + CC_ID, req ? req->channel_id : "(null)"); + return; } + if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: create_channel req=NULL", CC_ID); return; } + + DEBUG_INFO(DEBUG_CATEGORY_CONNECTIVITY, "%s: create_channel BEGIN ch=%s name=%s", + CC_ID, req->channel_id, req->name); + + chat_core_ensure_channel_ready(req->channel_id); /* записываем канал в БД */ int rc = topo_node_sqlite_channel_put(g_cc.db, diff --git a/tools/chatgui/transport/chat_core.h b/tools/chatgui/transport/chat_core.h index 3d961071..6af3978d 100644 --- a/tools/chatgui/transport/chat_core.h +++ b/tools/chatgui/transport/chat_core.h @@ -68,6 +68,7 @@ struct chat_channel_create { uint8_t signature[64]; }; +void chat_core_ensure_channel_ready(const char* ch_id); void chat_core_create_channel(struct chat_channel_create* req); void chat_core_create_channel_trampoline(void* arg); diff --git a/tools/chatgui/transport/chat_sync.c b/tools/chatgui/transport/chat_sync.c index c1a59e22..c9ea3711 100644 --- a/tools/chatgui/transport/chat_sync.c +++ b/tools/chatgui/transport/chat_sync.c @@ -774,6 +774,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer, /* save channel to local DB */ topo_node_sqlite_channel_put(cs->inst->topo_groups->topo_sqlite_db, ch_id, name, (int)is_dm, owner, x25519, NULL, ed_pub, NULL, ch_sig); + chat_core_ensure_channel_ready(ch_id); /* verify inviter's join_sig */ { sqlite3* vdb = cs->inst->topo_groups->topo_sqlite_db;