/* * chat_core_priv.h — внутренний заголовок для под-модулей chat_core * * Предоставляет доступ к глобальному состоянию g_cc и общим хелперам. * Не включать извне chat/ — только для chat_core*.c. */ #ifndef CHAT_CORE_PRIV_H #define CHAT_CORE_PRIV_H #include "chat_core.h" #include "db_sync.h" #include "../../lib/debug_config.h" #include #include #include #include #define CC_ID "chat_core" /* ── Base64 encode/decode (URL-safe, used for msg "d" field prefix) ── */ static const char B64_ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; static inline int b64_decode_char(char c) { if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '-') return 62; if (c == '_') return 63; return -1; } static inline size_t b64_encode(const uint8_t* src, size_t src_len, char* dst, size_t dst_cap) { size_t out = 0; for (size_t i = 0; i < src_len; i += 3) { if (out + 4 > dst_cap) break; uint32_t v = (uint32_t)src[i] << 16; if (i + 1 < src_len) v |= (uint32_t)src[i + 1] << 8; if (i + 2 < src_len) v |= (uint32_t)src[i + 2]; dst[out++] = B64_ALPHABET[(v >> 18) & 0x3F]; dst[out++] = B64_ALPHABET[(v >> 12) & 0x3F]; dst[out++] = (i + 1 < src_len) ? B64_ALPHABET[(v >> 6) & 0x3F] : '='; dst[out++] = (i + 2 < src_len) ? B64_ALPHABET[v & 0x3F] : '='; } return out; } static inline size_t b64_decode(const char* src, size_t src_len, uint8_t* dst, size_t dst_cap) { size_t out = 0; int vals[4]; size_t vi = 0; for (size_t i = 0; i < src_len && out < dst_cap; i++) { if (src[i] == '=') break; int v = b64_decode_char(src[i]); if (v < 0) continue; vals[vi++] = v; if (vi == 4) { dst[out++] = (uint8_t)((vals[0] << 2) | (vals[1] >> 4)); if (out < dst_cap) dst[out++] = (uint8_t)((vals[1] << 4) | (vals[2] >> 2)); if (out < dst_cap) dst[out++] = (uint8_t)((vals[2] << 6) | vals[3]); vi = 0; } } if (vi == 3 && out < dst_cap) { dst[out++] = (uint8_t)((vals[0] << 2) | (vals[1] >> 4)); if (out < dst_cap) dst[out++] = (uint8_t)((vals[1] << 4) | (vals[2] >> 2)); } else if (vi == 2 && out < dst_cap) { dst[out++] = (uint8_t)((vals[0] << 2) | (vals[1] >> 4)); } return out; } /* ── Глобальное состояние (определено в chat_core.c) ── */ struct ms_props_cbk; /* member_sync.c */ struct ms_apply_cbk; /* member_sync.c */ struct chat_core_ctx { struct UTUN_INSTANCE* inst; sqlite3* db; char db_path[512]; uint8_t shared_db; uint64_t my_node_id; uint8_t initialized; /* per-instance sub-module state (was file-scope statics) */ struct ms_props_cbk* props_cbks; /* was member_sync.c g_props_cbks */ struct ms_apply_cbk* apply_cbks; /* was member_sync.c g_apply_cbks */ uint64_t media_cache_bytes; /* was chat_msg.c g_media_cache_bytes */ void* media_backfill_timer;/* was chat_msg.c g_media_startup_backfill_timer */ int media_backfill_ran; /* was chat_msg.c g_media_startup_backfill_ran */ struct UTUN_INSTANCE* media_backfill_inst; /* was chat_msg.c g_media_startup_backfill_inst */ void* media_channel_backfill_timer; /* debounce per-channel докачки */ char media_channel_backfill[16][64]; /* pending ch_id */ int media_channel_backfill_pending; }; /* Per-instance chat context. inst->chat_core обязателен после chat_core_init. */ #define CC(inst) ((inst)->chat_core) /* ── Хелперы ── */ void sanitize_ch_id(const char* ch_id, char* out, size_t out_sz); void msg_table_name(const char* ch_id, char* buf, size_t sz); void peers_table_name(const char* ch_id, char* buf, size_t sz); /* ── db_sync registry (chat_core.c) ── */ struct DB_SYNC_INSTANCE* si_find(struct UTUN_INSTANCE* inst, const char* ch_id); void si_register(struct UTUN_INSTANCE* inst, struct DB_SYNC_INSTANCE* si, const char* ch_id); /* ── db_sync callback (chat_msg.c) ── */ struct msg_insert_arg { struct UTUN_INSTANCE* inst; char ch_id[64]; }; void on_msg_inserted(struct DB_SYNC_INSTANCE* si, uint64_t record_ts, const char* data, size_t len, uint64_t author, int initial_sync, void* arg); /* ── применить настройку group_autoconnect ко всем CHAT-группам (chat_channel.c) ── */ void chat_core_apply_group_autoconnect(struct UTUN_INSTANCE* inst); #endif /* CHAT_CORE_PRIV_H */