chat: локальное удаление канала (Android) + db_sync инстансы в куче
This commit is contained in:
1 parent
ddfffad1ed
commit
7c8d65db78
30 files changed
+466
-42
No files matched your search
@@ -14,7 +14,10 @@
|
||||
#include "../routing_layer/topo_group.h"
|
||||
#include "../routing_layer/topo_group_connect.h"
|
||||
#include "member_sync.h"
|
||||
#include "chat_sync.h"
|
||||
#include "../transport_layer/secure_channel.h"
|
||||
#include "../media_delivery/media_delivery.h"
|
||||
#include "../media_delivery/media_index.h"
|
||||
#include "../../lib/mem.h"
|
||||
#include "../../lib/ll_queue.h"
|
||||
#include "../../lib/platform_compat.h"
|
||||
@@ -169,6 +172,8 @@ void chat_core_create_channel_auto(const char* name) {
|
||||
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); } }
|
||||
|
||||
uint64_t chId = 0; RAND_bytes((uint8_t*)&chId, sizeof(chId));
|
||||
chId &= 0x7FFFFFFFFFFFFFFFULL; /* как node_id — всегда < 2^63 (помещается в signed Long) */
|
||||
if (chId == 0) chId = 1;
|
||||
char channelId[64]; snprintf(channelId, sizeof(channelId), "%llu", (unsigned long long)chId);
|
||||
|
||||
uint8_t sig[64] = {0};
|
||||
@@ -295,3 +300,72 @@ void chat_core_apply_group_autoconnect(void) {
|
||||
e = e->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── локальное удаление канала ─── */
|
||||
|
||||
static const char* cc_ui_state_get(const char* key) {
|
||||
static char val[512];
|
||||
val[0] = '\0';
|
||||
sqlite3_stmt* st = NULL;
|
||||
if (sqlite3_prepare_v2(g_cc.db, "SELECT value FROM ui_state WHERE key=?", -1, &st, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_text(st, 1, key, -1, SQLITE_STATIC);
|
||||
if (sqlite3_step(st) == SQLITE_ROW) {
|
||||
const char* v = (const char*)sqlite3_column_text(st, 0);
|
||||
if (v) snprintf(val, sizeof(val), "%s", v);
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void chat_core_delete_channel(const char* ch_id) {
|
||||
if (!g_cc.initialized || !g_cc.db || !g_cc.inst) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: delete_channel — not initialized", CC_ID);
|
||||
return;
|
||||
}
|
||||
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: delete_channel — empty ch_id", CC_ID); return; }
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: delete_channel BEGIN ch=%s", CC_ID, ch_id);
|
||||
uint64_t gid = strtoull(ch_id, NULL, 10);
|
||||
|
||||
/* 1. отмена медиа-загрузок/релэев/суперузлов канала (держат conn_mgr handle группы) */
|
||||
media_delivery_cancel_channel(g_cc.inst, gid);
|
||||
|
||||
/* 2. снять merkle-сессии этого namespace */
|
||||
member_sync_cancel_channel(g_cc.inst, ch_id);
|
||||
|
||||
/* 3. удалить группу (conn_mgr → закрытие соединений, connect-цикл, broadcast, recovery) */
|
||||
if (g_cc.inst->topo_groups)
|
||||
topo_groups_remove_group(g_cc.inst->topo_groups, gid);
|
||||
|
||||
/* 4. удалить db_sync инстанс (освобождает память, отменяет таймеры) */
|
||||
{
|
||||
struct DB_SYNC_INSTANCE* si = si_find(ch_id);
|
||||
if (si) db_sync_instance_remove(si);
|
||||
}
|
||||
|
||||
/* 5. немедленно убрать канал из кеша chat_sync */
|
||||
chat_sync_on_channel_deleted(g_cc.inst, ch_id);
|
||||
|
||||
/* 6. удалить медиафайлы канала на диске + строки media_files */
|
||||
media_index_delete_channel(g_cc.db, ch_id, cc_ui_state_get("media_base"));
|
||||
|
||||
/* 7. удалить таблицы и метаданные канала */
|
||||
topo_node_sqlite_channel_delete(g_cc.db, ch_id);
|
||||
|
||||
/* 8. уведомить GUI */
|
||||
{
|
||||
uint8_t evt[65]; uint8_t cl = (uint8_t)strlen(ch_id);
|
||||
evt[0] = cl; memcpy(evt + 1, ch_id, cl);
|
||||
chat_event_post(CHAT_EVT_CHANNEL_DELETED, evt, 1 + cl);
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: delete_channel DONE ch=%s gid=0x%016llx", CC_ID, ch_id, (unsigned long long)gid);
|
||||
}
|
||||
|
||||
void chat_core_delete_channel_trampoline(void* arg) {
|
||||
struct chat_delete_channel_req* req = (struct chat_delete_channel_req*)arg;
|
||||
if (!req) return;
|
||||
chat_core_delete_channel(req->ch_id);
|
||||
u_free(req);
|
||||
}
|
||||
+2
-17
@@ -69,22 +69,11 @@ int db_exec(const char* sql) {
|
||||
/* ─── db_sync registry ─── */
|
||||
|
||||
struct DB_SYNC_INSTANCE* si_find(const char* ch_id) {
|
||||
for (int i = 0; i < g_cc.si_count; i++)
|
||||
if (strcmp(g_cc.si_ch_id[i], ch_id) == 0) return g_cc.si[i];
|
||||
return NULL;
|
||||
if (!g_cc.inst || !g_cc.inst->db_sync || !ch_id || !ch_id[0]) return NULL;
|
||||
return db_sync_instance_find(g_cc.inst, strtoull(ch_id, NULL, 10));
|
||||
}
|
||||
|
||||
void si_register(struct DB_SYNC_INSTANCE* si, const char* ch_id) {
|
||||
if (g_cc.si_count >= g_cc.si_capacity) {
|
||||
int nc = g_cc.si_capacity ? g_cc.si_capacity * 2 : 8;
|
||||
g_cc.si = u_realloc(g_cc.si, nc * sizeof(void*));
|
||||
g_cc.si_ch_id = u_realloc(g_cc.si_ch_id, nc * sizeof(char*));
|
||||
g_cc.si_capacity = nc;
|
||||
}
|
||||
g_cc.si[g_cc.si_count] = si;
|
||||
g_cc.si_ch_id[g_cc.si_count] = u_strdup(ch_id);
|
||||
g_cc.si_count++;
|
||||
|
||||
uint32_t msg_cnt = db_sync_count(si);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: si_register ch=%s mc=%u", CC_ID, ch_id, msg_cnt);
|
||||
}
|
||||
@@ -243,10 +232,6 @@ void chat_core_destroy(struct UTUN_INSTANCE* inst) {
|
||||
if (!g_cc.initialized) return;
|
||||
g_cc.initialized = 0;
|
||||
|
||||
for (int i = 0; i < g_cc.si_count; i++) u_free(g_cc.si_ch_id[i]);
|
||||
u_free(g_cc.si_ch_id); u_free(g_cc.si);
|
||||
g_cc.si = NULL; g_cc.si_ch_id = NULL; g_cc.si_count = g_cc.si_capacity = 0;
|
||||
|
||||
if (g_cc.db && !g_cc.shared_db) { sqlite3_close(g_cc.db); }
|
||||
g_cc.db = NULL; g_cc.inst = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: destroyed", CC_ID);
|
||||
|
||||
@@ -88,6 +88,18 @@ void chat_core_create_channel_trampoline(void* arg);
|
||||
void chat_core_create_channel_auto(const char* name);
|
||||
void chat_core_create_channel_auto_trampoline(void* arg);
|
||||
|
||||
/* ── Локальное удаление канала (GUI → uasync) ── */
|
||||
|
||||
struct chat_delete_channel_req {
|
||||
char ch_id[64];
|
||||
};
|
||||
|
||||
/* Удалить канал с этого устройства: отмена медиа-загрузок, удаление группы
|
||||
* (соединения/синк), db_sync инстанса, таблиц msg_ и peers_, медиафайлов и
|
||||
* merkle-хешей. Работает в uasync-потоке. Другие узлы канал не теряют. */
|
||||
void chat_core_delete_channel(const char* ch_id);
|
||||
void chat_core_delete_channel_trampoline(void* arg);
|
||||
|
||||
/* ── Утилиты ── */
|
||||
|
||||
void chat_core_set_my_node_id(uint64_t node_id);
|
||||
|
||||
@@ -81,9 +81,6 @@ struct chat_core_ctx {
|
||||
char db_path[512];
|
||||
uint8_t shared_db;
|
||||
uint64_t my_node_id;
|
||||
struct DB_SYNC_INSTANCE** si;
|
||||
char** si_ch_id;
|
||||
int si_count, si_capacity;
|
||||
uint8_t initialized;
|
||||
};
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ extern "C" {
|
||||
#define CHAT_EVT_ADMIN_KEY_RECEIVED 28 /* [ch_id_len:1][ch_id:var][from_node_id:8] — получен канальный ключ (стал совладельцем) */
|
||||
#define CHAT_EVT_INVITE_LINK_READY 29 /* [ch_id_len:1][ch_id:var][link_len:2][link:var] — пустой link = ошибка */
|
||||
#define CHAT_EVT_INVITE_CANDIDATES 30 /* [ch_id_len:1][ch_id:var][auto_node_id:8][count:2][node_id:8]* — достижимые узлы для invite */
|
||||
#define CHAT_EVT_CHANNEL_DELETED 31 /* [ch_id_len:1][ch_id:var] — канал удалён локально */
|
||||
|
||||
typedef void (*chat_event_handler_fn)(int type, const uint8_t* data, int len);
|
||||
|
||||
|
||||
@@ -679,6 +679,20 @@ void chat_sync_connect_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
||||
(void)inst; (void)node_id;
|
||||
}
|
||||
|
||||
void chat_sync_on_channel_deleted(struct UTUN_INSTANCE* inst, const char* ch_id) {
|
||||
(void)inst;
|
||||
if (!g_cs || !ch_id || !ch_id[0]) return;
|
||||
for (int i = 0; i < g_cs->channel_count; i++) {
|
||||
if (strcmp(g_cs->channels[i].channel_id, ch_id) != 0) continue;
|
||||
if (g_cs->channels[i].peer_ids) u_free(g_cs->channels[i].peer_ids);
|
||||
memmove(&g_cs->channels[i], &g_cs->channels[i + 1],
|
||||
(size_t)(g_cs->channel_count - i - 1) * sizeof(struct channel_cache));
|
||||
g_cs->channel_count--;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: channel removed from cache ch=%s", CS_ID, ch_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct chat_invite {
|
||||
uint64_t channel_id;
|
||||
uint64_t node_id;
|
||||
|
||||
@@ -111,6 +111,10 @@ void chat_sync_join_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint6
|
||||
Вызывается из auto_socket при появлении/изменении сетевой связности. */
|
||||
void chat_sync_retry_channels_on_socket_change(struct UTUN_INSTANCE* inst);
|
||||
|
||||
/* Немедленно убрать канал из кеша g_cs->channels (локальное удаление канала),
|
||||
* чтобы cs_on_conn_status не запускал member_sync для удалённого ns до следующего refresh. */
|
||||
void chat_sync_on_channel_deleted(struct UTUN_INSTANCE* inst, const char* ch_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+32
-18
@@ -82,7 +82,7 @@ struct DB_SYNC {
|
||||
sqlite3* db;
|
||||
uint8_t shared_db; /* db == inst->topo_sqlite_db, do not close */
|
||||
uint64_t last_connected_tb;
|
||||
struct DB_SYNC_INSTANCE* instances;
|
||||
struct DB_SYNC_INSTANCE** instances;
|
||||
int instance_count, instance_capacity;
|
||||
void* peer_check_timer;
|
||||
void* peer_check_wait; /* standby_wait handle (Android) */
|
||||
@@ -225,26 +225,33 @@ static void db_chain_hash_compute(const uint8_t prev_chain_hash[32],
|
||||
static struct DB_SYNC_INSTANCE* db_instance_find(struct DB_SYNC* db, uint64_t group_id)
|
||||
{
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
if (db->instances[i].group_id == group_id && db->instances[i].enabled) return &db->instances[i];
|
||||
if (db->instances[i]->group_id == group_id && db->instances[i]->enabled) return db->instances[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Выделяет новый слот инстанса в массиве, расширяя его при необходимости
|
||||
struct DB_SYNC_INSTANCE* db_sync_instance_find(struct UTUN_INSTANCE* inst, uint64_t group_id)
|
||||
{
|
||||
if (!inst || !inst->db_sync) return NULL;
|
||||
return db_instance_find(inst->db_sync, group_id);
|
||||
}
|
||||
|
||||
// Выделяет новый инстанс в куче (стабильный указатель) и регистрирует его в массиве
|
||||
static struct DB_SYNC_INSTANCE* db_instance_alloc(struct DB_SYNC* db)
|
||||
{
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "count=%d cap=%d", db->instance_count, db->instance_capacity);
|
||||
if (db->instance_count >= db->instance_capacity) {
|
||||
int nc = db->instance_capacity ? db->instance_capacity * 2 : 4;
|
||||
struct DB_SYNC_INSTANCE* np = u_realloc(db->instances, nc * sizeof(*db->instances));
|
||||
struct DB_SYNC_INSTANCE** np = u_realloc(db->instances, nc * sizeof(*db->instances));
|
||||
if (!np) return NULL;
|
||||
db->instances = np;
|
||||
db->instance_capacity = nc;
|
||||
}
|
||||
struct DB_SYNC_INSTANCE* si = &db->instances[db->instance_count++];
|
||||
memset(si, 0, sizeof(*si));
|
||||
struct DB_SYNC_INSTANCE* si = u_calloc(1, sizeof(*si));
|
||||
if (!si) return NULL;
|
||||
si->db_sync = db;
|
||||
si->enabled = 1;
|
||||
db->instances[db->instance_count++] = si;
|
||||
return si;
|
||||
}
|
||||
|
||||
@@ -856,8 +863,10 @@ static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const
|
||||
|
||||
struct SI_PEER* sp = si_peer_find(si, src);
|
||||
|
||||
// Peer empty → send ALL our data, then SYNC_DONE will be sent from DATA handler when slave responds
|
||||
if (peer_ch8 == 0 && sc == 0) {
|
||||
// Peer empty → send ALL our data, then SYNC_DONE will be sent from DATA handler when slave responds.
|
||||
// Если мы тоже пусты (mc==0) — обе стороны пусты: не отправляем ничего, а завершаем sync через
|
||||
// SYNC_DONE в ветке "exact match" ниже (иначе обе стороны вечно ждут ответа → TIMEOUT).
|
||||
if (peer_ch8 == 0 && sc == 0 && mc > 0) {
|
||||
uint32_t vp = (uint32_t)-1; if (sp) sp->verified_pos = vp;
|
||||
uint32_t sent = 0;
|
||||
while (sent < mc) {
|
||||
@@ -1293,7 +1302,7 @@ static void db_sync_on_conn_up(struct ETCP_CONN* conn, void* arg)
|
||||
int synced = 0;
|
||||
char tbl_list[256] = "";
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
struct DB_SYNC_INSTANCE* si = &db->instances[i];
|
||||
struct DB_SYNC_INSTANCE* si = db->instances[i];
|
||||
if (!si->enabled) continue;
|
||||
struct SI_PEER* p = si_peer_add(si, pid);
|
||||
if (!p) continue;
|
||||
@@ -1323,14 +1332,14 @@ static void db_sync_on_conn_down(struct ETCP_CONN* conn, void* arg)
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "peer=%016llx", (unsigned long long)pid);
|
||||
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
struct SI_PEER* p = si_peer_find(&db->instances[i], pid);
|
||||
struct SI_PEER* p = si_peer_find(db->instances[i], pid);
|
||||
if (p) p->sync_state = 0;
|
||||
}
|
||||
|
||||
int any = 0;
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
for (int j = 0; j < db->instances[i].peer_count; j++) {
|
||||
if (db->instances[i].peers[j].sync_state >= 1) { any = 1; goto cd_done; }
|
||||
for (int j = 0; j < db->instances[i]->peer_count; j++) {
|
||||
if (db->instances[i]->peers[j].sync_state >= 1) { any = 1; goto cd_done; }
|
||||
}
|
||||
}
|
||||
cd_done:
|
||||
@@ -1507,7 +1516,7 @@ static int db_sync_has_pending_work(struct DB_SYNC* db)
|
||||
{
|
||||
if (!db || !db->enabled) return 0;
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
struct DB_SYNC_INSTANCE* si = &db->instances[i];
|
||||
struct DB_SYNC_INSTANCE* si = db->instances[i];
|
||||
if (!si->enabled) continue;
|
||||
for (int j = 0; j < si->peer_count; j++)
|
||||
if (si->peers[j].sync_state != 2) return 1;
|
||||
@@ -1546,7 +1555,7 @@ static void db_sync_peer_check_cb(void* arg)
|
||||
char launched_list[256] = "";
|
||||
if (g) {
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
struct DB_SYNC_INSTANCE* si = &db->instances[i];
|
||||
struct DB_SYNC_INSTANCE* si = db->instances[i];
|
||||
if (!si->enabled) continue;
|
||||
if (si->sync_gated) continue;
|
||||
|
||||
@@ -1591,7 +1600,7 @@ static void db_sync_peer_check_cb(void* arg)
|
||||
uint64_t now = get_time_tb();
|
||||
uint64_t to_tb = DB_SYNC_SYNC_TIMEOUT * 10000u;
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
struct DB_SYNC_INSTANCE* si = &db->instances[i];
|
||||
struct DB_SYNC_INSTANCE* si = db->instances[i];
|
||||
if (!si->enabled) continue;
|
||||
for (int j = 0; j < si->peer_count; j++) {
|
||||
struct SI_PEER* p = &si->peers[j];
|
||||
@@ -1722,10 +1731,11 @@ void db_sync_destroy(struct UTUN_INSTANCE* inst)
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
struct DB_SYNC_INSTANCE* si = &db->instances[i];
|
||||
struct DB_SYNC_INSTANCE* si = db->instances[i];
|
||||
if (si->ttl_timer) { uasync_cancel_timeout(inst->ua, si->ttl_timer); si->ttl_timer = NULL; }
|
||||
if (si->recalc.timer) { uasync_cancel_timeout(inst->ua, si->recalc.timer); si->recalc.timer = NULL; }
|
||||
if (si->peers) u_free(si->peers);
|
||||
u_free(si);
|
||||
}
|
||||
|
||||
etcp_remove_conn_status_cbk(inst, db_sync_on_conn_status, NULL);
|
||||
@@ -1834,13 +1844,17 @@ void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si)
|
||||
if (si->recalc.timer) { uasync_cancel_timeout(inst->ua, si->recalc.timer); si->recalc.timer = NULL; }
|
||||
if (si->peers) { u_free(si->peers); si->peers = NULL; si->peer_count = si->peer_capacity = 0; }
|
||||
|
||||
int idx = (int)(si - db->instances);
|
||||
if (idx >= 0 && idx < db->instance_count) {
|
||||
int idx = -1;
|
||||
for (int i = 0; i < db->instance_count; i++) {
|
||||
if (db->instances[i] == si) { idx = i; break; }
|
||||
}
|
||||
if (idx >= 0) {
|
||||
memmove(&db->instances[idx], &db->instances[idx + 1],
|
||||
(db->instance_count - idx - 1) * sizeof(*db->instances));
|
||||
db->instance_count--;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance removed tbl=%s group=%016llx", si->table_name, (unsigned long long)si->group_id);
|
||||
u_free(si);
|
||||
}
|
||||
|
||||
// Вставляет подписанную запись: проверяет подпись, вставляет в БД, рассылает PUSH всем синхронизированным пирам
|
||||
|
||||
@@ -98,6 +98,8 @@ void db_sync_destroy(struct UTUN_INSTANCE* inst);
|
||||
// Instance management
|
||||
struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const char* table_name, uint64_t group_id, int auto_sync);
|
||||
void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si);
|
||||
// Найти живой инстанс по group_id (поиск в текущем массиве db->instances — указатель всегда актуален).
|
||||
struct DB_SYNC_INSTANCE* db_sync_instance_find(struct UTUN_INSTANCE* inst, uint64_t group_id);
|
||||
|
||||
// Data operations (per-instance)
|
||||
// db_sync_insert_signed: sig MUST be non-NULL, 64 bytes.
|
||||
|
||||
@@ -813,6 +813,10 @@ void member_sync_cancel(struct UTUN_INSTANCE* inst, uint64_t peer, const char* c
|
||||
merkle_sync_cancel(inst, peer, ch_id);
|
||||
}
|
||||
|
||||
void member_sync_cancel_channel(struct UTUN_INSTANCE* inst, const char* ch_id) {
|
||||
merkle_sync_cancel_ns(inst, ch_id);
|
||||
}
|
||||
|
||||
/* Сериализует одного мембера в wire-формат [count:2][member...].
|
||||
Возвращает 0 и *out_len, или -1 если мембер не найден/нет БД. */
|
||||
static int _serialize_member(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t member_id,
|
||||
|
||||
@@ -96,6 +96,12 @@ int member_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer,
|
||||
*/
|
||||
void member_sync_cancel(struct UTUN_INSTANCE* inst, uint64_t peer, const char* ch_id);
|
||||
|
||||
/*
|
||||
* Отменить все merkle-сессии канала (локальное удаление канала).
|
||||
* Делегирует в merkle_sync_cancel_ns().
|
||||
*/
|
||||
void member_sync_cancel_channel(struct UTUN_INSTANCE* inst, const char* ch_id);
|
||||
|
||||
/*
|
||||
* Добавить/обновить мембера (локальная запись, доверенная) и пересчитать дерево.
|
||||
* Делегирует в member_sync_apply_record() с from_peer = inst->node_id.
|
||||
|
||||
@@ -910,3 +910,23 @@ void merkle_sync_cancel(struct UTUN_INSTANCE* inst, uint64_t peer, const char* n
|
||||
p = &(*p)->next;
|
||||
}
|
||||
}
|
||||
|
||||
void merkle_sync_cancel_ns(struct UTUN_INSTANCE* inst, const char* ns) {
|
||||
struct merkle_sync* ms = inst ? inst->msync : NULL;
|
||||
if (!ms || !ns) return;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cancel_ns ns=%s", MS_ID, ns);
|
||||
struct ms_session** p = &ms->sessions;
|
||||
int removed = 0;
|
||||
while (*p) {
|
||||
struct ms_session* s = *p;
|
||||
if (strcmp(s->ns, ns) == 0) {
|
||||
*p = s->next;
|
||||
ms_session_outq_free(s);
|
||||
u_free(s);
|
||||
removed++;
|
||||
continue;
|
||||
}
|
||||
p = &(*p)->next;
|
||||
}
|
||||
if (removed) DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cancel_ns ns=%s removed=%d", MS_ID, ns, removed);
|
||||
}
|
||||
@@ -216,6 +216,12 @@ int merkle_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer,
|
||||
*/
|
||||
void merkle_sync_cancel(struct UTUN_INSTANCE* inst, uint64_t peer, const char* ns);
|
||||
|
||||
/*
|
||||
* Отменить и удалить ВСЕ сессии для namespace ns (независимо от пира).
|
||||
* Используется при локальном удалении канала. done_cb НЕ вызывается.
|
||||
*/
|
||||
void merkle_sync_cancel_ns(struct UTUN_INSTANCE* inst, const char* ns);
|
||||
|
||||
/* ── Recompute tree path after data change ── */
|
||||
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user