Files
utun2/src/chat/db_sync.h
T

142 lines
7.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* db_sync — репликация подписанных записей SQLite по прямым ETCP-соединениям.
* Каждый DB_SYNC_INSTANCE связывает таблицу с group_id. Различия находятся по
* цепочке хешей; новые записи рассылаются PUSH. Ключ и порядок записей:
* (timestamp, author_signature). Подпись автора покрывает timestamp || data.
* Ядро создаёт модуль, чат включает его и регистрирует таблицы каналов.
* Обычно используется общая SQLite ядра; remove отключает таблицу от обмена,
* сохраняя данные. Все вызовы и callbacks выполняются в потоке uasync. */
#ifndef DB_SYNC_H
#define DB_SYNC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
struct UTUN_INSTANCE;
struct DB_SYNC_INSTANCE;
// etcp service ID: ETCP_RT_ID_DB_SYNC (etcp_bind, см. etcp_api.h)
// Message types
#define DB_MSG_INIT_SYNC 0x01
#define DB_MSG_INIT_RESP 0x02
#define DB_MSG_SEND_DATA 0x04
#define DB_MSG_PUSH 0x05
#define DB_MSG_ACK_PUSH 0x06
#define DB_MSG_SYNC_DONE 0x07
#define DB_MSG_ERROR 0x08
#define DB_MSG_REQUEST_SYNC 0x09
/* PUSH имеет фиксированный буфер 4096 байт; 4000 оставляет место заголовку и подписи. */
#define DB_SYNC_MESSAGE_MAX 4000
// SEND_DATA want_from sentinel
#define DB_WANT_FROM_NONE 0xFFFFFFFF // no request for peer's data
// SEND_DATA wire: [from:4][count:2][vp:4][want_from:4][records...]
// Record: [id:8][ts:8][node_id:8][dlen:4][data][sig_len:1=64][sig:64]
// SYNC_DONE wire: [count:4][chain_hash8:8]
// Error codes for DB_MSG_ERROR
#define DB_ERR_NOT_FOUND 0x01 // instance not found
#define DB_ERR_DISABLED 0x02 // instance exists but disabled
#define DB_ERR_NOT_READY 0x03 // участники или групповая сессия ещё не готовы
// Defaults
#define DB_SYNC_DEFAULT_TTL 86400
#define DB_SYNC_DEFAULT_MAPSIZE (100UL * 1024 * 1024)
#define DB_SYNC_PEER_CHECK_INTERVAL 5
#define DB_SYNC_SYNC_TIMEOUT 15
#define DB_SYNC_TTL_INTERVAL 3600
// Record flags
#define DB_REC_FLAG_WAS_SENT 0x01
// Sync protocol constants
#define DB_SEND_DATA_MAX 32
// Ed25519 signature size
#define DB_SIG_SIZE 64
// Создать контекст и учесть db_sync_enabled из конфига. 0/-1.
int db_sync_init(struct UTUN_INSTANCE* inst);
// Включить ранее созданный модуль независимо от флага конфига. Повтор допустим; 0/-1.
int db_sync_enable(struct UTUN_INSTANCE* inst);
// Отменить таймеры/обмен, снять обработчики; общую SQLite не закрывает.
void db_sync_destroy(struct UTUN_INSTANCE* inst);
// Зарегистрировать таблицу существующей группы без сетевого обмена; первоначально gated. NULL при ошибке.
struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const char* table_name, uint64_t group_id);
// Освободить экземпляр синхронизации; сама таблица остаётся в БД.
void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si);
// Заимствованный указатель по group_id; действителен до remove/destroy, NULL если нет.
struct DB_SYNC_INSTANCE* db_sync_instance_find(struct UTUN_INSTANCE* inst, uint64_t group_id);
// group_id инстанса (для chat-таблиц равен числовому channel_id). Возвращает 0 при si==NULL.
uint64_t db_sync_instance_group_id(struct DB_SYNC_INSTANCE* si);
// Data operations (per-instance)
// db_sync_insert_signed: sig MUST be non-NULL, 64 bytes.
// sig = Ed25519(ts[8] || json); ts записан в порядке байтов хоста.
// ts — call db_sync_next_timestamp(si) before signing to reserve monotonically increasing timestamp.
int db_sync_insert_signed(struct DB_SYNC_INSTANCE* si, const char* json_data, size_t len,
const uint8_t* sig, size_t sig_len, uint64_t ts,
const char* local_attrs);
uint32_t db_sync_count(struct DB_SYNC_INSTANCE* si);
// Последний известный/зарезервированный timestamp в миллисекундах Unix; 0 для NULL.
uint64_t db_sync_get_last_timestamp(struct DB_SYNC_INSTANCE* si);
// Зарезервировать следующий timestamp перед подписью; растёт даже в пределах одной ms.
uint64_t db_sync_next_timestamp(struct DB_SYNC_INSTANCE* si);
// Обход по (timestamp, author_signature), начиная с offset; limit=0 — без ограничения.
// Возвращает число записей или -1. Данные callback заимствованы на время вызова.
typedef void (*db_sync_select_cb)(void* arg, uint64_t id, uint64_t timestamp,
const char* data, size_t data_len, uint64_t author,
const uint8_t* author_sig, size_t sig_len,
int delivered_peers, const char* delivery_chain);
int db_sync_select(struct DB_SYNC_INSTANCE* si, uint32_t offset, uint32_t limit,
db_sync_select_cb cb, void* arg);
// Insert callback: fired after local or peer insert succeeds.
// author_node_id — исходный автор записи, не обязательно переславший её пир.
// initial_sync = 1 если запись пришла в рамках bulk-обмена SEND_DATA (initial/re-sync),
// 0 для live-PUSH и локальных вставок.
typedef void (*db_sync_insert_cb)(struct DB_SYNC_INSTANCE* si,
const uint8_t message_id[32],
uint64_t record_timestamp,
const char* json_data, size_t len,
uint64_t author_node_id, int initial_sync, void* arg);
void db_sync_set_insert_cb(struct DB_SYNC_INSTANCE* si, db_sync_insert_cb cb, void* arg);
// Verify chain integrity: returns 0 if all chain_hashes are correct, 1 if any mismatch found
int db_sync_chain_verify(struct DB_SYNC_INSTANCE* si);
// Peer state control (for testing — disable PUSH to isolate sync protocol)
void db_sync_peer_set_state(struct DB_SYNC_INSTANCE* si, uint64_t node_id, uint8_t state);
// Per-(chat,peer) «play sound on message» flag: sound_off + sleeping peer → throttled.
void db_sync_set_peer_sound(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t peer_node_id, int sound_on);
// До успешного member_sync блокирует входящий и исходящий обмен. После снятия
// блокировки запускает историю только через READY-пиров этой группы.
void db_sync_instance_set_gated(struct DB_SYNC_INSTANCE* si, int gated);
// Force re-initiate sync to a specific peer (for testing)
void db_sync_reinitiate(struct DB_SYNC_INSTANCE* si, uint64_t node_id);
// Get last chain hash8 (for cross-peer consistency check in tests)
int db_sync_last_chain_hash8(struct DB_SYNC_INSTANCE* si, uint64_t* out_hash8);
// Sync completion callback (global, per-instance: fires when SYNC_DONE sent/received for any group)
typedef void (*db_sync_done_fn)(struct DB_SYNC_INSTANCE* si, uint64_t peer_node_id, void* arg);
void db_sync_add_done_cbk(struct UTUN_INSTANCE* inst, db_sync_done_fn fn, void* arg);
void db_sync_remove_done_cbk(struct UTUN_INSTANCE* inst, db_sync_done_fn fn, void* arg);
#ifdef __cplusplus
}
#endif
#endif // DB_SYNC_H