chat: передавать group_id в бинарном виде в протоколе синхронизации
db_sync/merkle_sync/chat_sync шлют group_id (uint64 BE) вместо текстового channel_id/namespace. Приёмная сторона находит группу/таблицу через topo_groups_find(group_id) и требует существующую CHAT-группу. db_sync: instance key заменён с SHA256(ch_id) на strtoull(ch_id)=group_id.
This commit is contained in:
1 parent
326dfd7e2c
commit
7b73d99b5b
6 files changed
+194
-147
No files matched your search
+40
-40
@@ -33,7 +33,7 @@ static void db_sync_peer_check_cb(void* arg);
|
||||
static void db_sync_resume_peer_check(struct DB_SYNC* db);
|
||||
static void db_sync_instance_ttl_cb(void* arg);
|
||||
static int db_sync_send(struct DB_SYNC_INSTANCE* si, uint64_t dst_node_id, const uint8_t* payload, size_t len);
|
||||
static int db_sync_send_hash(struct DB_SYNC* db, uint64_t node_id, uint64_t hash, const uint8_t* payload, size_t len);
|
||||
static int db_sync_send_gid(struct DB_SYNC* db, uint64_t node_id, uint64_t group_id, const uint8_t* payload, size_t len);
|
||||
static void db_sync_initiate_sync(struct DB_SYNC_INSTANCE* si, uint64_t peer_node_id);
|
||||
static int si_send_data_batch(struct DB_SYNC_INSTANCE* si, uint64_t dst, uint32_t from, uint32_t count, uint32_t vp, uint32_t want_from);
|
||||
static void si_delivery_update(struct DB_SYNC_INSTANCE* si, uint64_t ts, uint64_t author, uint64_t peer_id);
|
||||
@@ -54,7 +54,7 @@ struct SI_PEER {
|
||||
|
||||
struct DB_SYNC_INSTANCE {
|
||||
struct DB_SYNC* db_sync;
|
||||
uint64_t hash;
|
||||
uint64_t group_id;
|
||||
char table_name[64];
|
||||
uint64_t next_id;
|
||||
uint64_t last_timestamp_ms;
|
||||
@@ -128,7 +128,7 @@ void db_sync_remove_done_cbk(struct UTUN_INSTANCE* inst, db_sync_done_fn fn, voi
|
||||
#define SI_TBL(si) ((si)->table_name)
|
||||
#define SI_SHRT(si) ({ \
|
||||
static char _tbuf[28]; \
|
||||
snprintf(_tbuf, sizeof(_tbuf), "%s.%04llX", SI_TBL(si), (unsigned long long)((si)->hash & 0xFFFF)); \
|
||||
snprintf(_tbuf, sizeof(_tbuf), "%s.%04llX", SI_TBL(si), (unsigned long long)((si)->group_id & 0xFFFF)); \
|
||||
_tbuf; \
|
||||
})
|
||||
|
||||
@@ -220,11 +220,11 @@ static void db_chain_hash_compute(const uint8_t prev_chain_hash[32],
|
||||
// Instance management
|
||||
// ============================================================
|
||||
|
||||
// Ищет активный инстанс синхронизации по 64-битному хешу
|
||||
static struct DB_SYNC_INSTANCE* db_instance_find(struct DB_SYNC* db, uint64_t hash)
|
||||
// Ищет активный инстанс синхронизации по group_id канала
|
||||
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].hash == hash && 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;
|
||||
}
|
||||
@@ -672,24 +672,24 @@ static int db_record_insert_cascade(struct DB_SYNC_INSTANCE* si,
|
||||
// Send
|
||||
// ============================================================
|
||||
|
||||
// Отправляет сообщение узлу через ETCP с заголовком: [ETCP_RT_ID_DB_SYNC:1][hash_be:8][payload]. Возвращает код etcp_send
|
||||
static int db_sync_send_hash(struct DB_SYNC* db, uint64_t node_id, uint64_t hash, const uint8_t* payload, size_t plen)
|
||||
// Отправляет сообщение узлу через ETCP с заголовком: [ETCP_RT_ID_DB_SYNC:1][group_id_be:8][payload]. Возвращает код etcp_send
|
||||
static int db_sync_send_gid(struct DB_SYNC* db, uint64_t node_id, uint64_t group_id, const uint8_t* payload, size_t plen)
|
||||
{
|
||||
struct ll_entry* entry = queue_entry_new(0);
|
||||
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "queue_entry_new"); return -1; }
|
||||
uint8_t* buf = u_malloc(plen + 9);
|
||||
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_sync_send_hash: u_malloc(%zu) failed for dst=%016llx", plen + 9, (unsigned long long)node_id); queue_entry_free(entry); return -1; }
|
||||
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_sync_send_gid: u_malloc(%zu) failed for dst=%016llx", plen + 9, (unsigned long long)node_id); queue_entry_free(entry); return -1; }
|
||||
buf[0] = ETCP_RT_ID_DB_SYNC;
|
||||
uint64_t hb = htobe64(hash);
|
||||
memcpy(buf + 1, &hb, 8);
|
||||
uint64_t gb = htobe64(group_id);
|
||||
memcpy(buf + 1, &gb, 8);
|
||||
memcpy(buf + 9, payload, plen);
|
||||
entry->dgram = buf;
|
||||
entry->len = plen + 9;
|
||||
|
||||
struct ETCP_CONN* conn = instance_find_conn(db->inst, node_id);
|
||||
if (!conn || !conn->links_up) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync: send DROP — no conn to %04llX (hash=%016llx, type=%02x)",
|
||||
(unsigned long long)(node_id >> 16), hash, plen > 0 ? payload[0] : 0,
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync: send DROP — no conn to %04llX (group=%016llx, type=%02x)",
|
||||
(unsigned long long)(node_id >> 16), group_id, plen > 0 ? payload[0] : 0,
|
||||
(void*)conn, conn ? conn->links_up : -1);
|
||||
queue_entry_free(entry);
|
||||
return -1;
|
||||
@@ -700,10 +700,10 @@ static int db_sync_send_hash(struct DB_SYNC* db, uint64_t node_id, uint64_t hash
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Отправляет сообщение через ETCP от имени конкретного инстанса (подставляет хеш инстанса)
|
||||
// Отправляет сообщение через ETCP от имени конкретного инстанса (подставляет group_id инстанса)
|
||||
static int db_sync_send(struct DB_SYNC_INSTANCE* si, uint64_t dst_node_id, const uint8_t* payload, size_t len)
|
||||
{
|
||||
return db_sync_send_hash(si->db_sync, dst_node_id, si->hash, payload, len);
|
||||
return db_sync_send_gid(si->db_sync, dst_node_id, si->group_id, payload, len);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -1202,15 +1202,15 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
if (!db || !db->enabled) { queue_dgram_free(entry); queue_entry_free(entry); return; }
|
||||
|
||||
uint64_t src = conn ? conn->peer_node_id : 0;
|
||||
uint64_t hash = be64toh(*(uint64_t*)(entry->dgram + 1));
|
||||
uint64_t group_id = be64toh(*(uint64_t*)(entry->dgram + 1));
|
||||
uint8_t type = entry->dgram[9];
|
||||
const uint8_t* payload = entry->dgram + 10;
|
||||
size_t plen = entry->len - 10;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "recv type=%02x from=%016llx hash=%016llx len=%zu", type, (unsigned long long)src, (unsigned long long)hash, plen);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "recv type=%02x from=%016llx group=%016llx len=%zu", type, (unsigned long long)src, (unsigned long long)group_id, plen);
|
||||
|
||||
struct DB_SYNC_INSTANCE* si = db_instance_find(db, hash);
|
||||
struct DB_SYNC_INSTANCE* si = db_instance_find(db, group_id);
|
||||
if (!si) {
|
||||
/* lazy-register: find table msg_<ch_id> with matching SHA256 */
|
||||
/* lazy-register: найти таблицу msg_<ch_id>, у которой strtoull(ch_id) == group_id */
|
||||
sqlite3_stmt* st = NULL;
|
||||
if (sqlite3_prepare_v2(db->db,
|
||||
"SELECT name, substr(name,5) FROM sqlite_master WHERE type='table' AND name LIKE 'msg_%'",
|
||||
@@ -1219,11 +1219,11 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
const char* tbl = (const char*)sqlite3_column_text(st, 0);
|
||||
const char* ch_id = (const char*)sqlite3_column_text(st, 1);
|
||||
if (!ch_id || !ch_id[0]) continue;
|
||||
uint64_t h; { uint8_t sh[32]; SHA256((const uint8_t*)ch_id, strlen(ch_id), sh); memcpy(&h, sh, 8); }
|
||||
if (h == hash) {
|
||||
si = db_sync_instance_add(db->inst, tbl, hash, 1);
|
||||
uint64_t gid = strtoull(ch_id, NULL, 10);
|
||||
if (gid == group_id) {
|
||||
si = db_sync_instance_add(db->inst, tbl, group_id, 1);
|
||||
if (si) { si_peer_add(si, src); }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "lazy-register: tbl=%s ch=%s hash=%016llx", tbl, ch_id, (unsigned long long)hash);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "lazy-register: tbl=%s ch=%s group=%016llx", tbl, ch_id, (unsigned long long)group_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1231,17 +1231,17 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
}
|
||||
if (!si) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC,
|
||||
"recv msg type=0x%02x from %016llx hash=%016llx — instance NOT FOUND; sending DB_ERR_NOT_FOUND",
|
||||
type, (unsigned long long)src, (unsigned long long)hash);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ instance not found for hash=%016llx", (unsigned long long)hash);
|
||||
"recv msg type=0x%02x from %016llx group=%016llx — instance NOT FOUND; sending DB_ERR_NOT_FOUND",
|
||||
type, (unsigned long long)src, (unsigned long long)group_id);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ instance not found for group=%016llx", (unsigned long long)group_id);
|
||||
uint8_t err[2]; err[0] = DB_MSG_ERROR; err[1] = DB_ERR_NOT_FOUND;
|
||||
db_sync_send_hash(db, src, hash, err, 2);
|
||||
db_sync_send_gid(db, src, group_id, err, 2);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
}
|
||||
if (!si->enabled) {
|
||||
uint8_t err[2]; err[0] = DB_MSG_ERROR; err[1] = DB_ERR_DISABLED;
|
||||
db_sync_send_hash(db, src, hash, err, 2);
|
||||
db_sync_send_gid(db, src, group_id, err, 2);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
|
||||
@@ -1255,8 +1255,8 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
case DB_MSG_SYNC_DONE: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle SYNC_DONE"); db_handle_sync_done(si, src, payload, plen); break;
|
||||
case DB_MSG_ERROR: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle ERROR"); db_handle_error(si, src, payload, plen); break;
|
||||
default:
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "sync: unknown msg type 0x%02x from %04llX (hash=%016llx) — dropped",
|
||||
type, (unsigned long long)(src >> 16), hash);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "sync: unknown msg type 0x%02x from %04llX (group=%016llx) — dropped",
|
||||
type, (unsigned long long)(src >> 16), group_id);
|
||||
break;
|
||||
}
|
||||
queue_dgram_free(entry);
|
||||
@@ -1707,19 +1707,19 @@ void db_sync_destroy(struct UTUN_INSTANCE* inst)
|
||||
}
|
||||
|
||||
// Создаёт SQLite-таблицу для синхронизации, регистрирует пиров, запускает первичную синхронизацию и TTL-таймер
|
||||
struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const char* table_name, uint64_t hash, int auto_sync)
|
||||
struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const char* table_name, uint64_t group_id, int auto_sync)
|
||||
{
|
||||
if (!inst || !inst->db_sync || !table_name || !table_name[0]) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "instance_add invalid args"); return NULL; }
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "table=%s hash=%016llx", table_name, (unsigned long long)hash);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "table=%s group=%016llx", table_name, (unsigned long long)group_id);
|
||||
struct DB_SYNC* db = inst->db_sync;
|
||||
if (!db->enabled || !db->db) return NULL;
|
||||
|
||||
struct DB_SYNC_INSTANCE* si = db_instance_find(db, hash);
|
||||
if (si) { DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance already exists hash=%016llx", (unsigned long long)hash); return si; }
|
||||
struct DB_SYNC_INSTANCE* si = db_instance_find(db, group_id);
|
||||
if (si) { DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance already exists group=%016llx", (unsigned long long)group_id); return si; }
|
||||
|
||||
si = db_instance_alloc(db);
|
||||
if (!si) return NULL;
|
||||
si->hash = hash;
|
||||
si->group_id = group_id;
|
||||
snprintf(si->table_name, sizeof(si->table_name), "%s", table_name);
|
||||
|
||||
// Create table — PK is (timestamp, node_id), author_signature NOT NULL
|
||||
@@ -1762,7 +1762,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
|
||||
|
||||
db_verify_chain(si);
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "instance_add: tbl=%s mc=%u next_id=%llu hash=%016llx", SI_TBL(si), db_count(si), (unsigned long long)si->next_id, (unsigned long long)si->hash);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "instance_add: tbl=%s mc=%u next_id=%llu group=%016llx", SI_TBL(si), db_count(si), (unsigned long long)si->next_id, (unsigned long long)si->group_id);
|
||||
|
||||
si->ttl_timer = uasync_set_timeout(inst->ua, DB_SYNC_TTL_INTERVAL * 10000u, si, db_sync_instance_ttl_cb, "db_sync_ttl");
|
||||
|
||||
@@ -1783,8 +1783,8 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC,
|
||||
"instance added table=%s tbl=%s hash=%016llx next_id=%llu peers_found=%d peers_synced=%d mc=%u",
|
||||
table_name, si->table_name, (unsigned long long)hash,
|
||||
"instance added table=%s tbl=%s group=%016llx next_id=%llu peers_found=%d peers_synced=%d mc=%u",
|
||||
table_name, si->table_name, (unsigned long long)group_id,
|
||||
(unsigned long long)si->next_id, peers_found, peers_synced, db_count(si));
|
||||
return si;
|
||||
}
|
||||
@@ -1793,7 +1793,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
|
||||
void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si)
|
||||
{
|
||||
if (!si) return;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s hash=%016llx", si->table_name, (unsigned long long)si->hash);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s group=%016llx", si->table_name, (unsigned long long)si->group_id);
|
||||
struct DB_SYNC* db = si->db_sync;
|
||||
struct UTUN_INSTANCE* inst = db->inst;
|
||||
|
||||
@@ -1808,7 +1808,7 @@ void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si)
|
||||
(db->instance_count - idx - 1) * sizeof(*db->instances));
|
||||
db->instance_count--;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance removed tbl=%s hash=%016llx", si->table_name, (unsigned long long)si->hash);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance removed tbl=%s group=%016llx", si->table_name, (unsigned long long)si->group_id);
|
||||
}
|
||||
|
||||
// Вставляет подписанную запись: проверяет подпись, вставляет в БД, рассылает PUSH всем синхронизированным пирам
|
||||
|
||||
Reference in new issue
Block a user