schema: rm is_dm, rename name→userinfo (json_flat), fix join_msg format
- Remove is_dm column from channels table (dm detection by member count)
- Rename member name column to userinfo — extensible json_flat format
- Add json_flat.c/h library for compact JSON serialization
- Fix join_sig message format: use ch_x25519+ch_ed25519 instead of channel_id string
- Remove name from join_msg body (now in userinfo via json_flat)
- Update chat_core, chat_sync, member_sync, db_manager to new format
- Add topo_strategy.txt — архитектурные заметки по топологии
conn_mgr_send(mgr, node_id, entry); // entry освобождается внутри
conn_mgr_send(mgr, node_id, entry); // entry освобождается внутри
```
```
### Alien-ноды
Для нод, которые сами подключились к нам, используется `conn_mgr_add_alien_node()` — не запускает фазы подключения, сразу устанавливает `CONNECTED`.
### Кандидаты-посредники
### Кандидаты-посредники
Внешний код (обычно `route_connectivity`) вызывает `conn_mgr_update_best_candidates()` для заполнения списка лучших посредников (топ-3 по RTT). Список используется фазой INDIRECT.
Внешний код (обычно `route_connectivity`) вызывает `conn_mgr_update_best_candidates()` для заполнения списка лучших посредников (топ-3 по RTT). Список используется фазой INDIRECT.
| `CONN_MGR_ENTRY` | Запись о подключении к одной ноде: `state`, `conn_type`, `alien`, `idle_timeout_ms`, список коллбэков `cb_list`, массив `intermediaries[]`, состояния `local_scan_state`/`main_connect_state`, текущая `main.phase` |
| `CONN_MGR_ENTRY` | Запись о подключении к одной ноде: `state`, `conn_type`, `idle_timeout_ms`, список коллбэков `cb_list`, массив `intermediaries[]`, состояния `local_scan_state`/`main_connect_state`, текущая `main.phase` |
| `CONN_MGR_CANDIDATE` | Пара `{node_id, rtt}` — запись о кандидате-посреднике (packed) |
| `CONN_MGR_CANDIDATE` | Пара `{node_id, rtt}` — запись о кандидате-посреднике (packed) |
@ -11,7 +11,8 @@ BGP-подобный обмен топологией узлов между пи
Группа по умолчанию (UTUN) создаётся автоматически при `topo_groups_init()`. Дополнительные группы создаются через `topo_groups_create_group()` (для chatgui). Узлы разных групп изолированы: peer из utun-группы не видит узлы чат-группы и наоборот.
Группа по умолчанию (UTUN) создаётся автоматически при `topo_groups_init()`. Дополнительные группы создаются через `topo_groups_create_group()` (для chatgui). Узлы разных групп изолированы: peer из utun-группы не видит узлы чат-группы и наоборот.
Помимо обмена топологией, модуль выполняет:
Помимо обмена топологией, модуль выполняет:
- **NAT-детекцию** (NAT_INFO / NAT_CHECK_REQ): клиент запрашивает проверку своего NAT у сервера; сервер через третий узел пингует клиента и сообщает тип NAT (EIM/STRICT)
- **Сборку local_node** (`topo_group_update_my_nodeinfo`) — при старте и при изменениях конфигурации сокетов собирает информацию о себе (адреса, подсети, ключи)
- **NAT-детекцию** — выделена в отдельный самодостаточный модуль `nat_detection.h` (свой ETCP_ID 0x02, своя обработка пакетов); topo_group предоставляет делегат `topo_group_set_nat_check_local` для тестовых нужд
- **Поиск оптимального маршрута** до узла (`topo_group_find_conn_for_node`) — по min hop_count среди live-путей (ETCP соединений)
- **Поиск оптимального маршрута** до узла (`topo_group_find_conn_for_node`) — по min hop_count среди live-путей (ETCP соединений)
- **Зондирование связности** — для новых узлов запускает `route_connectivity_probe_node()`
- **Зондирование связности** — для новых узлов запускает `route_connectivity_probe_node()`
- **Персистентность в SQLite** — синхронизация узлов и membership в БД (таблицы nodes, node_addresses, peers_*)
- **Персистентность в SQLite** — синхронизация узлов и membership в БД (таблицы nodes, node_addresses, peers_*)
@ -26,47 +27,49 @@ struct TOPO_GROUPS* g = topo_groups_init(instance); // создаёт конт
2. `topo_group_remove_path_by_hop(nq, wd_source)` — удаление всех путей, содержащих wd_source в hop_list
2. `topo_group_remove_path_by_hop(nq, wd_source)` — удаление всех путей, содержащих wd_source в hop_list
3. Если путей не осталось (ret == 1): удаление из routing, уведомление control_server, broadcast withdraw дальше
3. Если путей не осталось (ret == 1): удаление из routing, уведомление control_server, установка `dirty = 1`, отмена connectivity probe (`route_connectivity_cancel_node`), освобождение paths, `topo_node_free_lists`, закрытие виртуальных каналов (`etcp_router_conn_close_all_for_node`), broadcast withdraw дальше
4. Если группа CHAT — удаление member из SQLite
4. Если группа CHAT — удаление member из SQLite через `topo_node_sqlite_member_del`
### 2.5. Отключение соединения
### 2.5. Отключение соединения
При ETCP on_down вызывается `topo_group_remove_conn(group, conn)`:
При ETCP on_down вызывается `topo_group_remove_conn(group, conn)`:
1. Отмена pending ping-запросов для этого conn
1. Проверка наличия conn в senders_list (если уже удалён — выход)
2. Для всех узлов с путями через этот conn — `topo_group_remove_path`. Если узел стал полностью недоступен (нет путей) — удаляется из routing и nodes, с broadcast withdraw
2. Для всех узлов с путями через этот conn — `topo_group_remove_path`. Если узел стал полностью недоступен (нет путей) — удаляется из routing и nodes, устанавливается `dirty = 1`, отменяется connectivity probe, закрываются виртуальные каналы, broadcast withdraw
3. Удаление conn из `senders_list`
3. Удаление conn из `senders_list`
### 2.6. Поиск пути до узла
### 2.6. Поиск пути до узла
@ -74,17 +77,19 @@ struct TOPO_GROUPS* g = topo_groups_init(instance); // создаёт конт
`topo_group_find_conn_for_node(group, node_id)` — перебирает `path`'ы узла, выбирает с минимальным `hop_count`. Предпочитает live-пути (links_up > 0). Если live-путей нет, fallback на любой путь с минимальным hop_count.
`topo_group_find_conn_for_node(group, node_id)` — перебирает `path`'ы узла, выбирает с минимальным `hop_count`. Предпочитает live-пути (links_up > 0). Если live-путей нет, fallback на любой путь с минимальным hop_count.
Интенсивно используется `etcp_router`:
Интенсивно используется `etcp_router`:
- При маршрутизации пакетов к удалённому узлу (`src/etcp_router.c:262`)
- При маршрутизации пакетов к удалённому узлу
- При поиске next-hop для multihop соединений
- При поиске next-hop для multihop соединений
### 2.7. NAT-детекция
### 2.7. NAT-детекция
1. При новом соединении вызывается `topo_group_start_link_nat_check` для каждого линка
NAT-детекция выделена в отдельный самодостаточный модуль `nat_detection.h`:
2. Сервер ищет «третий узел» через `topo_group_find_third_node` — произвольный conn кроме проверяемого
- Свой ETCP ID: `ETCP_ID_NAT_DETECTION` (0x02)
3. Отправляет `PING_REQ` через третий узел на IP:port линка проверяемого клиента
- Сам подписывается на conn_up/conn_down, сам принимает свои пакеты
4. По результату пинга: `NAT_TYPE_EIM` (если успех) или `NAT_TYPE_STRICT`
- При поднятии линка (INIT handshake) вызывается `nat_detection_link_ready()`
5. Результат сохраняется в `link->nat_type` и отправляется клиенту через `topo_group_send_nat_info`
- Ищет третий узел напрямую в `instance->connections`, обновляет `ETCP_SOCKET` и broadcast-ит NODEINFO через `topo_group_update_my_nodeinfo()`
6. Клиент обновляет свой `local_node` через `topo_group_handle_nat_info` и broadcast-ит изменения
Из topo_group в NAT-детекцию остался только делегат:
- `topo_group_set_nat_check_local(group, allow)` → вызывает `nat_detection_set_allow_local(instance->nat_det, allow)`
### 2.8. Широковещательная рассылка
### 2.8. Широковещательная рассылка
@ -98,26 +103,25 @@ struct TOPO_GROUPS* g = topo_groups_init(instance); // создаёт конт
- CHAT-группа ожидает флаг = 0 (без подсетей)
- CHAT-группа ожидает флаг = 0 (без подсетей)
- При несовпадении отправляется `TOPO_SUBCMD_ERR_GROUP_MISMATCH` и пакет игнорируется
- При несовпадении отправляется `TOPO_SUBCMD_ERR_GROUP_MISMATCH` и пакет игнорируется
### 2.10. Alien-узлы
Узлы, помеченные `alien=1`, не участвуют в обмене маршрутами: при `topo_group_new_conn` для alien-пира обмен пропускается.
## 3. API
## 3. API
### 3.1. Структуры
### 3.1. Структуры
| Структура | Назначение |
| Структура | Назначение |
|---|---|
|---|---|
| `TOPO_GROUPS` | Контейнер всех групп топологии экземпляра. Хранит `group_list` (ll_queue), memory_pool'ы для сериализации, sqlite3, callback `node_updated_cb` |
| `TOPO_GROUPS` | Контейнер всех групп топологии экземпляра. Хранит `group_list` (ll_queue), memory_pool'ы для сериализации (v4_sock_meta, v4_addr, v6_sock_meta, v6_addr, v4_subnet, v6_subnet), callback `node_updated_cb` |
| `TOPO_GROUP` | Одна группа топологии. `group_id`, `group_type`, `nodes` (ll_queue узлов), `senders_list` (ll_queue conn'ов), `local_node` (TOPO_NODEQ) |
| `TOPO_GROUP` | Одна группа топологии. `group_id`, `group_type`, `nodes` (ll_queue узлов), `senders_list` (ll_queue conn'ов), `local_node` (TOPO_NODEQ), `ed25519_public_key` (производный из X25519), `channel_id[64]` (для CHAT-групп) |
| `TOPO_GROUP_CONN_ITEM` | Элемент списка senders: conn + ll_entry — связка с senders_list |
| `TOPO_GROUP_CONN_ITEM` | Элемент списка senders: conn + ll_entry — связка с senders_list |
| `TOPO_NODE` | Идентичность узла: pubkeys, имя, версия (ver), списки адресов (v4/v6 sock_meta, addrs). Разделяется между группами через ref_count |
| `TOPO_NODEQ` | Запись в очереди группы: указатель на TOPO_NODE, пути (paths), hop_list, tranzit_data, subnets, connectivity, conn_mgr (тип + intermediaries), best_socket, dirty, last_ver |
| `TOPO_NODEPATH` | Путь до узла через конкретное ETCP_CONN: conn + hop_count |
| `PROBE_RESULT_UNKNOWN` | 0 | Результат проверки: неизвестно |
| `PROBE_RESULT_REACHABLE` | 1 | Результат проверки: доступен |
| `PROBE_RESULT_UNREACHABLE` | 2 | Результат проверки: недоступен |
### 3.3. Функции инициализации/завершения
### 3.3. Функции инициализации/завершения
| Функция | Назначение |
| Функция | Назначение |
|---|---|
|---|---|
| `topo_groups_init(instance)` | Создаёт TOPO_GROUPS, memory_pool'ы, открывает SQLite, создаёт utun-группу по умолчанию, регистрирует ETCP-коллбэки |
| `topo_groups_init(instance)` | Создаёт TOPO_GROUPS, memory_pool'ы, открывает SQLite (если db_path в конфиге), создаёт utun-группу по умолчанию, регистрирует ETCP-коллбэки |
| `topo_groups_destroy(instance)` | Освобождает все группы, memory_pool'ы, закрывает SQLite; снимает ETCP-регистрацию |
| `topo_groups_destroy(instance)` | Освобождает все группы, memory_pool'ы, закрывает SQLite, отменяет connectivity probes, снимает ETCP-регистрацию |
| `topo_group_create(instance, group_id, group_type)` | Создаёт TOPO_GROUP: nodes (hash queue), senders_list, local_node; вызывается из topo_groups_init / topo_groups_create_group |
| `topo_group_remove_conn(group, conn)` | Отменяет NAT check и ping pending, удаляет все пути через conn, удаляет недоступные узлы, broadcast withdraw, убирает conn из senders_list |
| `topo_group_remove_conn(group, conn)` | Удаляет все пути через conn, удаляет недоступные узлы (route_delete, cancel_connectivity, etcp_router_conn_close_all_for_node, broadcast withdraw), убирает conn из senders_list |
| `topo_group_etcp_conn_cbk(conn, arg)` | Callback при создании нового ETCP-соединения: подписывается на on_up/on_down через etcp_conn_add_up_cbk/down_cbk |
| `topo_group_etcp_conn_cbk(conn, arg)` | Callback при создании нового ETCP-соединения: подписывается на on_up/on_down через etcp_conn_add_up_cbk/down_cbk |
| `topo_group_on_conn_up(conn, arg)` | При on_up: вызывает topo_group_new_conn |
| `topo_group_on_conn_up(conn, arg)` | При on_up: вызывает topo_group_new_conn |
| `topo_group_on_conn_down(conn, arg)` | При on_down: вызывает topo_group_remove_conn |
| `topo_group_on_conn_down(conn, arg)` | При on_down: вызывает topo_group_remove_conn |
@ -161,41 +172,41 @@ struct TOPO_GROUPS* g = topo_groups_init(instance); // создаёт конт
| Функция | Назначение |
| Функция | Назначение |
|---|---|
|---|---|
| `topo_group_receive_cbk(from_conn, entry)` | Точка входа приёма пакетов топологии: диспетчеризация по subcmd (NODEINFO/WITHDRAW/REQUEST_TABLE/PING_REQ/PING_RESP/NAT_INFO/NAT_CHECK_REQ/TABLE_COMPLETE/ERR_GROUP_MISMATCH) |
| `topo_group_receive_cbk(from_conn, entry)` | Точка входа приёма пакетов топологии: работает только с default-группой, диспетчеризация по subcmd (NODEINFO/WITHDRAW/REQUEST_TABLE/TABLE_COMPLETE/ERR_GROUP_MISMATCH) |
| `topo_group_handle_nat_info(group, from_conn, data, len)` | Обработка NAT_INFO: обновляет nat_type в local_node (TOPO_SOCKMETA4), ETCP_SOCKET, при изменениях broadcast NODEINFO |
| `topo_group_handle_nat_check_req(group, from_conn, data, len)` | Обработка NAT_CHECK_REQ от клиента: находит линк и запускает NAT-проверку |
### 3.6. Функции поиска
### 3.6. Функции поиска
| Функция | Назначение |
| Функция | Назначение |
|---|---|
|---|---|
| `topo_group_find_conn_for_node(group, node_id)` | Поиск оптимального ETCP_CONN до узла: min hop_count, предпочтение live-путям |
| `topo_group_find_conn_for_node(group, node_id)` | Поиск оптимального ETCP_CONN до узла: min hop_count, предпочтение live-путям |
| `topo_group_find_third_node(group, exclude)` | Поиск произвольного conn'а (не exclude) для использования как посредника при NAT-детекции; исключает private/local conn'ы |
| `topo_node_find_by_id(group, node_id)` | Поиск TOPO_NODEQ в nodes по node_id через хеш-индекс |
| `topo_groups_find(g, group_id)` | Поиск группы по group_id |
### 3.7. Функции broadcast
### 3.7. Функции broadcast
| Функция | Назначение |
| Функция | Назначение |
|---|---|
|---|---|
| `topo_group_send_nodeinfo(group, node, conn)` | Сериализует TOPO_NODEQ и отправляет NODEINFO одному conn |
| `topo_group_send_nodeinfo(group, node, conn)` | Сериализует TOPO_NODEQ и отправляет NODEINFO одному conn |
| `topo_group_broadcast_withdraw(group, node_id, wd_source, exclude)` | Рассылает WITHDRAW всем conn в senders_list, кроме exclude |
| `topo_group_broadcast_withdraw(group, node_id, wd_source, exclude)` | Рассылает WITHDRAW всем conn в senders_list, кроме exclude |
| `topo_group_send_full_table(group, conn)` | Отправляет все известные узлы (кроме тех, чей путь включает target) указанному conn |
| `topo_group_send_full_table(group, conn)` | Отправляет все известные узлы (с hop_count > 0), кроме тех, чей путь включает target, указанному conn |
| `topo_group_send_table_request(group, conn)` | Отправляет запрос полной таблицы (TOPO_SUBCMD_REQUEST_TABLE) |
| `topo_group_send_table_request(group, conn)` | Отправляет запрос полной таблицы (TOPO_SUBCMD_REQUEST_TABLE) |
| `topo_group_send_table_complete(group, conn)` | Отправляет метку завершения синхронизации (TOPO_SUBCMD_TABLE_COMPLETE) |
| `topo_group_send_table_complete(group, conn)` | Отправляет метку завершения синхронизации (TOPO_SUBCMD_TABLE_COMPLETE) |
| `topo_group_send_err_group_mismatch(group, conn, expected_type, received_flags)` | Отправляет ошибку несоответствия типа группы |
| `topo_group_send_err_group_mismatch(group, conn, expected_type, received_flags)` | Отправляет ошибку несоответствия типа группы |
### 3.8. Функции NAT
### 3.8. Функции NAT (делегаты в nat_detection)
| Функция | Назначение |
| Функция | Назначение |
|---|---|
|---|---|
| `topo_group_send_nat_info(conn, socket_id, nat_ip, nat_port, nat_type)` | Отправляет клиенту информацию о его NAT (результат проверки) |
| `topo_group_set_nat_check_local(group, allow)` | Делегат в `nat_detection_set_allow_local(instance->nat_det, allow)` — разрешить/запретить NAT check для локальных подсетей (тесты) |
| `topo_group_send_nat_check_req(conn, socket_id)` | Отправляет серверу запрос на проверку NAT для указанного socket_id |
| `nat_detection_create(inst)` | Создаёт модуль NAT-детекции: etcp_bind на 0x02, подписка на conn_up/conn_down |
| `topo_group_start_link_nat_check(group, link)` | Запускает NAT-проверку для одного линка через третий узел; проверяет is_local_subnet, пропускает private/local линки |
| `topo_group_update_my_nodeinfo(instance, group)` | Собирает информацию о локальном узле из конфига и ключей: адреса сокетов, подсети, pubkeys, имя; обновляет group->local_node; вызывается при старте и при изменениях сокетов |
| `nat_link_check_cb(success, avg_rtt, count_sent, count_ok, arg)` | Callback завершения NAT-проверки: устанавливает nat_type линка и отправляет результат клиенту |
Точка входа для пакетов топологии — `etcp_bind(instance, ETCP_ID_TOPO_ENTRY, topo_group_receive_cbk)` в `topo_groups_init`. Единственный обработчик на весь ETCP ID 0x01. Диспетчеризация внутри по subcmd (byte data[1]).
Точка входа для пакетов топологии — `etcp_bind(instance, ETCP_ID_TOPO_ENTRY, topo_group_receive_cbk)` в `topo_groups_init`. Единственный обработчик на весь ETCP ID 0x01. Диспетчеризация внутри по subcmd (byte data[1]). Обработка всегда идёт через default-группу (TOPO_GROUP_UTUN).
Коллбэки on_up/on_down новых соединений регистрируются через `etcp_add_new_conn_cbk(instance, topo_group_etcp_conn_cbk, NULL)`, которая при создании каждого нового ETCP_CONN подписывается на его события.
Коллбэки on_up/on_down новых соединений регистрируются через `etcp_add_new_conn_cbk(instance, topo_group_etcp_conn_cbk, NULL)`, которая при создании каждого нового ETCP_CONN подписывается на его события.
- **Хранилище памяти**: В отличие от STCP, модуль не имеет отдельной БД. Использует внешний SQLite3 pointer (`topo_groups->topo_sqlite_db`), который может быть открыт самим модулем (если указан `db_path`) или передан из chatgui через `topo_groups_set_sqlite_db`.
- **Хранилище SQLite**: Открывается в `topo_groups_init` если в конфиге задан `db_path`. БД хранится как `instance->topo_sqlite_db` (sqlite3*), используется во всех группах. Файл: `{db_path}/chats.db`. Режим: WAL, foreign_keys=ON, synchronous=NORMAL.
- **Версионирование NODEINFO**: Версия (ver, uint8_t 1-255) сравнивается через циклическую арифметику `(int8_t)(cur_ver - new_ver) >= 0`. Версия 0 не используется (нет данных).
- **Версионирование NODEINFO**: Версия (ver, uint8_t 1-255) сравнивается через циклическую арифметику `(int8_t)(cur_ver - new_ver) >= 0`. Версия 0 не используется (нет данных). Если версия stale — обновляются только пути без замены данных узла.
- **Защита от петель**: NODEINFO рассылается только тем пирам, чей node_id отсутствует в hop_list. WITHDRAW broadcast всем кроме отправителя.
- **Защита от петель**: NODEINFO рассылается только тем пирам, чей node_id отсутствует во всех путях (hop_list). WITHDRAW broadcast всем кроме отправителя.
- **NAT check для локальных сетей**: По умолчанию запрещён (`allow_nat_check_local=0`), можно включить через `topo_group_set_nat_check_local(group, 1)` для тестов.
- **Связность узлов**: Для новых/обновлённых узлов с адресами автоматически запускается зондирование (`route_connectivity_probe_node`). При удалении узла (withdraw/remove_conn) пробы отменяются (`route_connectivity_cancel_node`).
- **Aliens**: Узлы с `alien=1` хранятся в nodes, имеют пути, но не инициируют обмен маршрутами при подключении (topo_group_new_conn пропускает).
- **Виртуальные каналы**: При удалении узла закрываются все виртуальные ETCP-каналы через `etcp_router_conn_close_all_for_node`.
- **Обновление при NAT-детекции**: При получении NAT_INFO, если изменился nat_type сокета с не-EIM на EIM (или наоборот) — обновляется `local_node`, увеличивается версия и broadcast-ится всем пирам.
- **Dirty-флаг**: При withdraw/remove_conn узлы помечаются `dirty = 1` перед удалением.
- **NAT check для локальных сетей**: По умолчанию запрещён (`allow_nat_check_local=0`), можно включить через `topo_group_set_nat_check_local(group, 1)` для тестов (делегирует в `nat_detection_set_allow_local`).
- **Conn_mgr поля**: `conn_mgr_type`, `conn_mgr_intermediaries[]`, `conn_mgr_intermediariy_count` — используются менеджером соединений для стратегии установки связи с узлом (direct/reverse/indirect).
- **Обновление local_node при NAT-детекции**: Модуль `nat_detection` после определения типа NAT вызывает `topo_group_update_my_nodeinfo()` для обновления local_node с новыми данными сокетов — это автоматически увеличивает версию, и NODEINFO broadcast-ится всем пирам через механизм изменения конфигурации сокетов.
@ -57,18 +57,17 @@ int topo_node_sqlite_init(sqlite3* db) {
"CREATE UNIQUE INDEX IF NOT EXISTS idx_na_unique ON node_addresses(node_id, family, socket_id, addr_type);"
"CREATE UNIQUE INDEX IF NOT EXISTS idx_na_unique ON node_addresses(node_id, family, socket_id, addr_type);"
"CREATE TABLE IF NOT EXISTS channels ("
"CREATE TABLE IF NOT EXISTS channels ("
" channel_id TEXT PRIMARY KEY,"
" channel_id TEXT PRIMARY KEY,"// ID канала
" name TEXT NOT NULL,"
" name TEXT NOT NULL,"// Название канала
" owner_node_id INTEGER,"
" owner_node_id INTEGER,"// node id создателя (надо выпилить)
" is_dm INTEGER DEFAULT 0,"
" x25519_pubkey BLOB NOT NULL,"// ключ для шифрования канала
" x25519_pubkey BLOB NOT NULL,"
" x25519_privkey BLOB,"// если админ - то ключ канала
" x25519_privkey BLOB,"
" ed25519_pubkey BLOB NOT NULL,"// ключ для проверки подписи
" ed25519_pubkey BLOB NOT NULL,"
" ed25519_privkey BLOB,"// ключ для создания подписи
" ed25519_privkey BLOB,"
" signature BLOB NOT NULL,"// подпись при создании канал приватным ключом канала channel_id(NUL-terminated) || name(NUL-terminated) || owner_node_id(8 байт, LE uint64) || x25519_pubkey(32 байта) || ed25519_pubkey(32 байта)
" signature BLOB NOT NULL,"
" last_read_msg_id INTEGER,"// для скроллинга чата
" last_read_msg_id INTEGER,"
" last_pos_msg_id INTEGER,"// для скроллинга чата
" last_pos_msg_id INTEGER,"
" created_at INTEGER DEFAULT (unixepoch())"// когда создан
" created_at INTEGER DEFAULT (unixepoch())"
");";
");";
char*err=NULL;
char*err=NULL;
@ -79,14 +78,6 @@ int topo_node_sqlite_init(sqlite3* db) {
return-1;
return-1;
}
}
/* migration: add socket_id column if not exists (ignore error for existing DBs) */
" userinfo TEXT NOT NULL DEFAULT '',"// имя/метаданные узла в канале (json_flat style)
" creator_sig BLOB,"
" creator_sig BLOB,"// валидация мембера админом канала
" comment TEXT,"
" adm_tags TEXT,"// тэги которые может менять админ (json_flat style)
" joined_at INTEGER DEFAULT (unixepoch()),"
" adm_tags_sig BLOB,"// подпись тэгов adm_tags (может быть подписана ключом суперадмина или админов - проверяем перебором)
" node_type INTEGER NOT NULL,"// ENUM(0-'PRIV',1-'NAT',2-'EIM-NAT',3-'PUBLIC',4-SUPERNODE) тип ноды - private (только нода подключается), nat (односторонние подключения), eim-nat (доступны подключения но надо запрашивать ip), public - на прямых ip (но может быть недоступна в чебурнетах), supernode - на прямых ip, рекомендуемая для подключения
" PRIMARY KEY (node_id))",peers_tbl);
" PRIMARY KEY (node_id))",peers_tbl);
char*err=NULL;
char*err=NULL;
sqlite3_exec(db,sql,NULL,NULL,&err);
sqlite3_exec(db,sql,NULL,NULL,&err);
@ -262,20 +254,19 @@ int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
sqlite3_stmt*stmt=NULL;
sqlite3_stmt*stmt=NULL;
if(sqlite3_prepare_v2(db,
if(sqlite3_prepare_v2(db,
"INSERT OR REPLACE INTO channels(channel_id, name, owner_node_id, is_dm,"
"INSERT OR REPLACE INTO channels(channel_id, name, owner_node_id,"
virtual void sound2() = 0;// если =0 - метод обязательно должен быть реализован в наследнике, а сам класс становится абстрактным и его экземпляры создавать нельзя.
Animal() {// конструктор - совпадает с именем класса
cout << "Created";
}
~Animal() {// деструктор
cout << "Deleted";
}
};
class Dog : public Animal {// наследование
public:
void sound() override {}// override — говорит компилятору, что метод действительно переопределяет базовый.
};
Стратегия обмена
узлы которые online живут только в пемяти. и синхронизируемся с ними используя topo_group.
routing layer:
- topo_group - обеспечивает корректное построение оптимальной таблицы роутинга (per group) между узлами в рамках установленных подключений. И корректировку этой таблицы при перестроении подключений.
- topo_group_discovery - обеспечивает оптимизацию подключений, а именно:
- периодически пингует узлы проверяя их доступность
для каждой группы админ назначает суперузлы: a b c ... стать усуперузлом - получить разрешение с админской подписью.
суперузел активирует bgp обмен с остаьлными суперузлами.
как:
суперузел - это по сути сервер для группы. который также синхронизируется с другими суперузлами
клиенты приоритетно подключаются к суперузлам:
- подключаются к кому-то
- запрашивают таблицу маршрутизации
1. Узлы за nat сами выбирают подходящие для себя точки подключения к сети.
2 шт с минимальным rtt
2 шт с минимальной загруженностью
в чате (gui) можно выбрать предпочитаемые узлы для подключения
2. узлы с eim nat
??? если не хватает узлов прямым адресом
3. узлы с прямыми ип
суть - выстраивают линки между собой для надежного обмена конфигурацией сети
как:
- в таблице узлов для каждой группы
У каждого узла проставляется доступность (можем ли мы каким-либо образом подключиться): acessible, reverse (при подключении с другой стороны), no
Единое обновление инфы об узле (per-group):
- обновляем тип узла в каждой группе где есть узел при обовлении типа нат узла. прямая доступность узла: yes/no.
=======================================
функционал группы.
Есть суперадмины группы - владеют приватным ключом суперадмина (один на группу).
Есть админы - владеют сгенерированным приватным ключом админа и подписанным суперадмином.
суперадмины могут делать revoke админу.
админские действия также распространяются по чату как и обычные сообщения.
ид группы = пубкей группы
юзер - join по ссылке (приватный ключ пира). получает ключи других пиров. Может только читать.
админ подписывает разрешение на писать (как и другие разрешения). подпись храним в таблице юзеров