Browse Source

Keep message content type alive through JSON serialization

master
evgeny 1 week ago
parent
commit
387f95208d
  1. 3
      src/chat/chat_core.c
  2. 54
      src/chat/db_sync_arch.md

3
src/chat/chat_core.c

@ -397,8 +397,9 @@ int chat_core_get_messages_json(struct UTUN_INSTANCE* inst, const char* ch_id, i
if (!data) data = "";
if (!la) la = "";
const char* ct = "text";
char ctbuf[32] = {0};
const char* ctpos = strstr(data, "\"ct\":\"");
if (ctpos) { ctpos += 6; char ctbuf[32] = {0}; int ci = 0; while (*ctpos && *ctpos != '"' && ci < 31) ctbuf[ci++] = *ctpos++; ct = ctbuf; }
if (ctpos) { ctpos += 6; int ci = 0; while (*ctpos && *ctpos != '"' && ci < 31) ctbuf[ci++] = *ctpos++; ct = ctbuf; }
char esc_data[4096], esc_aname[256], esc_la[256];
json_escape(data, esc_data, sizeof(esc_data));
json_escape(author_name ? author_name : "", esc_aname, sizeof(esc_aname));

54
src/chat/db_sync_arch.md

@ -36,7 +36,8 @@
**DB_SYNC_INSTANCE** — одна таблица синхронизации:
- `table_name` — имя SQLite-таблицы (например `msg_GENERAL`)
- `hash` — instance_hash = первые 8 байт SHA256(name || id_be) для маршрутизации сообщений
- `group_id` — идентификатор группы для маршрутизации сообщений
- `sync_gated` — ожидание успешной синхронизации участников; блокирует входящий и исходящий обмен
- `next_id` — автоинкрементный ID записей
- `last_timestamp_ms` — последний использованный timestamp (монотонный)
- `peers[]` — динамический массив SI_PEER (состояние синхронизации с каждым пиром)
@ -50,8 +51,8 @@
- `verified_pos` — последняя подтверждённая позиция (совпадение хешей)
- `last_peer_count` — последнее известное количество записей у пира
- `sync_state` — 0=idle, 1=syncing, 2=synced
- `sync_start_tb` — время начала синхронизации (для детекции таймаутов)
- `retry_count` — счётчик ретраев (зарезервировано, не используется)
- `sync_start_tb` — время начала/последнего прогресса обмена; устанавливается в обеих ролях
- `retry_count` — число повторов после таймаута
### 1.2 Структура данных (SQLite)
@ -128,7 +129,7 @@ chain_hash[0] = SHA256(0x00..00 [32] || id_0 || ts_0 || author_0 || sig_0)
│ └──────────────┘ └───────────────┘
│ │
└─────────────────────────────────────────────┘
CONN DOWN / ERROR (DB_ERR_NOT_FOUND, DB_ERR_DISABLED)
потеря READY группы / ERROR (NOT_FOUND, DISABLED, NOT_READY)
```
### 2.2 Диаграмма протокола синхронизации
@ -137,7 +138,7 @@ chain_hash[0] = SHA256(0x00..00 [32] || id_0 || ts_0 || author_0 || sig_0)
MASTER (node_id > peer) SLAVE (node_id < peer)
─────────────────────── ──────────────────────
conn UP → initiate sync
участники синхронизированы + READY группы → initiate sync
│
├─ INIT_SYNC ──────────────────────────►
│ [my_count:4] │ flush recalc
@ -183,31 +184,29 @@ conn UP → initiate sync
│ db_sync_init(inst) │
│ ├─ открывает SQLite (shared или свой chats.db) │
│ ├─ etcp_bind(inst, 0x20, recv_cb) │
│ ├─ etcp_add_conn_status_cbk(conn_status) │
│ └─ запускает peer_check_timer (5s) │
│ └─ таймер повторов запускается при появлении работы │
│ │
│ ... позже, при создании канала ... │
│ │
│ db_sync_instance_add(inst, "msg_GENERAL", hash, 1) │
│ db_sync_instance_add(inst, "msg_GENERAL", group_id) │
│ ├─ CREATE TABLE IF NOT EXISTS... │
│ ├─ загружает next_id = MAX(id)+1 │
│ ├─ db_verify_chain() — проверка целостности цепных хешей │
│ ├─ запускает TTL-таймер (1 час) │
│ └─ для всех активных соединений: si_peer_add() + initiate_sync() │
│ └─ подписка на READY группы; gated=1, сетевого обмена нет │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─── DB_SYNC_INSTANCE активен ───────────────────────────────────────────┐│
│ │ ││
│ │ conn UP ──► on_conn_up() ││
│ │ └─ для всех enabled инстансов: ││
│ │ si_peer_add() → initiate_sync() ││
│ │ member_sync OK + READY группы → initiate_sync() ││
│ │ └─ пир должен быть участником именно этой группы ││
│ │ ││
│ │ conn DOWN ──► on_conn_down() ││
│ │ └─ сброс sync_state для всех инстансов ││
│ │ потеря READY (DOWN/REINIT/LEAVE/ошибка отправки снимка) ││
│ │ └─ сброс состояния обмена только этой групповой сессии ││
│ │ ││
│ │ recv_cb() — приём сообщений ││
│ │ ├─ извлекает instance_hash, type, payload ││
│ │ ├─ lazy-register если инстанс не найден ││
│ │ ├─ извлекает group_id, type, payload ││
│ │ ├─ проверяет регистрацию, членство, gated и READY ││
│ │ └─ диспетчеризация по type ││
│ │ ││
│ │ peer_check_timer (каждые 5с) ││
@ -222,6 +221,7 @@ conn UP → initiate sync
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ db_sync_instance_remove(si) │
│ ├─ снимает подписку на готовность группы │
│ ├─ отменяет таймеры │
│ ├─ освобождает peers[] │
│ └─ сдвигает массив instances[] (таблица БД не удаляется) │
@ -245,13 +245,13 @@ conn UP → initiate sync
```
┌─────────────────┬──────────────┬──────────────────────────────┐
│ svc_id (1 byte) │ hash_be (8) │ payload (variable) │
│ ETCP_RT_ID=0x20 │ instance_hash│ зависит от type │
│ svc_id (1 byte) │ group_id (8) │ payload (variable) │
│ ETCP_RT_ID=0x20 │ big-endian │ зависит от type │
└─────────────────┴──────────────┴──────────────────────────────┘
```
**instance_hash** = первые 8 байт `SHA256(table_name || id_be)` в big-endian.
Это позволяет приёмной стороне найти `DB_SYNC_INSTANCE` по хешу.
**group_id** — идентификатор группы в big-endian. Приёмная сторона находит
зарегистрированную таблицу этой группы; входящий пакет не создаёт таблицы или callbacks.
### 3.2 Типы сообщений
@ -263,7 +263,7 @@ conn UP → initiate sync
| `DB_MSG_PUSH` | 0x05 | →Peers | Рассылка новой записи всем synced-пирам |
| `DB_MSG_ACK_PUSH` | 0x06 | →Author | Подтверждение получения PUSH |
| `DB_MSG_SYNC_DONE` | 0x07 | ↔ | Завершение синхронизации |
| `DB_MSG_ERROR` | 0x08 | ↔ | Ошибка (NOT_FOUND, DISABLED) |
| `DB_MSG_ERROR` | 0x08 | ↔ | Ошибка (NOT_FOUND, DISABLED, NOT_READY) |
| `DB_MSG_REQUEST_SYNC` | 0x09 | Slave→Master | Запрос на инициацию синхронизации |
### 3.3 DB_MSG_INIT_SYNC (0x01)
@ -416,10 +416,18 @@ tp=10 → entry[0]: pos=9 (tp - 1)
Коды ошибок:
| #define | Value | Значение |
|---------|-------|----------|
| `DB_ERR_NOT_FOUND` | 0x01 | Инстанс с таким hash не найден |
| `DB_ERR_NOT_FOUND` | 0x01 | Таблица этой группы не зарегистрирована |
| `DB_ERR_DISABLED` | 0x02 | Инстанс существует, но disabled |
| `DB_ERR_NOT_READY` | 0x03 | Участники или групповая сессия ещё не готовы |
При получении ERROR сбрасывается `sync_state` пира в 0.
При получении ERROR сбрасываются `sync_state` и ожидание ответа; планируется повтор.
Ошибка отправки также возвращает обмен в IDLE. Обе роли ждут прогресс не более 15 секунд;
таймер повторов работает с периодом 5 секунд, пока есть несинхронизированные READY-пиры.
Появление нового READY запускает обмен независимо от того, работал ли таймер.
При JOIN запись connection-узла из JOIN_INFO_RESP применяется через `member_sync_apply_record()`:
подписи проверяются, модель и Merkle-индекс обновляются в одной транзакции. JOIN_READY
подтверждает вступление, но история разблокируется только после успешного member_sync.
### 3.10 DB_MSG_REQUEST_SYNC (0x09)

Loading…
Cancel
Save