/* * ── member_sync — синхронизация участников чата ── * * Тонкая прослойка над merkle_sync, адаптированная под мемберов каналов. * Данные хранятся в таблицах: nodes, node_addresses, peers_. * Хеш мембера = SHA256(node_id || x25519 || ed25519 || join_sig || join_ts || addrs). * * ── Использование ── * * // разово: инициализация (из chat_sync_init) * member_sync_init(inst); * * // асинхронный запуск синхронизации (из cs_on_conn_up) * member_sync_start(inst, peer, ch_id, on_done, ch); * * // коллбэк: синхронизация завершена * static void on_done(uint64_t peer, const char* ch_id, int result, void* arg) { * struct channel_cache* ch = (struct channel_cache*)arg; * if (result == MT_OK) ch->synced = CS_SYNC_DONE; * } * * // добавление/обновление мембера (из chat_core_create_channel, cs_handle_welcome) * member_sync_put(inst, ch_id, node_id, x25519, ed25519, join_sig, join_ts, addrs, ac); * // дерево автоматически пересчитано * * // онлайн-статус (из cs_on_conn_up / cs_on_conn_down) * member_sync_set_online(inst, node_id, 1); // online * member_sync_set_online(inst, node_id, 0); // offline * * // удаление мембера * member_sync_del(inst, ch_id, node_id); * * // отмена синхронизации (коллбэк НЕ вызывается) * member_sync_cancel(inst, peer, ch_id); * * // количество мемберов в канале * int n = member_sync_count(inst, ch_id); * * // разово: завершение (из chat_sync_destroy) * member_sync_destroy(inst); */ #ifndef MEMBER_SYNC_H #define MEMBER_SYNC_H #include "merkle_sync.h" #ifdef __cplusplus extern "C" { #endif #include #include struct UTUN_INSTANCE; /* * Инициализировать модуль: создаёт merkle_sync с коллбэками для мемберов * (ETCP сервис 0x31), регистрирует _on_node_updated для пересчёта дерева * при обновлении node info. */ int member_sync_init(struct UTUN_INSTANCE* inst); /* Завершить модуль. */ void member_sync_destroy(struct UTUN_INSTANCE* inst); /* * Запустить синхронизацию мемберов канала ch_id с пиром peer. * Делегирует в merkle_sync_start(). */ int member_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer, const char* ch_id, merkle_sync_done_cb done_cb, void* arg); /* * Отменить синхронизацию. Делегирует в merkle_sync_cancel(). */ void member_sync_cancel(struct UTUN_INSTANCE* inst, uint64_t peer, const char* ch_id); /* * Добавить/обновить мембера и пересчитать дерево. * * ch_id — ID канала * member_id — node_id участника * x25519 — X25519 публичный ключ (32 байта) * ed25519 — Ed25519 публичный ключ (32 байта) * join_sig — Ed25519 подпись join-сообщения (64 байта) * сообщение: ch_x25519(32) || ch_ed25519(32) || node_id(8LE) || x25519(32) || join_ts(8LE) * join_ts — NTP-синхронизированное время подписи (unix epoch seconds) * userinfo — метаданные узла (имя) в канале * addrs_data — адреса в wire-формате: [family:1][ip:4|16][port:2]... * addr_count — количество адресов (0 если нет) * * Пишет только в таблицу peers_ (INSERT OR REPLACE). * nodes обновляется отдельно через topo_node_sqlite_node_update_verified(). * Вызывает merkle_sync_recompute_path() для пересчёта дерева. * * Возвращает 0 при успехе, -1 при ошибке. */ int member_sync_put(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t member_id, const uint8_t* x25519, const uint8_t* ed25519, const uint8_t* join_sig, uint64_t join_ts, const uint8_t* update_sig, uint64_t update_ts, const char* userinfo, const uint8_t* addrs_data, int addr_count); /* Удалить мембера из канала и пересчитать дерево. */ int member_sync_del(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t member_id); /* Количество мемберов в канале (SELECT COUNT из peers_). */ int member_sync_count(struct UTUN_INSTANCE* inst, const char* ch_id); /* * Установить онлайн-статус узла (nodes.online = 0/1). */ void member_sync_set_online(struct UTUN_INSTANCE* inst, uint64_t node_id, int online); /* Получить хеш бакета из merkle_tree_hash (для тестов). */ const uint8_t* member_sync_get_hash(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t level, uint64_t prefix64); /* * Коллбэк: узел изменился по инициативе удалённого пира (через MSG_ITEM_UPDATE). * Вызывается из uasync-потока. Потребитель (chat_sync) может из него * постить GUI-события. */ typedef void (*member_sync_node_updated_fn)(uint64_t node_id, int online); void member_sync_set_node_updated_cb(member_sync_node_updated_fn cb); #ifdef __cplusplus } #endif #endif /* MEMBER_SYNC_H */