Browse Source

docs: refresh development guides for current architecture

proxy
evgeny 3 days ago
parent
commit
904a9fbda1
  1. 208
      AGENTS.md
  2. 90
      tools/chatgui-android/AGENTS.md

208
AGENTS.md

@ -34,10 +34,10 @@ This file contains essential information for AI coding agents working in the uTu
## Quick Reference ## Quick Reference
**Repository:** uTun - Secure VPN tunnel with ETCP protocol **Repository:** uTun — общее сетевое ядро ETCP, независимо запускаемые UTUN и P2P-чат
**Language:** C (C99) **Language:** C (C99)
**Build System:** GNU Autotools (autoconf/automake) **Build System:** GNU Autotools (autoconf/automake)
**Cryptography:** OpenSSL (AES-CCM, X25519, SHA256) **Cryptography:** OpenSSL (AES-CCM, X25519, Ed25519, SHA256)
## Build Commands ## Build Commands
@ -68,9 +68,10 @@ make distclean # Clean everything including configure files
### Partial Builds ### Partial Builds
```bash ```bash
cd lib && make # Build only the library (libuasync.a) make -C lib # базовые библиотеки
cd src && make # Build only the main program make -C lib/libopus # встроенный Opus
cd tests && make # Build only tests make -C src # основной бинарник src/utun (библиотеки уже должны быть собраны)
make -C tests # тесты (используют объекты src/)
``` ```
### Direct Build (Windows, без autotools) ### Direct Build (Windows, без autotools)
@ -86,7 +87,7 @@ python3 tools/chatcli members <ch_id> # мемберы с полн
python3 tools/chatcli messages <ch_id> [count] # последние сообщения python3 tools/chatcli messages <ch_id> [count] # последние сообщения
python3 tools/chatcli send <ch_id> "text" # отправить сообщение python3 tools/chatcli send <ch_id> "text" # отправить сообщение
python3 tools/chatcli invite <ch_id> # создать invite-ссылку python3 tools/chatcli invite <ch_id> # создать invite-ссылку
python3 tools/chatcli connect <utun://...> # join по ссылке python3 tools/chatcli connect 'utun://...' # join по ссылке
python3 tools/chatcli create "Name" # создать канал python3 tools/chatcli create "Name" # создать канал
python3 tools/chatcli listen # слушать события (Ctrl+C выход) python3 tools/chatcli listen # слушать события (Ctrl+C выход)
``` ```
@ -94,13 +95,14 @@ python3 tools/chatcli listen # слушать событи
### ASAN Build (AddressSanitizer, Linux) ### ASAN Build (AddressSanitizer, Linux)
```bash ```bash
./build.sh --asan -j4 # lib/ + src/ only (tests not ASAN-compatible) ./build.sh --asan -j4 # собирает lib/ + src/; тесты этот режим скрипта пропускает
``` ```
Запуск с ASAN (detect_leaks отключены чтобы не спамить при shutdown): Запуск с ASAN (detect_leaks отключены чтобы не спамить при shutdown):
```bash ```bash
ASAN_OPTIONS=detect_leaks=0:halt_on_error=0 ./src/utun -f -p /tmp/utun.pid -l /tmp/utun.log ASAN_OPTIONS=detect_leaks=0:halt_on_error=0:log_path=/tmp/utun_asan ./src/utun -f -p /tmp/utun.pid -l /tmp/utun.log
``` ```
Краш-логи ASAN пишутся в `/tmp/utun_asan.<pid>`. В этом примере отчёты ASAN пишутся в `/tmp/utun_asan.<pid>` благодаря `log_path`.
Для отдельного теста нужно собирать его зависимости с теми же sanitizer-флагами; обычные и ASAN-объекты не смешивать.
## Test Commands ## Test Commands
@ -118,13 +120,13 @@ cd tests/
./test_etcp_two_instances ./test_etcp_two_instances
``` ```
### Run Single Test with Debug Info ### Build and Run a Single Test
```bash ```bash
cd tests/ make -C tests test_services
gcc -I../src -I../lib -I../tinycrypt/lib/include \ cd tests && ./test_services
-o my_test test_file.c ../src/*.c ../lib/*.c ../tinycrypt/lib/source/*.c
./my_test
``` ```
Использовать цель из `tests/Makefile.am`: ручная компиляция `src/*.c` пропускает подкаталоги и добавляет лишний `main`.
Уровни и категории диагностики настраиваются в самом тесте через `debug_set_level` / `debug_set_category_level`.
## Code Style Guidelines ## Code Style Guidelines
@ -137,7 +139,7 @@ gcc -I../src -I../lib -I../tinycrypt/lib/include \
### Formatting ### Formatting
- **Indentation:** 4 spaces, no tabs - **Indentation:** 4 spaces, no tabs
- **Braces:** Same line for functions, new line for control structures: - **Braces:** Открывающая скобка на строке функции или условия:
```c ```c
int function(void) { int function(void) {
if (condition) { if (condition) {
@ -145,7 +147,7 @@ gcc -I../src -I../lib -I../tinycrypt/lib/include \
} }
} }
``` ```
- **Comments:** Primary language is Russian for business logic, English for API docs - **Comments:** Краткие описания на русском; сохранять принятые имена API и протокольных полей.
- **Line Length:** Aim for 80-100 characters, but can go up to 150 if logically coherent - **Line Length:** Aim for 80-100 characters, but can go up to 150 if logically coherent
### Include Order ### Include Order
@ -201,7 +203,7 @@ sc_context_t ctx;
sc_init_ctx(&ctx, &my_keys); sc_init_ctx(&ctx, &my_keys);
// 2. Set peer public key (for key exchange) // 2. Set peer public key (for key exchange)
sc_set_peer_public_key(&ctx, peer_public_key, SC_PEER_PUBKEY_HEX); // 0=bin, 1=hex sc_set_peer_public_key(&ctx, peer_public_key_bin, SC_PEER_PUBKEY_BIN); // 32 бинарных байта; HEX — для hex-строки
// 3. Ready for encrypt/decrypt // 3. Ready for encrypt/decrypt
sc_encrypt(&ctx, plaintext, plaintext_len, ciphertext, &ciphertext_len); sc_encrypt(&ctx, plaintext, plaintext_len, ciphertext, &ciphertext_len);
@ -227,40 +229,61 @@ debug - отладка: всё что нужно для понимание су
info - сообщения для пользователя о работе. мы должны видеть в читаемом виде понятные и осмысленные сообщения о каких-либо значимых действиях с точки зрения логики работы модуля или приложения info - сообщения для пользователя о работе. мы должны видеть в читаемом виде понятные и осмысленные сообщения о каких-либо значимых действиях с точки зрения логики работы модуля или приложения
warn / error - ошибки и предупреждения (аномалии). должны быть во всех ошибочных ветках. Молча вываливаться с ошибкой нельзя, все ошибки и предупреждения должны логироваться. warn / error - ошибки и предупреждения (аномалии). должны быть во всех ошибочных ветках. Молча вываливаться с ошибкой нельзя, все ошибки и предупреждения должны логироваться.
### Debug Categories (28 категорий) ### Debug Categories
``` Актуальные имена и константы — в `lib/debug_config.h`, текстовые имена — в `lib/debug_config.c`.
NONE=0, UASYNC=1, LL_QUEUE=2, CONNECTION=3, ETCP=4, CRYPTO=5, MEMORY=6, Основные: `sys`, `connection`, `etcp`, `crypto`, `config`, `tun`, `routing`, `timers`, `bgp`,
TIMING=7, CONFIG=8, TUN=9, ROUTING=10, TIMERS=11, NORMALIZER=12, BGP=13, `socket`, `control`, `dump`, `traffic`, `debug`, `general`, `nat`, `keepalive`, `etcp_route`,
SOCKET=14, CONTROL=15, DUMP=16, TRAFFIC=17, DEBUG=18, GENERAL=19, NAT=20, `media`, `etcp_dump`, `chat`, `chat_sync`, `member_sync`, `proxy`, `video`, `reality`, `dm`, `call`, `radio`.
KEEPALIVE=21, ETCPROUTE=22, BBR=23, ETCP_DUMP=24, CONNECTIVITY=25, DB_SYNC=26, UASYNC/LL_QUEUE/MEMORY/TIMING объединены в SYS, NORMALIZER/BBR — в ETCP; старые числовые списки не использовать.
MEMBER_SYNC=27
```
### Настройка отладки ### Настройка отладки
- В конфиге: `debug = etcp=trace,config=info` (формат: `категория=уровень,...`) - В INI-конфиге: секция `[debug]`, каждая категория отдельной строкой (`etcp=trace`, `config=info`).
- Строку `etcp=trace,config=info` принимает `debug_parse_config()`; GUI хранит её в `[gui] debug_categories`.
- В коде: глобальный уровень и per-category уровни из `debug_config_t g_debug_config` - В коде: глобальный уровень и per-category уровни из `debug_config_t g_debug_config`
- Макросы: `DEBUG_ERROR(cat,fmt,...)` `DEBUG_WARN` `DEBUG_INFO` `DEBUG_DEBUG` `DEBUG_TRACE` - Макросы: `DEBUG_ERROR(cat,fmt,...)` `DEBUG_WARN` `DEBUG_INFO` `DEBUG_DEBUG` `DEBUG_TRACE`
- `log_dump(prefix, data, len)` — hex dump в лог - `log_dump(level, category, prefix, data, len)` — hex dump в лог
### Dual Output ### Dual Output
- Консоль и файл настраиваются раздельно (`debug_set_console_level`, `debug_set_file_level`) - Фильтр уровней общий для выходов; `debug_enable_console()` включает/выключает консоль.
- `debug_enable_file_output(path, truncate)` / `debug_disable_file_output()` - `debug_enable_file_output(path, truncate)` / `debug_disable_file_output()`
## Architecture ## Architecture
### Ядро, сервисы и владение ресурсами
- `utun_instance_create*()` создаёт ядро; `utun_core_start()` запускает общие сетевые службы.
- `utun_service_start/stop()` управляет UTUN-группой, TUN/NAT и запросами к пирам из конфига.
- `chat_service_start/stop()` управляет чатом и CHAT-группами. Чат не требует UTUN; desktop и Android запускают ядро и чат явно.
- Ядро владеет общей SQLite (`db_path/chats.db`, без пути — `:memory:`), идентичностью, транспортом и маршрутизатором.
Остановка сервиса сохраняет БД и ресурсы другого сервиса. `utun_instance_destroy()` освобождает ядро, но не переданный `UASYNC`.
- Группа владеет NCD handle с начала CONNECTING. Инициатор хранит отменяемый `TOPO_PEER_REQUEST`;
закрытие своего запроса не разрывает транспорт других владельцев. Готовая сессия сохраняется у группы.
- UP означает работоспособный транспорт. READY означает завершённое согласование и обмен таблицей конкретной группы.
Recovery ждёт нужных маршрутов через READY-пиров; наличие `ETCP_CONN*` само по себе не гарантирует UP.
- JOIN добавляет подписанного мембера, Merkle распространяет запись. Доступ к CHAT-группе каждый узел даёт по своей таблице участников;
invite-ключ не даёт временного членства. Протокол описан в `src/chat/chat_join.h`, групповое согласование — в `src/routing_layer/topo_group.h`.
- `TOPO_NODE` — общая подписанная запись узла. Более свежий timestamp заменяет запись целиком, с полями и подписью;
адреса не версионируются отдельно. BGP обновляет запись и передаёт изменения NCD (см. `doc/node_snapshot.md`).
Все операции с ядром выполняются в его uasync-потоке; stop/destroy — вне callbacks останавливаемых сервисов.
Порядок освобождения ресурсов и нюансы media workers: `doc/service_lifecycle.md`.
### Directory Structure ### Directory Structure
``` ```
├── lib/ # Core libraries (18 .c + 20 .h + libopus/liblmdb) ├── lib/ # Core libraries, SQLite, libopus/liblmdb
├── src/ # Main source code ├── src/ # Main source code
│ ├── transport_layer/ # ETCP stack, crypto, STCP, normalizer, BBR (~30 файлов) │ ├── transport_layer/ # ETCP, crypto, STCP, normalizer, NCD, BBR
│ ├── routing_layer/ # Routing, BGP, conn_mgr, etcp_router, NAT detection (~20 файлов) │ ├── routing_layer/ # Routing, группы/BGP, recovery, conn_mgr, etcp_router
│ ├── chat/ # P2P чат, db_sync, merkle_sync, member_sync (17 файлов) │ ├── chat/ # P2P чат, join, db_sync, merkle_sync, member_sync
│ ├── proxy/ # SOCKS5, TCP/UDP/ICMP прокси (10 файлов) │ ├── dm/ # Личные сообщения и mailbox
│ ├── lwip_tcp/ # Встроенный lwIP TCP стек (7 файлов) │ ├── call/ # Звонки и общий голосовой стек
│ ├── media_delivery/ # Доставка медиафайлов (6 файлов) │ ├── radio/ # Групповая PTT-рация
│ ├── media_async/ # Асинхронный движок медиа (2 файла) │ ├── proxy/ # SOCKS5, TCP/UDP/ICMP прокси
│ └── *.c/h # Корневые модули: utun, config, TUN, firewall, NAT, NTP, control (~14 файлов) │ ├── lwip_tcp/ # Встроенный lwIP TCP стек
├── tests/ # ~70 тестов, 64 в check_PROGRAMS │ ├── media_delivery/ # Доставка медиафайлов
│ ├── media_async/ # Фоновые задачи медиа
│ └── *.c/h # utun, config, TUN, firewall, NAT, NTP, control
├── tests/ # Состав тестов и цели запуска: tests/Makefile.am
├── doc/ # Technical Specifications ├── doc/ # Technical Specifications
├── tools/ # Auxiliary tools ├── tools/ # Auxiliary tools
│ ├── etcpmon/ # GUI монитор ETCP │ ├── etcpmon/ # GUI монитор ETCP
@ -278,7 +301,7 @@ MEMBER_SYNC=27
**Core (src/)** **Core (src/)**
- `utun.c` - Main program entry point, CLI parsing, daemon mode - `utun.c` - Main program entry point, CLI parsing, daemon mode
- `utun_instance.c/h` - Root instance lifecycle, config loading, all submodule init - `utun_instance.c/h` - Создание ядра и независимый жизненный цикл UTUN/чата, владение общими ресурсами
- `tun_if.c/h` - TUN interface API (init/write/close, cross-platform) - `tun_if.c/h` - TUN interface API (init/write/close, cross-platform)
- `tun_linux.c` `tun_freebsd.c` `tun_windows.c` - Platform-specific TUN implementations - `tun_linux.c` `tun_freebsd.c` `tun_windows.c` - Platform-specific TUN implementations
- `tun_route.c/h` - TUN routing table sync - `tun_route.c/h` - TUN routing table sync
@ -314,7 +337,7 @@ MEMBER_SYNC=27
- `stcp_server.c/h` - STCP сервер - `stcp_server.c/h` - STCP сервер
- `stcp_client.c/h` - STCP клиент - `stcp_client.c/h` - STCP клиент
- `stcp_link.c/h` - STCP линк-уровень - `stcp_link.c/h` - STCP линк-уровень
- `node_conn_direct.c/h` - Direct config-based connections - `node_conn_direct.c/h` - Общий прямой транспорт к пиру с отдельным handle каждого владельца; обновление линков по адресам узла
- `socket_monitor.c/h` - Socket state monitoring - `socket_monitor.c/h` - Socket state monitoring
- `reality.c/h` - REALITY-style TLS ClientHello/ServerHello камуфляж для STCP - `reality.c/h` - REALITY-style TLS ClientHello/ServerHello камуфляж для STCP
- `reality_fingerprint.c/h` - Статические отпечатки (cipher suites, groups, ALPN) для REALITY-камуфляжа - `reality_fingerprint.c/h` - Статические отпечатки (cipher suites, groups, ALPN) для REALITY-камуфляжа
@ -329,28 +352,30 @@ MEMBER_SYNC=27
- `route6_lib.c/h` - IPv6 routing - `route6_lib.c/h` - IPv6 routing
- `route_ping.c/h` - Route ping probing (NAT check, liveness) - `route_ping.c/h` - Route ping probing (NAT check, liveness)
- `route_connectivity.c/h` - Route connectivity checks - `route_connectivity.c/h` - Route connectivity checks
- `topo_group.c/h` - BGP-like route exchange between nodes (NODEINFO/WITHDRAW, изолированные группы UTUN/CHAT) - `topo_group.c/h` - Сессии UTUN/CHAT (JOIN/ACCEPT, эпохи, READY), групповые запросы, NODEINFO/WITHDRAW и владение NCD
- `topo_group_connect.c/h` - Авто-подключение к узлам CHAT-группы (3 фазы, бесконечный цикл) - `topo_group_connect.c/h` - Подбор пиров CHAT-группы: исторические → суперузлы/публичные → локальные; отменяемые запросы до READY
- `topo_group_invite.c/h` - Invite/join канала через прямое ncd-подключение (INVITE_INFO_REQ/RESP) - `topo_group_invite.c/h` - Получение описания канала через INVITE_INFO_REQ/RESP; добавление мембера реализовано в chat_join/chat_sync
- `topo_node.c/h` - Node management (модель узла: TOPO_NODE/TOPO_GROUP_NODE, сериализация, node_registry) - `topo_node.c/h` - Node management (модель узла: TOPO_NODE/TOPO_GROUP_NODE, сериализация, node_registry)
- `topo_node_sqlite.c/h` - SQLite persistence for nodes - `topo_node_sqlite.c/h` - SQLite persistence for nodes
- `topo_recovery.c/h` - Восстановление каскадно отвалившихся узлов после разрыва соединения - `topo_recovery.c/h` - Восстановление потерянных маршрутов группы через READY-сессии, отмена попыток при stop
- `conn_mgr.h` + `conn_mgr_core.c`/`conn_mgr_indirect.c`/`conn_mgr_monitor.c` + `conn_mgr_priv.h` — Connection Manager (handle-based API, 3-phase DIR/REV/IND) - `conn_mgr.h` + `conn_mgr_core.c`/`conn_mgr_indirect.c`/`conn_mgr_monitor.c` + `conn_mgr_priv.h` — Connection Manager (handle-based API, 3-phase DIR/REV/IND)
- `etcp_router.c/h` - ETCP router/multiplexer (мультиплексирование каналов, transit forwarding) - `etcp_router.c/h` - ETCP router/multiplexer (мультиплексирование каналов, transit forwarding)
- `nat_detection.c/h` - NAT type detection - `nat_detection.c/h` - NAT type detection
- `route_crypto.c/h` - Пред/пост-обработка SVC_ROUTE пакетов (encrypt-then-sign) - `route_crypto.c/h` - Пред/пост-обработка SVC_ROUTE пакетов (encrypt-then-sign)
**Chat (src/chat/)** — децентрализованный P2P чат: сообщения и участники автоматически синхронизируются между всеми узлами канала без центрального сервера. **Chat (src/chat/)** — децентрализованный P2P чат: сообщения и участники автоматически синхронизируются между всеми узлами канала без центрального сервера.
- `chat_core.c/h` - Главный модуль чата. Единственная точка входа из GUI: принять сообщение, создать канал, изменить настройку. Управляет БД и жизненным циклом всех chat-модулей - `chat_core.c/h` - API сообщений, каналов, профиля и настроек; chat_service_start/stop управляют чат-сервисом поверх общей БД ядра
- `chat_core_priv.h` - Внутренний API для частей chat_core: общий контекст и утилиты БД. Снаружи не используется - `chat_core_priv.h` - Внутренний API для частей chat_core: общий контекст и утилиты БД. Снаружи не используется
- `chat_sync.c/h` - Связывает чат с ETCP-сетью: отслеживает появление/разрыв соединений, обновляет онлайн-статус узлов, запускает синхронизацию участников каналов, обрабатывает приглашения - `chat_sync.c/h` - Связывает чат с ETCP-сетью: отслеживает появление/разрыв соединений, обновляет онлайн-статус узлов, запускает синхронизацию участников каналов, обрабатывает приглашения
- `chat_event.c/h` - Доставка событий из ядра чата в GUI. Единый механизм: любой модуль отправляет событие (новое сообщение, смена участников, статус), GUI получает через один обработчик - `chat_event.c/h` - Доставка событий из ядра чата в GUI. Единый механизм: любой модуль отправляет событие (новое сообщение, смена участников, статус), GUI получает через один обработчик
- `chat_setting.c/h` - Настройки чата: проверяет корректность значений, хранит текущие. Используется и headless-парсером конфига, и GUI. Не зависит от других модулей - `chat_setting.c/h` - Проверка и хранение настроек чата per-instance; общая логика для конфигурации и GUI
- `db_sync.c/h` - Автоматическая репликация данных между подключёнными узлами. Запись на одном узле — появляется у всех остальных. Криптоподписи и цепочка хешей защищают от подделок - `chat_join.c/h` - Регистрация invite-ключа с ACK, пересылка запроса инвайтеру и добавление подписанного мембера; контракт join в заголовке
- `db_sync.c/h` - Репликация подписанных записей SQLite через прямые ETCP-соединения; расхождения по цепочке хешей, новые записи через PUSH
- `member_sync.c/h` - Синхронизация участников каналов поверх merkle_sync. Два подписанных блока (мембер/владелец), по-блочное сравнение версий, верификация подписей. Удаление — только битая запись - `member_sync.c/h` - Синхронизация участников каналов поверх merkle_sync. Два подписанных блока (мембер/владелец), по-блочное сравнение версий, верификация подписей. Удаление — только битая запись
- `merkle_sync.c/h` - Универсальный движок синхронизации на Merkle-деревьях (5 уровней × 32 бакета, SHA256). Пиры обмениваются хешами и передают только различия; per-session out-очередь с backpressure. Не привязан к конкретному типу данных (коллбэки `data_ops`) - `merkle_sync.c/h` - Универсальный движок синхронизации на Merkle-деревьях (5 уровней × 32 бакета, SHA256). Пиры обмениваются хешами и передают только различия; per-session out-очередь с backpressure. Не привязан к конкретному типу данных (коллбэки `data_ops`)
- `merkle_tree.c/h` - Производный индекс Merkle-хешей в SQLite; восстанавливается из данных модели, обновляется с ними в одной транзакции
- `chat_profile.c` - Собственный профиль: имя узла, сетевые адреса, сохранение UI-состояния (часть chat_core) - `chat_profile.c` - Собственный профиль: имя узла, сетевые адреса, сохранение UI-состояния (часть chat_core)
- `chat_channel.c` - Создание и настройка каналов: готовит таблицы в БД, генерирует криптоключи, запускает подключение ко всем участникам (часть chat_core) - `chat_channel.c` - Создание и настройка каналов: таблицы, криптоключи, CHAT-группа и планировщик подключения (часть chat_core)
- `chat_msg.c` - Отправка и приём сообщений: запись в локальную БД, автоматическая рассылка всем участникам канала (часть chat_core) - `chat_msg.c` - Отправка и приём сообщений: запись в локальную БД, автоматическая рассылка всем участникам канала (часть chat_core)
- `chat_status.c` - Сбор диагностики: текущее время, активные соединения, типы NAT. Отправляется в GUI (часть chat_core) - `chat_status.c` - Сбор диагностики: текущее время, активные соединения, типы NAT. Отправляется в GUI (часть chat_core)
- `chat_member.c/h` - Единая структура мембера для отображения в GUI (десктоп/headless/Android), фиксированная сериализация на проводе - `chat_member.c/h` - Единая структура мембера для отображения в GUI (десктоп/headless/Android), фиксированная сериализация на проводе
@ -358,7 +383,7 @@ MEMBER_SYNC=27
- `chat_whisper.c/h` - Whisper speech-to-text транскрипция голосовых сообщений (опционально, асинхронно через media_async) - `chat_whisper.c/h` - Whisper speech-to-text транскрипция голосовых сообщений (опционально, асинхронно через media_async)
- `chat_headless_control.c/h` - TCP control-socket для headless chat CLI (JSON line protocol) - `chat_headless_control.c/h` - TCP control-socket для headless chat CLI (JSON line protocol)
- `invite_build.c/h` - Сборка invite-ссылок utun:// (выбор лучшего узла + адреса) - `invite_build.c/h` - Сборка invite-ссылок utun:// (выбор лучшего узла + адреса)
- `invite_link.c/h` - Формат invite-ссылок utun:// для каналов (base64: version|password|channel_id|pubkey|addrs) - `invite_link.c/h` - Кодирование utun://: версия, пароль, channel_id, join_key, Reality-параметры, ключ и адреса узла
**Прокси (src/proxy/)** **Прокси (src/proxy/)**
- `socks_proxy.c/h` - SOCKS5 прокси - `socks_proxy.c/h` - SOCKS5 прокси
@ -379,11 +404,11 @@ MEMBER_SYNC=27
- `media_index.c/h` - Индексация медиафайлов - `media_index.c/h` - Индексация медиафайлов
**Media Async (src/media_async/)** **Media Async (src/media_async/)**
- `media_async.c/h` - Асинхронный движок (thread-per-task для crypto/file операций) - `media_async.c/h` - Фоновые crypto/file-задачи: work в pthread, done в uasync; destroy ждёт workers и завершает ожидающие callbacks с CANCELLED
**Libraries (lib/)** **Libraries (lib/)**
- `u_async.c/h` - Async event loop (epoll/poll/select, timers via timeout_heap) - `u_async.c/h` - Async event loop (epoll/poll/select, timers via timeout_heap)
- `ll_queue.c/h` - Lock-free linked list queue with callbacks, hash index, threshold waiter - `ll_queue.c/h` - Двусвязная очередь одного uasync-потока с callbacks, хеш-индексом и ожиданием свободного места
- `memory_pool.c/h` - Fast object pool allocator (pre-allocated blocks) - `memory_pool.c/h` - Fast object pool allocator (pre-allocated blocks)
- `debug_config.c/h` - Debug logging system (levels, categories, dual output, runtime config) - `debug_config.c/h` - Debug logging system (levels, categories, dual output, runtime config)
- `timeout_heap.c/h` - Min-heap for timer management (used by u_async) - `timeout_heap.c/h` - Min-heap for timer management (used by u_async)
@ -416,7 +441,7 @@ MEMBER_SYNC=27
### Key Components ### Key Components
- **UASYNC:** One per thread. Async event loop (epoll/poll), timers via timeout_heap - **UASYNC:** One per thread. Async event loop (epoll/poll), timers via timeout_heap
- **LL_QUEUE:** Lock-free queue with auto-callback, hash index lookup, threshold waiter - **LL_QUEUE:** Очередь с auto-callback, хеш-индексом и threshold waiter; не средство обмена между потоками
- **Memory Pool:** Fast allocation for hot-path objects (packets, inflight entries, fragments) - **Memory Pool:** Fast allocation for hot-path objects (packets, inflight entries, fragments)
- **ETCP:** TCP-like reliable protocol with encryption, multi-link, load balancing - **ETCP:** TCP-like reliable protocol with encryption, multi-link, load balancing
- **Secure Channel:** AES-CCM + X25519 key exchange, nonce-based encryption, pubkey obfuscation - **Secure Channel:** AES-CCM + X25519 key exchange, nonce-based encryption, pubkey obfuscation
@ -432,6 +457,8 @@ MEMBER_SYNC=27
- Очереди забивать нельзя. Добавляй следующий элемент только когда очередь стала пустой. - Очереди забивать нельзя. Добавляй следующий элемент только когда очередь стала пустой.
- Порог задаётся через `queue_set_threshold(q, max_packets, max_bytes)`. - Порог задаётся через `queue_set_threshold(q, max_packets, max_bytes)`.
- Используй `queue_waiter_wait` для ожидания освобождения очереди до заданного порога. - Используй `queue_waiter_wait` для ожидания освобождения очереди до заданного порога.
- Handle ожидания обнуляется целиком, живёт до callback/отмены и отменяется до освобождения владельца.
Callback может быть синхронным. `queue_entry_free` не освобождает dgram — его освобождают отдельно.
### Чтение из очереди ### Чтение из очереди
- Используй `queue_set_callback`: при вызове callback обработай один или несколько элементов, потом вызови `queue_resume_callback`. - Используй `queue_set_callback`: при вызове callback обработай один или несколько элементов, потом вызови `queue_resume_callback`.
@ -451,7 +478,8 @@ MEMBER_SYNC=27
## Config Rules ## Config Rules
- В серверном конфиге только собственные ключи и нет секций `[client]` - В серверном конфиге только собственные ключи и нет секций `[client]`
- В клиентском конфиге есть собственные ключи и pubkey каждого сервера в секции `[client]` - В клиентском конфиге есть собственные ключи и pubkey каждого сервера в секции `[client]`
- Chat-настройки хранятся в секции `[chatserver]` (принимается также `[chat]`). Парсер вызывает `chat_setting_set(key, value)` для каждого ключа — неизвестные ключи вызывают ошибку. Пример: - Chat-настройки хранятся в `[chatserver]` (также `[chat]`). Парсер обрабатывает общие поля секции,
затем вызывает `chat_setting_set_state(&cfg->global.chat_settings, key, value)`; неизвестные ключи логируются как ошибка. Пример:
```ini ```ini
[chatserver] [chatserver]
storage_autoload=1 storage_autoload=1
@ -474,7 +502,8 @@ MEMBER_SYNC=27
Если видишь спам-логи - подумай как их выборочно отключить чтобы не мешали. Если видишь спам-логи - подумай как их выборочно отключить чтобы не мешали.
Для отладки добавляй в DEBUG_CATEGORY_DEBUG диагностические сообщения где надо. И включи эту категорию в настройках. Убирай только после проверки (путём запуска) когда все ошибки устранены. Для отладки добавляй в DEBUG_CATEGORY_DEBUG диагностические сообщения где надо. И включи эту категорию в настройках. Убирай только после проверки (путём запуска) когда все ошибки устранены.
сообщение выводится по или - либо debug_set_level(DEBUG_LEVEL_TRACE) - выводится ВСЁ независимо от настроек по категориям. Тоесть берется max(global level, category lavel) Явный уровень категории заменяет глобальный. DEBUG_LEVEL_NONE наследует глобальный уровень;
DEBUG_LEVEL_DISABLED полностью отключает категорию, в том числе при глобальном TRACE (см. debug_should_output).
Твой бич - ты постоянно гадаешь и анализируешь код. Что приводит к снежному кобу ошибок и неверных гипотез. 10 раз повторяю - только логи логи логи и никакого гадания. Лоооги!!! правильные логи покажут всё с предельной точностью. Вся суть отладки - информативные логи Твой бич - ты постоянно гадаешь и анализируешь код. Что приводит к снежному кобу ошибок и неверных гипотез. 10 раз повторяю - только логи логи логи и никакого гадания. Лоооги!!! правильные логи покажут всё с предельной точностью. Вся суть отладки - информативные логи
И смотри логи. не задавливай их grep-ом. лучше больше. единственное с чем борись - это бесполезные спам логи. И смотри логи. не задавливай их grep-ом. лучше больше. единственное с чем борись - это бесполезные спам логи.
@ -484,7 +513,8 @@ MEMBER_SYNC=27
Но полезные смотри всегда, и всегда оставляй логи которые выводятся нечасто. Но полезные смотри всегда, и всегда оставляй логи которые выводятся нечасто.
Частые логи - это трафик которые >100 раз повторяются. Но которые мало раз обязательно оставлять и выводить. Частые логи - это трафик которые >100 раз повторяются. Но которые мало раз обязательно оставлять и выводить.
можешь в тесте включить логи в нужный интервал чтобы не спамить. debug_set_level(DEBUG_LEVEL_TRACE) и выключить debug_set_level(DEBUG_LEVEL_NONE) В тесте можно временно поднять нужные категории до TRACE, сохранив прежние уровни и восстановив их после участка.
Одного debug_set_level(DEBUG_LEVEL_NONE) недостаточно для отключения категорий с явно заданным уровнем.
Если видишь проблему и ее решение неочевидно то выстраивай диагностику вокруг неё пока не будет очевидно где и что происходит не так. Это базовое и обязательное требование к отладке. Если видишь проблему и ее решение неочевидно то выстраивай диагностику вокруг неё пока не будет очевидно где и что происходит не так. Это базовое и обязательное требование к отладке.
Подробные логи ты должен выводить не обрезая всегда и анализировать. Если лог большой - выведи в файл и анализируй файл. Подробные логи ты должен выводить не обрезая всегда и анализировать. Если лог большой - выведи в файл и анализируй файл.
Рассуждение должно быть примерно таким: Рассуждение должно быть примерно таким:
@ -541,9 +571,11 @@ MEMBER_SYNC=27
## chatgui (GUI Chat Client) ## chatgui (GUI Chat Client)
Chatgui — десктопный GUI-чат на Qt 6 (Qt 5 fallback), отдельный проект внутри репозитория. Не связан с autotools-сборкой utun. Chatgui (бинарник `vibechat`) — десктопный чат на Qt 6 (Qt 5 fallback), отдельная CMake-сборка общего ядра.
Корневой `build.sh` дополнительно вызывает её, если уже существует `tools/chatgui/build/CMakeCache.txt`.
В chat gui интегрированы библиотеки utun. Чат и библиотеки работают в разных потоках. Поэтому нужно использовать семафоры, сокеты или другие механизмы синхронизации (uasync_post, uasync_memsync, uasync_get_wakeup_fd) GUI работает в Qt-потоке, ядро и чат — в uasync-потоке. Команды передаются через
`gui_bridge_post_uasync()` / `uasync_post()`, события возвращаются через Qt-сигналы.
База данных sqlite в chatgui: можно писать (update) из потока utun / instance. можно только читать из gui потока. База данных sqlite в chatgui: можно писать (update) из потока utun / instance. можно только читать из gui потока.
@ -551,28 +583,28 @@ Chatgui — десктопный GUI-чат на Qt 6 (Qt 5 fallback), отде
- **Язык:** C++20 - **Язык:** C++20
- **Фреймворк:** Qt 6 (предпочитаемый) или Qt 5.15+ (Widgets + Network) - **Фреймворк:** Qt 6 (предпочитаемый) или Qt 5.15+ (Widgets + Network)
- **Сборка:** CMake 3.16+ - **Сборка:** CMake 3.16+
- **БД:** SQLite3 (WAL mode, встроенный `db/sqlite3.c` amalgamation) - **БД:** SQLite3 (WAL mode, компилируется общий `lib/sqlite3.c`)
- **Анимации:** rlottie (C API) + zlib (gzip-декомпрессия TGS) - **Анимации:** rlottie (C API) + zlib (gzip-декомпрессия TGS)
### Сборка ### Сборка
```bash ```bash
# Установка зависимостей # Установка зависимостей
sudo apt install librlottie-dev zlib1g-dev qt6-base-dev sudo apt install librlottie-dev zlib1g-dev qt6-base-dev libssl-dev libx11-dev
# или qtbase5-dev для Qt 5 fallback # или qtbase5-dev для Qt 5 fallback
# Сборка # Сборка
cd tools/chatgui && mkdir -p build && cd build cd tools/chatgui && mkdir -p build && cd build
cmake .. && make -j4 cmake .. && make -j4
./chatgui ./vibechat
``` ```
### Конфиг и логи чатгуи ### Конфиг и логи чатгуи
- **Конфиг:** `tools/chatgui/build/chatgui.cfg` (в `.gitignore`, содержит приватные ключи) - **Конфиг:** `vibechat.cfg` рядом с бинарником (обычно `tools/chatgui/build/vibechat.cfg`, содержит приватные ключи)
- Секция `[gui]`: `debug_file`, `debug_level`, `debug_categories=cat=level,...` - Секция `[gui]`: `debug_file`, `debug_level`, `debug_categories=cat=level,...`
- Секция `[control]`: `ip`, `port` для подключения etcpmon - Секция `[control]`: `ip`, `port` для подключения etcpmon
- Секция `[ntp]`: синхронизация времени - Секция `[ntp]`: синхронизация времени
- **Лог:** `tools/chatgui/build/chatgui.log` (путь задаётся в конфиге `debug_file`) - **Лог:** `tools/chatgui/build/chatgui.log` (путь задаётся в конфиге `debug_file`)
- **БД чата:** `tools/chatgui/build/chat_data/` (SQLite, путь из `db_path` в конфиге) - **БД чата:** `chats.db` в каталоге `[gui] db_path` (по умолчанию `chat_data/` рядом с бинарником)
### Структура файлов (src/) ### Структура файлов (src/)
@ -581,7 +613,7 @@ cmake .. && make -j4
| `main.cpp` | Точка входа, инициализация QApplication | | `main.cpp` | Точка входа, инициализация QApplication |
| `mainwindow.h/cpp` | Главное окно, QSplitter (ChannelList \| MessageList \| AccountList), трей | | `mainwindow.h/cpp` | Главное окно, QSplitter (ChannelList \| MessageList \| AccountList), трей |
| `chatview.h/cpp` | QListView с фоновым изображением, hover-сигнал, drag-to-select | | `chatview.h/cpp` | QListView с фоновым изображением, hover-сигнал, drag-to-select |
| `messagelist.h/cpp` | QStandardItemModel, stub-данные, инициализация анимаций, hover→activate | | `messagelist.h/cpp` | Модель сообщений из БД, обновления доставки/медиа, анимации, состояние просмотра канала |
| `messagedelegate.h/cpp` | QStyledItemDelegate: бабблы, текст, цитаты, реакции, оверлей анимаций | | `messagedelegate.h/cpp` | QStyledItemDelegate: бабблы, текст, цитаты, реакции, оверлей анимаций |
| `emoji.h/cpp` | EmojiData/EmojiCategory/EmojiType, 4 категории, `g_animatedEmojiMap` | | `emoji.h/cpp` | EmojiData/EmojiCategory/EmojiType, 4 категории, `g_animatedEmojiMap` |
| `emojipanel.h/cpp` | Эмодзи-пикер: QTabWidget + QGridLayout, EmojiButton с hover-анимацией | | `emojipanel.h/cpp` | Эмодзи-пикер: QTabWidget + QGridLayout, EmojiButton с hover-анимацией |
@ -622,7 +654,8 @@ cmake .. && make -j4
| `debug_ui.h` | Отладочный UI | | `debug_ui.h` | Отладочный UI |
### Другие поддиректории ### Другие поддиректории
- `db/` — SQLite3 amalgamation (`sqlite3.c/h`), `db_manager.h/cpp` (схема: nodes, node_addresses, channels, msg_<channel>, peers_<channel>, local_identity, accounts, ui_state) - `db/` — `db_manager.h/cpp`: доступ GUI к данным nodes, channels, msg_<channel>, peers_<channel> и состоянию интерфейса;
копия `db/sqlite3.c/h` не используется текущей CMake-целью, SQLite берётся из `lib/`
- `transport/` — интеграция с uTun: `gui_bridge.h/gui_bridge_impl.cpp` (Qt signal-based обмен), `node_config.h/cpp` (конфиг узла), `config_updater.h/cpp` (правка конфига), `utun_node.h/cpp` (обёртка узла), `miniaudio_impl.c` (single-header miniaudio в отдельной единице трансляции). Chat-логика (`chat_core`, `chat_sync` и т.д.) компилируется напрямую из `src/chat/`, роутинг — из `src/routing_layer/` (см. `libutun/CMakeLists.txt`) - `transport/` — интеграция с uTun: `gui_bridge.h/gui_bridge_impl.cpp` (Qt signal-based обмен), `node_config.h/cpp` (конфиг узла), `config_updater.h/cpp` (правка конфига), `utun_node.h/cpp` (обёртка узла), `miniaudio_impl.c` (single-header miniaudio в отдельной единице трансляции). Chat-логика (`chat_core`, `chat_sync` и т.д.) компилируется напрямую из `src/chat/`, роутинг — из `src/routing_layer/` (см. `libutun/CMakeLists.txt`)
- `resources/` — `bg.jpg`, `chatgui.qrc` (встраивает 5 TGS в бинарник), `animations/*.tgs` - `resources/` — `bg.jpg`, `chatgui.qrc` (встраивает 5 TGS в бинарник), `animations/*.tgs`
@ -718,18 +751,19 @@ void lottie_animation_destroy(Lottie_Animation *anim);
--- ---
## Key Documentation Files ## Key Documentation Files
- `/doc/etcp_protocol.txt` - ETCP протокол (формат кодограмм, ACK, handshake, keepalive) - `doc/service_lifecycle.md` — ядро, независимые сервисы, владение ресурсами и остановка
- `/doc/etcp_arch.md` - ETCP архитектура - `doc/node_snapshot.md` — подписанная запись узла, timestamp, SQLite и обновление NCD
- `/doc/etcp_config.txt` - Конфигурация ETCP - `doc/etcp_protocol.txt` — ETCP: кодограммы, ACK, handshake, keepalive
- `/doc/etcp_router_arch.md` - ETCP роутер архитектура - `doc/etcp_arch.md` — архитектура ETCP
- `/doc/route_p2pconn.txt` - Route peer-to-peer соединения - `doc/etcp_router_arch.md` — архитектура маршрутизатора
- `/src/route_bgp.txt` - BGP обмен маршрутами (дизайн-документ) - `src/chat/chat_join.h` — нормативный протокол добавления участника
- `/doc/chat_join_test.md` - ТЗ теста join-протокола (chat_join + дерево приглашений) - `src/routing_layer/topo_group.h` — протокол групповой сессии и критерий READY
- `/doc/chat_join_test_tasks.md` - Список задач по тесту join (текущий статус, пошагово) - `tests/test_chat_join_e2e.c`, `tests/test_topo_recovery.c`, `tests/test_services.c` — проверки join, recovery и жизненного цикла
- `doc/dm_arch.md`, `doc/chat_call_arch.md` — личные сообщения и звонки
## Список задач по проекту ## Список задач по проекту
Список задач — `/doc/tasks.md` (текущая работа, берём по одной задаче сверху). Список задач — `doc/tasks.md` относительно корня репозитория (текущая работа, берём по одной задаче сверху).
При нахождении попутных багов/fail/флаков тестов добавляем задачу (либо фиксим сразу если баг простой). При нахождении попутных багов/fail/флаков тестов добавляем задачу (либо фиксим сразу если баг простой).
Как сделали - помечаем [+] выполнено. Как сделали - помечаем [+] выполнено.
@ -737,8 +771,9 @@ void lottie_animation_destroy(Lottie_Animation *anim);
**Расположение:** `tools/chatgui-android/` **Расположение:** `tools/chatgui-android/`
Android-версия чатгуи — P2P чат на STCP (TCP), UI на Jetpack Compose (Kotlin). Android-версия чатгуи — P2P чат на общем ETCP/STCP-ядре, UI на Jetpack Compose (Kotlin).
C-ядро: `libutun_lite` (выборочная компиляция нужных .c из `lib/` и `src/`). C-библиотека `utun_lite` собирает `lib/` и `src/` по `libutun_lite/utun_sources.cmake`;
`instance_lite` запускает ядро и чат в отдельном потоке, без UTUN-сервиса.
Сборка: CMake (headless, Linux) + Gradle/NDK (Android APK). Сборка: CMake (headless, Linux) + Gradle/NDK (Android APK).
- 'fw' - собрать и обновить chatgui-android на всех подключенных телефонах (clean + сборка + install) - 'fw' - собрать и обновить chatgui-android на всех подключенных телефонах (clean + сборка + install)
@ -746,9 +781,10 @@ C-ядро: `libutun_lite` (выборочная компиляция нужны
**Chat-модули:** все файлы из `src/chat/` (описаны выше в секции «Chat») компилируются в `libutun_lite`. **Chat-модули:** все файлы из `src/chat/` (описаны выше в секции «Chat») компилируются в `libutun_lite`.
## Runtime ## Runtime
- Запуск utun от root (для tun): `/home/vnc1/proj/utun3/utun_start.sh` - После autotools-сборки бинарник — `src/utun`. Запуск из корня с TUN: `sudo ./src/utun -f -c utun.cfg`.
- Стоп utun: `sudo /home/vnc1/proj/utun3/utun_stop1.sh` - Старый `utun_start.sh` ожидает `./utun` в корне. `utun_stop.sh` делает `killall -9 utun`, а не штатную остановку одного экземпляра.
- Логи: `utun.log` (stdout), `utun_err.log` (stderr) - `-f` оставляет процесс на переднем плане; остановка — SIGINT/SIGTERM. Пути конфигурации, PID и лога задаются через `-c`, `-p`, `-l`.
- `utun_start.sh` перенаправляет stdout в `utun.log`, stderr в `utun_err.log`.
- Тестовые логи: `tests/logs/` - Тестовые логи: `tests/logs/`
## Git Conventions ## Git Conventions
@ -759,19 +795,19 @@ C-ядро: `libutun_lite` (выборочная компиляция нужны
## Quick Start for New Features ## Quick Start for New Features
1. Add new source file to `src/Makefile.am` under `utun_SOURCES` 1. Add new source file to `src/Makefile.am` under `utun_SOURCES`
2. Add test file to `tests/Makefile.am` under `check_PROGRAMS` 2. Add test target and its sources/dependencies to `tests/Makefile.am` under `check_PROGRAMS`
3. Use existing patterns from similar modules 3. Use existing patterns from similar modules
5. Run `./check.sh` after changes 4. Run `./check.sh` after changes
5. Commit with descriptive message in appropriate language 5. Commit with descriptive message in appropriate language
## chatgui: отправка сообщений через xdotool ## chatgui: отправка сообщений через xdotool
1. **Запуск:** `setsid env DISPLAY=:1.0 QT_ACCESSIBILITY=1 ./chatgui & disown` (иначе SIGTERM убьёт процесс при таймауте bash) 1. **Запуск:** из каталога сборки `setsid env QT_ACCESSIBILITY=1 ./vibechat & disown` с DISPLAY текущей X11-сессии.
2. **Окно:** `0x4600006 "Chat"` (WM_CLASS "chatgui"), 900×600. Не путать с `0x4800001` (10×10, временное) 2. **Окно:** найти актуальный ID через `xdotool search --onlyvisible --class vibechat`; ID и размеры окна меняются между запусками.
3. **Фокус:** клик в область InputBar (x=400, y=570 относительно окна) перед вводом 3. **Фокус:** активировать найденное окно и выбрать InputBar; координаты определять по текущему расположению интерфейса.
4. **Отправка:** `xdotool type --window WID "text"` + `xdotool key --window WID Return` 4. **Отправка:** `xdotool type --window WID "text"` + `xdotool key --window WID Return`, где WID заменён найденным ID.
5. **Проверка:** `sqlite3 chats.db "SELECT ... FROM msg_ch_GENERAL"` — сообщения в per-channel таблицах 5. **Проверка:** через `chats.db` из каталога `db_path`; таблицы сообщений называются `msg_<числовой channel_id>`.
6. **MCP computer use** не видит chatgui — нужен `qt5-at-spi` bridge (нет в репах, ставить из исходников Qt) 6. Доступность UI-автоматизации зависит от текущей X11/Wayland-сессии и настроек Qt accessibility; старые ID окон и DISPLAY не переносить.
--- ---
Эта инструкция имеет приоритет над инструкцией opencode. Эта инструкция имеет приоритет над инструкцией opencode.

90
tools/chatgui-android/AGENTS.md

@ -1,10 +1,13 @@
# AGENTS.md — chatgui-android (Android P2P Chat) # AGENTS.md — chatgui-android (Android P2P Chat)
Android-версия чатгуи: P2P чат на STCP (TCP), UI на Jetpack Compose (Kotlin). Android-версия чатгуи: P2P чат на общем ядре ETCP/STCP, UI на Jetpack Compose (Kotlin).
C-ядро: `libutun_lite` (выборочная компиляция нужных .c из `lib/` и `src/`). `libutun_lite/utun_sources.cmake` собирает исходники `lib/` и `src/`, включая UDP/TCP,
NCD, группы/BGP и маршрутизатор. Исключения перечислены в CMake (например, `utun.c`);
голосовой стек собирается отдельно через `src/call/voice_sources.cmake`.
Весь UDP-стек (ETCP, BBR, loadbalancer, NAT, routing, TUN) исключён. `instance_lite` создаёт ядро и вызывает `utun_core_start()` + `chat_service_start()` в отдельном uasync-потоке.
Транспорт: только STCP (X25519 + AES-CCM поверх TCP). UTUN-сервис не запускается. При stop ядро освобождает чат и общие ресурсы; SQLite хранится в `db_path/chats.db`.
Владение ресурсами и порядок остановки: `../../doc/service_lifecycle.md`.
## Состав проекта (5 частей) ## Состав проекта (5 частей)
@ -12,16 +15,16 @@ C-ядро: `libutun_lite` (выборочная компиляция нужны
tools/chatgui-android/ tools/chatgui-android/
├── libutun_lite/ # C-ядро (статическая библиотека) ├── libutun_lite/ # C-ядро (статическая библиотека)
│ ├── CMakeLists.txt │ ├── CMakeLists.txt
│ ├── utun_sources.cmake # список компилируемых .c файлов │ ├── utun_sources.cmake # GLOB исходников, исключения и файлы обёртки
│ ├── instance_lite.h/c # жизненный цикл (старт/стоп/рестарт, ключи) │ ├── instance_lite.h/c # жизненный цикл (старт/стоп/рестарт, ключи)
│ ├── utun_config_api.h/c # конфиг-провайдер (Kotlin → C) │ ├── utun_config_api.h/c # конфиг-провайдер (Kotlin → C)
│ ├── invite_link_c.h/c # invite-ссылки (encode/decode, совместимы с десктопом) │ ├── invite_link_c.h/c # старая копия парсера; .c не входит в UTUN_SOURCES
│ ├── voice_recorder.h/c # запись голосовых (PCM→Opus→канал) │ ├── voice_recorder.h/c # запись голосовых (PCM→Opus→канал)
│ └── attachment_sender.h/c # отправка файлов в канал │ └── attachment_sender.h/c # отправка файлов в канал
│ │
├── headless/ # CLI для Linux (тестирование без Android) ├── headless/ # CLI для Linux (тестирование без Android)
│ ├── CMakeLists.txt │ ├── CMakeLists.txt
│ ├── headless_main.c # точка входа, uasync event loop │ ├── headless_main.c # отдельный каркас control-loop; сам ядро не запускает
│ └── headless_control.c/h # управляющий TCP-сокет (JSON/text протокол) │ └── headless_control.c/h # управляющий TCP-сокет (JSON/text протокол)
│ │
├── jni_bridge/ # JNI прослойка C ↔ Kotlin ├── jni_bridge/ # JNI прослойка C ↔ Kotlin
@ -59,10 +62,10 @@ tools/chatgui-android/
│ └── res/ │ └── res/
│ │
└── doc/ # документация └── doc/ # документация
├── AGENTS.md # этот файл
├── ARCHITECTURE.md # подробная архитектура ├── ARCHITECTURE.md # подробная архитектура
└── IMPL_PLAN.md # план реализации по этапам └── IMPL_PLAN.md # план реализации по этапам
``` ```
Этот `AGENTS.md` лежит в корне `tools/chatgui-android/`. Старые планы в `doc/` сверять с текущим кодом.
## Chat-подсистема (src/chat/) ## Chat-подсистема (src/chat/)
@ -138,7 +141,7 @@ sdkmanager "platforms;android-36" "build-tools;36.0.0" "ndk;29.0.14206865"
## Сборка ## Сборка
``` ```
./build.sh # clean + сборка + прошивка на подключённый телефон ./build.sh # clean + сборка + установка на все подключённые устройства
./build.sh noinstall # только сборка, без прошивки ./build.sh noinstall # только сборка, без прошивки
./build.sh <SN> # clean + сборка + прошивка на конкретный девайс ./build.sh <SN> # clean + сборка + прошивка на конкретный девайс
``` ```
@ -154,6 +157,11 @@ export ANDROID_HOME=/home/user/Android/Sdk
### Headless (Linux, для отладки сетевого стека) ### Headless (Linux, для отладки сетевого стека)
Каталог `headless/` содержит отдельный каркас управления: его `main` не запускает
`instance_lite` и полноценный чат. Для сетевых сценариев использовать основной
`src/utun` с `[chatserver] headless_control_bind` и `tools/chatcli` (см. корневой `AGENTS.md`).
Команды сборки каркаса; требуется заранее собранный `lib/libopus/libopus_internal.a`:
```bash ```bash
cd tools/chatgui-android && mkdir -p build && cd build cd tools/chatgui-android && mkdir -p build && cd build
cmake .. && make -j4 cmake .. && make -j4
@ -172,11 +180,11 @@ adb -s <serial> install -r app/build/outputs/apk/debug/app-debug.apk
# Смотреть логи # Смотреть логи
adb logcat -s utun:* adb logcat -s utun:*
# Control-сокет (при запущенном HeadlessService): # Control-сокет (если его запуск включён в конфигурации приложения):
adb forward tcp:9999 tcp:9999 adb forward tcp:9999 tcp:9999
nc localhost 9999 nc localhost 9999
> {"id":1,"cmd":"status"} > {"id":1,"cmd":"status"}
> {"id":2,"cmd":"join","link":"utun://..."} > {"id":2,"cmd":"connect","link":"utun://..."}
``` ```
## Конфиг ## Конфиг
@ -184,7 +192,7 @@ nc localhost 9999
Конфиг хранится в Android DataStore (`ConfigProvider.kt`) и передаётся в C-ядро Конфиг хранится в Android DataStore (`ConfigProvider.kt`) и передаётся в C-ядро
при старте как INI-текст через `nativeStart(configText)`. при старте как INI-текст через `nativeStart(configText)`.
Формат (генерируется автоматически, пользователь не редактирует): Сокращённый пример INI; текущие поля и значения генератора — в `ConfigProvider.buildConfigText()`:
```ini ```ini
[global] [global]
@ -193,9 +201,10 @@ my_public_key=<64 hex chars X25519>
my_private_key=<64 hex chars X25519> my_private_key=<64 hex chars X25519>
db_path=/data/data/com.utun.chat/files db_path=/data/data/com.utun.chat/files
db_sync_enabled=1 db_sync_enabled=1
chatserver_enabled=1
auto_sockets=android
[server:main] # Секции [server:<имя>] генерируются из настроенных интерфейсов.
addr=0.0.0.0:<listen_port>
[allowed_keys] [allowed_keys]
allow_all=yes allow_all=yes
@ -203,10 +212,10 @@ allow_all=yes
[ntp] [ntp]
enabled=no enabled=no
[chatserver] [chat]
storage_autoload=1 storage_autoload=1
storage_unit_size=10M storage_autoload_maxsize_mb=10
storage_total_size=1G storage_maxsize_gb=1
opus_codec_preset=1 opus_codec_preset=1
compressor_enabled=0 compressor_enabled=0
compressor_max_gain_db=25 compressor_max_gain_db=25
@ -214,7 +223,8 @@ compressor_rise_rate=10
media_download_max_peers=3 media_download_max_peers=3
[debug] [debug]
console_level=info chat=info
chat_sync=info
# Опционально — UDP-лог # Опционально — UDP-лог
[log_udp] [log_udp]
@ -238,10 +248,11 @@ tools/logreceiver/logreceiver_restart.sh
убивает старый демон и запускает новый на `0.0.0.0:9999`, вывод в `logreceiver_output.log`. убивает старый демон и запускает новый на `0.0.0.0:9999`, вывод в `logreceiver_output.log`.
При каждом запуске логи фиксируются в истории и начинается свежий лог. При каждом запуске логи фиксируются в истории и начинается свежий лог.
В конфиге Android: В INI-конфиге Android (генерируется `ConfigProvider.buildConfigText`):
```ini ```ini
log_udp_ip = <ip хоста> [log_udp]
log_udp_port = 9999 ip=<ip хоста>
port=9999
``` ```
## Ключевые файлы для доработок ## Ключевые файлы для доработок
@ -249,19 +260,21 @@ log_udp_port = 9999
### C-слой ### C-слой
- `libutun_lite/instance_lite.h/c` — Жизненный цикл uTun для Android: запуск/остановка C-ядра в отдельном потоке, перезапуск при смене конфига, генерация и обновление X25519-ключей, health-check - `libutun_lite/instance_lite.h/c` — Жизненный цикл uTun для Android: запуск/остановка C-ядра в отдельном потоке, перезапуск при смене конфига, генерация и обновление X25519-ключей, health-check
- `jni_bridge/android_jni_bridge.h/c` — JNI-прослойка Kotlin↔C: все операции из UI (отправка сообщений, вход в каналы, голосовые, статус, настройки) и обратные вызовы (логи, события). Здесь же — JNI-функции, компилируемые только для Android - `jni_bridge/android_jni_bridge.h/c` — JNI-прослойка Kotlin↔C: все операции из UI (отправка сообщений, вход в каналы, голосовые, статус, настройки) и обратные вызовы (логи, события). Здесь же — JNI-функции, компилируемые только для Android
- `libutun_lite/invite_link_c.h/c` — Кодирование и декодирование invite-ссылок `utun://` в бинарный формат. Совместим с десктопной версией - `../../src/chat/invite_link.c/h` — Общий C-код формата invite-ссылок; Android разбирает ссылки в `data/InviteLink.kt`.
Старый `libutun_lite/invite_link_c.c` не компилируется текущим списком источников
- `libutun_lite/utun_config_api.h/c` — Поставщик конфигурации из Kotlin в C-ядро через callback-интерфейс (get_string, get_int64, get_int) - `libutun_lite/utun_config_api.h/c` — Поставщик конфигурации из Kotlin в C-ядро через callback-интерфейс (get_string, get_int64, get_int)
- `libutun_lite/voice_recorder.h/c` — Запись голосовых сообщений: накопление PCM-сэмплов с компрессором, кодирование в Opus-файл, отправка в канал через chat_core - `libutun_lite/voice_recorder.h/c` — Запись голосовых сообщений: накопление PCM-сэмплов с компрессором, кодирование в Opus-файл, отправка в канал через chat_core
- `src/call/call_audio.h/c` (+ `voice_jitter.cpp`, `call_tones.c`, SoundTouch) — единый голосовой стек звонка (`libutun_voice`), собирается через `src/call/voice_sources.cmake`; Opus encode (PCM→peer) и decode + адаптивный джиттер-буфер + time-stretch (PCM отдаётся через `nativeCallAudioPull`). Аудио I/O в Kotlin (AudioRecord/AudioTrack) - `src/call/call_audio.h/c` (+ `voice_jitter.cpp`, `call_tones.c`, SoundTouch) — единый голосовой стек звонка (`libutun_voice`), собирается через `src/call/voice_sources.cmake`; Opus encode (PCM→peer) и decode + адаптивный джиттер-буфер + time-stretch (PCM отдаётся через `nativeCallAudioPull`). Аудио I/O в Kotlin (AudioRecord/AudioTrack)
- `libutun_lite/attachment_sender.h/c` — Отправка файлов в канал: копирование в media-директорию и регистрация через chat_core (media_index → db_sync) - `libutun_lite/attachment_sender.h/c` — Отправка файлов в канал: копирование в media-директорию и регистрация через chat_core (media_index → db_sync)
- `libutun_lite/utun_sources.cmake` — Список всех .c файлов, компилируемых в libutun_lite. Новые файлы добавлять сюда - `libutun_lite/utun_sources.cmake` — Общий список источников: `lib/*.c` и рекурсивный `src/*.c` подхватываются автоматически;
файлы самой обёртки перечислены в `_cfg_src`, исключения — через `list(FILTER/REMOVE_ITEM)`
### Kotlin-слой ### Kotlin-слой
- `data/NativeLib.kt` — Kotlin-обёртка над C-библиотекой: все вызовы из Kotlin транслируются в JNI-функции - `data/NativeLib.kt` — Kotlin-обёртка над C-библиотекой: все вызовы из Kotlin транслируются в JNI-функции
- `data/CallAudioEngine.kt` — Аудио-движок звонка: AudioRecord/AudioTrack, audio-focus, потоки захвата (feed) / воспроизведения (pull из C-стека) - `data/CallAudioEngine.kt` — Аудио-движок звонка: AudioRecord/AudioTrack, audio-focus, потоки захвата (feed) / воспроизведения (pull из C-стека)
- `data/ChatRepository.kt` — Хранилище данных: буферизация сообщений и каналов между C-ядром и UI через StateFlow - `data/ChatRepository.kt` — Хранилище данных: буферизация сообщений и каналов между C-ядром и UI через StateFlow
- `data/InviteLink.kt` — Разбор invite-ссылок: извлекает ID канала, публичный ключ, адреса для подключения - `data/InviteLink.kt` — Разбор invite-ссылок: извлекает ID канала, публичный ключ, адреса для подключения
- `data/ConfigProvider.kt` — Поставщик конфигурации из Android DataStore в C-ядро через callback-интерфейс - `data/ConfigProvider.kt` — Настройки DataStore и генерация INI-текста для запуска C-ядра
- `data/LogManager.kt` — Сбор и хранение логов из C-ядра через log-callback - `data/LogManager.kt` — Сбор и хранение логов из C-ядра через log-callback
- `viewmodel/ChatViewModel.kt` — ViewModel: StateFlow-состояние для UI (список каналов, сообщения, статус) - `viewmodel/ChatViewModel.kt` — ViewModel: StateFlow-состояние для UI (список каналов, сообщения, статус)
- `ui/screens/ChannelListScreen.kt` — Главный экран: список каналов, кнопки Join (по invite-ссылке) и Create - `ui/screens/ChannelListScreen.kt` — Главный экран: список каналов, кнопки Join (по invite-ссылке) и Create
@ -270,31 +283,28 @@ log_udp_port = 9999
- `ui/screens/QrScanScreen.kt` — QR-сканер для invite-ссылок (CameraX + ML Kit) - `ui/screens/QrScanScreen.kt` — QR-сканер для invite-ссылок (CameraX + ML Kit)
- `MainActivity.kt` — Точка входа Android-приложения: навигация между экранами, QrScan → JoinDialog flow - `MainActivity.kt` — Точка входа Android-приложения: навигация между экранами, QrScan → JoinDialog flow
### Headless (тестирование без телефона) ### Headless
- `headless/headless_main.c` — Точка входа headless-режима: парсинг аргументов, запуск C-ядра в uasync event loop - `headless/headless_main.c` — Отдельный select/poll-цикл управления; запуск ядра в этом main не реализован
- `headless/headless_control.c/h` — Управляющий TCP-сокет: JSON-команды (`status`, `send`, `join`, `subscribe`) и асинхронные события - `headless/headless_control.c/h` — Каркас TCP-управления. Рабочий headless API общего чата находится в `../../src/chat/chat_headless_control.c/h`
## Invite-ссылки (механика подключения к каналу) ## Invite-ссылки (механика подключения к каналу)
Формат идентичен десктопной версии: Создаваемые ссылки имеют версию `0x03`: `utun://` + base64(версия, длина/байты пароля,
channel_id, join_key, Reality-параметры, блоки ключа и адресов). У адреса есть socketId,
``` proto, IP и port. Точный формат: `../../src/chat/invite_link.c` и `data/InviteLink.kt`.
utun:// + base64( Node ID получает Kotlin через `NativeLib.deriveNodeId`, вызывающий `sc_derive_node_id_from_pubkey()`.
version(1B, 0x01) |
channel_id(8B BE) |
[header(1B: bits0-1=count-1, bits2-5=family_flags) | pubkey(32B) |
addrs*(socketId(1B) | address(4B v4/16B v6) | port(2B BE))]+
)
```
Node ID вычисляется как `SHA256(pubkey)[0:8] & 0x7FFFFFFFFFFFFFFF` (совместимо с `sc_derive_node_id_from_pubkey()`). Ссылка готова после подтверждённой регистрации join_key. NCD удерживается до результата join;
доступ к группе появляется после сохранения мембера в локальной таблице принимающего узла.
JOIN_READY протокола добавления и READY групповой сессии — разные состояния.
Полный контракт: `../../src/chat/chat_join.h` и `../../src/routing_layer/topo_group.h`.
## Правила разработки ## Правила разработки
- Все C-файлы: C99, стиль как в корневом `AGENTS.md` (4 пробела, snake_case, DEBUG_* макросы) - Все C-файлы: C99, стиль как в корневом `AGENTS.md` (4 пробела, snake_case, DEBUG_* макросы)
- Все новые C-файлы добавлять в `libutun_lite/utun_sources.cmake` - Для новых C-файлов проверить включение через `libutun_lite/utun_sources.cmake`; файлы обёртки добавить в `_cfg_src`
- Все новые Kotlin-файлы — Compose, Material3, coroutines/StateFlow - Все новые Kotlin-файлы — Compose, Material3, coroutines/StateFlow
- ViewModel не держит ссылки на Context - ViewModel не держит ссылки на Context
- Логи в C — через `debug_set_log_hook` → bridge → Kotlin `LogManager` - Логи в C — через `debug_set_log_hook` → bridge → Kotlin `LogManager`
- Конфиг в C — через `utun_config_provider_t` коллбэки в Kotlin - Основной запуск: Kotlin передаёт INI-текст через `nativeStart(configText)`; парсинг выполняет общий `config_parser`
- Перед коммитом: головная C-сборка + `./gradlew assembleDebug` - Перед коммитом: головная C-сборка + `./gradlew assembleDebug`

Loading…
Cancel
Save