604 lines
37 KiB
Markdown
604 lines
37 KiB
Markdown
# AGENTS.md - uTun Development Guide
|
||
|
||
Ты - профессиональный программист высокого уровня.
|
||
Ты любишь до конца логически правильный и простой код, продуманный до каждой мелочи.
|
||
Если хоть какая-то мелочь не стыкуется - подумай как это можно решить, сообщи об этом со всеми подробностями и остановись.
|
||
Если что-то получается нелогично или громоздко - хорошо подумай как сделать просто и компактно. предложи варианты и остановись.
|
||
Имей, загружай когда надо полный код нужных тебе функций/структур. Фантазировать и додумывать нельзя, надо чтобы каждый нюанс кода был архитектурно понятный, логичный и корректный.
|
||
Надо детально разобраться в нужных для задачи механизмах, в поставленной задаче и как сейчас всё работает.
|
||
Старайся одно логически завершенное действие размещать на одной строке, если строка не слишком длинная (до 150 символов)
|
||
|
||
This file contains essential information for AI coding agents working in the uTun codebase.
|
||
|
||
## Quick Reference
|
||
|
||
**Repository:** uTun - Secure VPN tunnel with ETCP protocol
|
||
**Language:** C (C99)
|
||
**Build System:** GNU Autotools (autoconf/automake)
|
||
**Cryptography:** OpenSSL (AES-CCM, X25519, SHA256)
|
||
|
||
## Build Commands
|
||
|
||
### Full Build (Linux)
|
||
```bash
|
||
./build.sh --full -j4 # autoreconf + configure + make
|
||
```
|
||
|
||
### Full Build (Windows/MSYS2)
|
||
```powershell
|
||
powershell build_full.bat # запускает bash build.sh --full через MSYS2 UCRT64
|
||
```
|
||
|
||
### Incremental Build
|
||
```bash
|
||
./build.sh -j4 # make с авто-конфигурацией если надо
|
||
```
|
||
```powershell
|
||
powershell -Command ".\build.bat" 2>&1 # Windows, логи: build_win.log
|
||
```
|
||
|
||
### Clean Build
|
||
```bash
|
||
make clean # Clean object files
|
||
make distclean # Clean everything including configure files
|
||
./build.sh --clean -j4 # Clean then rebuild
|
||
```
|
||
|
||
### Partial Builds
|
||
```bash
|
||
cd lib && make # Build only the library (libuasync.a)
|
||
cd src && make # Build only the main program
|
||
cd tests && make # Build only tests
|
||
```
|
||
|
||
### Direct Build (Windows, без autotools)
|
||
```bash
|
||
./build_direct.sh # Компиляция вручную с x86_64-w64-mingw32-gcc
|
||
```
|
||
|
||
### ASAN Build (AddressSanitizer, Linux)
|
||
```bash
|
||
./build.sh --asan -j4 # lib/ + src/ only (tests not ASAN-compatible)
|
||
```
|
||
Запуск с ASAN (detect_leaks отключены чтобы не спамить при shutdown):
|
||
```bash
|
||
ASAN_OPTIONS=detect_leaks=0:halt_on_error=0 ./src/utun -f -p /tmp/utun.pid -l /tmp/utun.log
|
||
```
|
||
Краш-логи ASAN пишутся в `/tmp/utun_asan.<pid>`.
|
||
|
||
## Test Commands
|
||
|
||
### Run All Tests
|
||
```bash
|
||
make check # Run all tests via automake, логи в tests/logs/
|
||
```
|
||
```powershell
|
||
powershell check.bat # Windows, запускает каждый .exe из tests/
|
||
```
|
||
|
||
### Run Specific Test
|
||
```bash
|
||
cd tests/
|
||
./test_etcp_crypto
|
||
./test_etcp_two_instances
|
||
./test_etcp_simple_traffic
|
||
./test_pkt_normalizer_etcp
|
||
./test_etcp_api
|
||
./test_ll_queue
|
||
./test_nat_detection
|
||
./test_bgp_route_exchange
|
||
```
|
||
|
||
### Run Single Test with Debug Info
|
||
```bash
|
||
cd tests/
|
||
gcc -I../src -I../lib -I../tinycrypt/lib/include \
|
||
-o my_test test_file.c ../src/*.c ../lib/*.c ../tinycrypt/lib/source/*.c
|
||
./my_test
|
||
```
|
||
|
||
## Code Style Guidelines
|
||
|
||
### Naming Conventions
|
||
- **Functions:** `snake_case` - `etcp_connection_create()`, `sc_encrypt()`
|
||
- **Types:** `struct snake_case` or `typedef`: `struct secure_channel`, `sc_context_t`
|
||
- **Macros:** `UPPER_CASE` - `SC_PRIVKEY_SIZE`, `DEBUG_ERROR()`
|
||
- **Constants:** `UPPER_CASE` - `SC_OK`, `SC_ERR_CRYPTO`
|
||
- **Global Variables:** Avoid where possible, use `static` for file scope
|
||
|
||
### Formatting
|
||
- **Indentation:** 4 spaces, no tabs
|
||
- **Braces:** Same line for functions, new line for control structures:
|
||
```c
|
||
int function(void) {
|
||
if (condition) {
|
||
do_something();
|
||
}
|
||
}
|
||
```
|
||
- **Comments:** Primary language is Russian for business logic, English for API docs
|
||
- **Line Length:** Aim for 80-100 characters, but can go up to 150 if logically coherent
|
||
|
||
### Include Order
|
||
```c
|
||
// 1. System headers
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
// 2. Library headers
|
||
#include "../lib/ll_queue.h"
|
||
|
||
// 3. Local headers
|
||
#include "etcp.h"
|
||
```
|
||
|
||
### Error Handling
|
||
- Use custom error codes defined in headers (e.g., `SC_ERR_INVALID_ARG`)
|
||
- Return negative values for errors, 0 for success
|
||
- Use DEBUG macros for logging:
|
||
```c
|
||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize: %s", err);
|
||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Socket created on port %d", port);
|
||
```
|
||
- Во всех блоках обработки ошибок/нештатных ситуаций должны быть сообщения DEBUG_ERROR/DEBUG_WARN
|
||
|
||
### Memory Management
|
||
- Use `u_malloc`/`u_calloc`/`u_realloc`/`u_free`/`u_strdup` from `lib/mem.h` (wrappers with leak tracking)
|
||
- Memory pools: `memory_pool_alloc()` / `memory_pool_free()` for hot-path allocations
|
||
- Queue entries: `queue_entry_new_from_pool()` / `queue_entry_free()` / `queue_dgram_free()`
|
||
|
||
## Cryptography Guidelines
|
||
|
||
### Key Sizes
|
||
| Constant | Value | Description |
|
||
|----------|-------|-------------|
|
||
| `SC_PRIVKEY_SIZE` | 32 | X25519 private key |
|
||
| `SC_PUBKEY_SIZE` | 32 | X25519 public key |
|
||
| `SC_NONCE_SIZE` | 13 | CCM nonce (exactly 13 bytes) |
|
||
| `SC_SESSION_KEY_SIZE` | 16 | AES-128 session key |
|
||
| `SC_TAG_SIZE` | 16 | CCM auth tag |
|
||
| `SC_CRC32_SIZE` | 4 | CRC32 checksum |
|
||
| `SC_PUBKEY_ENC_SALT_SIZE` | 8 | Salt for pubkey obfuscation |
|
||
| `SC_PUBKEY_ENC_SIZE` | 40 | Total pubkey+salt block sent unencrypted |
|
||
|
||
### Using Secure Channel (secure_channel.h)
|
||
```c
|
||
// 1. Initialize context
|
||
struct SC_MYKEYS my_keys;
|
||
sc_init_local_keys(&my_keys, public_key_hex, private_key_hex);
|
||
// or sc_generate_keypair(&my_keys);
|
||
|
||
sc_context_t ctx;
|
||
sc_init_ctx(&ctx, &my_keys);
|
||
|
||
// 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
|
||
|
||
// 3. Ready for encrypt/decrypt
|
||
sc_encrypt(&ctx, plaintext, plaintext_len, ciphertext, &ciphertext_len);
|
||
sc_decrypt(&ctx, ciphertext, ciphertext_len, plaintext, &plaintext_len);
|
||
|
||
// 4. Pubkey obfuscation (used in INIT/PING packets):
|
||
// salt(8) + XOR(SHA256(salt||peer_pubkey) || SHA256(peer_pubkey||salt), my_pubkey)
|
||
sc_obfuscate_pubkey(salt, peer_pubkey_bin, my_pubkey_bin, obfuscated_output);
|
||
```
|
||
|
||
### Important Notes
|
||
- **Encryption:** 3-byte header (timestamp uint16_t + flag_up uint8_t) + data_len bytes encrypted
|
||
- **INIT packets:** Header + data encrypted, pubkey+salt block (SC_PUBKEY_ENC_SIZE bytes) appended unencrypted
|
||
- **Nonce:** Must be exactly 13 bytes for CCM mode
|
||
- **Error codes:** Check return values, negative = error (SC_OK=0, SC_ERR_* < 0)
|
||
|
||
## Debug System
|
||
|
||
### Debug Levels (по возрастанию)
|
||
`none < error < warn < info < debug < trace`
|
||
|
||
### Debug Categories (25 категорий)
|
||
```
|
||
NONE=0, UASYNC=1, LL_QUEUE=2, CONNECTION=3, ETCP=4, CRYPTO=5, MEMORY=6,
|
||
TIMING=7, CONFIG=8, TUN=9, ROUTING=10, TIMERS=11, NORMALIZER=12, BGP=13,
|
||
SOCKET=14, CONTROL=15, DUMP=16, TRAFFIC=17, DEBUG=18, GENERAL=19, NAT=20,
|
||
KEEPALIVE=21, ETCPROUTE=22, BBR=23, ETCP_DUMP=24
|
||
```
|
||
|
||
### Настройка отладки
|
||
- В конфиге: `debug = etcp=trace,config=info` (формат: `категория=уровень,...`)
|
||
- В коде: глобальный уровень и per-category уровни из `debug_config_t g_debug_config`
|
||
- Макросы: `DEBUG_ERROR(cat,fmt,...)` `DEBUG_WARN` `DEBUG_INFO` `DEBUG_DEBUG` `DEBUG_TRACE`
|
||
- `log_dump(prefix, data, len)` — hex dump в лог
|
||
|
||
### Dual Output
|
||
- Консоль и файл настраиваются раздельно (`debug_set_console_level`, `debug_set_file_level`)
|
||
- `debug_enable_file_output(path, truncate)` / `debug_disable_file_output()`
|
||
|
||
## Architecture
|
||
|
||
### Directory Structure
|
||
```
|
||
├── lib/ # Core libraries (17 .c + 17 .h)
|
||
├── src/ # Main source code (42 .c + 44 .h root + 17 в поддиректориях)
|
||
├── tests/ # 65 .c файлов, 55 в check_PROGRAMS
|
||
├── doc/ # Technical Specifications
|
||
├── tools/ # Auxiliary tools
|
||
│ ├── etcpmon/ # GUI монитор ETCP
|
||
│ ├── chatgui/ # GUI чат (Qt 5, отдельная сборка через CMake)
|
||
│ ├── tdesktop-dev/ # Референс: Telegram Desktop (только для изучения)
|
||
│ ├── proxy/ # UDP прокси для тестов
|
||
│ └── bping/ # BPing (bandwidth ping)
|
||
├── tinycrypt/ # TinyCrypt crypto library (external)
|
||
├── net_emulator/ # Network emulator (delays, loss, reordering)
|
||
└── c2/ # Test instance 2 (конфиг и бинарник для тестов)
|
||
```
|
||
|
||
### File Overview
|
||
|
||
**Core (src/)**
|
||
- `utun.c` - Main program entry point, CLI parsing, daemon mode
|
||
- `utun_instance.c/h` - Root instance lifecycle, config loading, all submodule init
|
||
- `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_route.c/h` - TUN routing table sync
|
||
|
||
**Network Stack (src/)**
|
||
- `etcp.c/h` - ETCP protocol implementation (inflight queues, retrans, ACK, RTT/jitter)
|
||
- `etcp_api.c/h` - ETCP public API (send/recv/bind callbacks)
|
||
- `etcp_connections.c/h` - Socket and link management, INIT handshake, keepalive, PING/PONG
|
||
- `etcp_loadbalancer.c/h` - Multi-link load balancing with traffic shaper
|
||
- `etcp_debug.c/h` - ETCP packet dump/formatting
|
||
- `etcp_router.c/h` - ETCP router/multiplexer (мультиплексирование каналов)
|
||
- `etcp_connect.c/h` - ETCP outbound connections
|
||
- `etcp_dump.c/h` - ETCP дамп/декодирование пакетов
|
||
- `etcp_bbr.c/h` - BBR congestion control for ETCP
|
||
- `pkt_normalizer.c/h` - Packet fragmentation/reassembly (packer/unpacker)
|
||
- `packet_dump.c/h` - Packet hex dump utility
|
||
- `firewall.c/h` - Firewall rules (per-interface filtering)
|
||
- `dummynet.c/h` - Network emulator integrated into utun (for testing)
|
||
|
||
**BBR (src/BBR/)**
|
||
- `bbr_v3.c` - BBR congestion control algorithm v3
|
||
|
||
**STCP (src/)**
|
||
- `stcp.c/h` - STCP протокол (Secure TCP)
|
||
- `stcp_server.c/h` - STCP сервер
|
||
- `stcp_client.c/h` - STCP клиент
|
||
- `stcp_link.c/h` - STCP линк-уровень
|
||
|
||
**Топология / Маршрутизация (src/)**
|
||
- `routing.c/h` - Таблица маршрутов (локальные)
|
||
- `route_lib.c/h` - Библиотека маршрутизации
|
||
- `route6_lib.c/h` - IPv6 маршрутизация
|
||
- `route_ping.c/h` - Route ping probing (NAT check, liveness)
|
||
- `route_connectivity.c/h` - Проверка связности маршрутов
|
||
- `topo_group.c/h` - BGP-подобный обмен маршрутами между узлами
|
||
- `topo_node.c/h` - Управление узлами (peer management)
|
||
- `topo_node_lmdb.c/h` - LMDB-персистентность узлов
|
||
- `conn_mgr.c/h` - Менеджер соединений
|
||
|
||
**Crypto (src/)**
|
||
- `secure_channel.c/h` - AES-CCM encryption with X25519 key exchange, pubkey obfuscation
|
||
- `crc32.c/h` - CRC32 checksums
|
||
|
||
**NAT (src/)**
|
||
- `eim_nat.c/h` - Endpoint-Independent Mapping NAT engine
|
||
- `nat_transport.c/h` - NAT transport layer (packet relay)
|
||
|
||
**Config (src/)**
|
||
- `config_parser.c/h` - INI-style config file parsing
|
||
- `config_updater.c/h` - Config file modification utilities
|
||
|
||
**Control (src/)**
|
||
- `control_server.c/h` - Control/monitoring server (etcpmon backend API)
|
||
|
||
**Транспорт сообщений (src/)**
|
||
- `msg_transport.c/h` - Транспорт сообщений (чат, команды)
|
||
- `db_sync.c/h` - Синхронизация БД между узлами
|
||
|
||
**Прокси (src/proxy/)**
|
||
- `socks_proxy.c/h` - SOCKS5 прокси
|
||
- `udp_proxy.c/h` - UDP прокси
|
||
- `icmp_proxy.c/h` - ICMP прокси
|
||
- `tcp_proxy_server.c/h` - TCP прокси (серверная сторона)
|
||
- `tcp_proxy_client.c/h` - TCP прокси (клиентская сторона)
|
||
|
||
**lwIP TCP (src/lwip_tcp/)**
|
||
- `lwip_tcp.c/h` - lwIP TCP стек
|
||
- `lwip_tcp_out.c` / `lwip_tcp_in.c` - Исходящий/входящий трафик
|
||
- `lwip_pbuf.c/h` - Пакетные буферы lwIP
|
||
- `lwip_tcp_priv.h`, `lwip_tcp_opts.h` - Внутренние настройки lwIP
|
||
|
||
**Libraries (lib/)**
|
||
- `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
|
||
- `memory_pool.c/h` - Fast object pool allocator (pre-allocated blocks)
|
||
- `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)
|
||
- `sha256.c/h` - SHA256 hashing (fallback; OpenSSL preferred via USE_OPENSSL)
|
||
- `mem.c/h` - Memory wrappers with leak tracking (`u_malloc`/`u_free`/`u_calloc`/`u_strdup`)
|
||
- `serialize.c/h` - Binary serialization utilities
|
||
- `swm_min.c/h` - Sliding window minimum (for RTT min tracking)
|
||
- `getmyip.c/h` - Get local IP / default route detection
|
||
- `myip.c` - My IP helper (no header)
|
||
- `socket_compat.c/h` - Cross-platform socket compatibility (Linux/FreeBSD/Windows)
|
||
- `platform_compat.c/h` - Cross-platform compatibility layer (byte order, time, random)
|
||
- `radix.c/h` - Radix tree for IP routing lookups
|
||
- `tcp_io.c/h` - TCP I/O abstraction (Windows IOCP, Linux epoll)
|
||
- `wintun.h` - Wintun API header for Windows TUN driver
|
||
|
||
**Memory Pools in UTUN_INSTANCE:**
|
||
- `data_pool` — для данных пакетов (payload), используется input_queue/output_queue фрагментами
|
||
- `pkt_pool` — для struct ETCP_DGRAM (сетевые пакеты на отправку/приём)
|
||
- `ack_pool` — для struct ACK_PACKET (подтверждения приёма)
|
||
|
||
### Key Components
|
||
- **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
|
||
- **Memory Pool:** Fast allocation for hot-path objects (packets, inflight entries, fragments)
|
||
- **ETCP:** TCP-like reliable protocol with encryption, multi-link, load balancing
|
||
- **Secure Channel:** AES-CCM + X25519 key exchange, nonce-based encryption, pubkey obfuscation
|
||
|
||
## Queue Usage Rules
|
||
|
||
## Работа с очередями. Важно!
|
||
С очередью следуею работать придерживаясь следующих правил:
|
||
- при сетевом обмене не забиваем очередь. всегда используем Пороговое ожидание (backpressure).
|
||
- для работы с очередью полностью загрузи ll_queue.h и пойми как работает.
|
||
|
||
### Запись в очередь
|
||
- Очереди забивать нельзя. Добавляй следующий элемент только когда очередь стала пустой.
|
||
- Порог задаётся через `queue_set_threshold(q, max_packets, max_bytes)`.
|
||
- Используй `queue_waiter_wait` для ожидания освобождения очереди до заданного порога.
|
||
|
||
### Чтение из очереди
|
||
- Используй `queue_set_callback`: при вызове callback обработай один или несколько элементов, потом вызови `queue_resume_callback`.
|
||
- Внутри коллбэка ОБЯЗАТЕЛЬНО: `queue_data_get(q)` → обработать элемент → `queue_resume_callback(q)`
|
||
- Без вызова `queue_resume_callback` очередь навсегда застрянет
|
||
|
||
### Поиск
|
||
- `queue_data_put_with_index(q, entry)` — добавляет с индексом для быстрого поиска (offset/size заданы при queue_new)
|
||
- `queue_find_data_by_index(q, key)` — поиск по индексу через хеш-таблицу (размер ключа из q->index_size)
|
||
|
||
## u_async Rules
|
||
- Нельзя использовать в одном потоке несколько u_async. Один поток = всегда 1 uasync instance
|
||
- Нельзя использовать sleep/usleep если есть uasync. Нужно использовать `uasync_set_timeout`.
|
||
- Таймеры: `uasync_set_timeout(ua, timeout_tb, arg, callback, name)` — timebase units (0.1ms)
|
||
Возвращает `void*` handle, отмена: `uasync_cancel_timeout(ua, handle)`.
|
||
|
||
## Config Rules
|
||
- В серверном конфиге только собственные ключи и нет секций `[client]`
|
||
- В клиентском конфиге есть собственные ключи и pubkey каждого сервера в секции `[client]`
|
||
|
||
## Bugs Debugging Protocol
|
||
Всегда когда начинаешь диагностику ознакомься со скиллом (используй skills)
|
||
Диагностика и поиск ошибок - это в первую очередь продумывание отладочных механизмов которые покажут понятную картину и точное представление об ошибке. Рассуждать надо как диагностикой добиться точной картины. И как приавльнее добавить диагностику чтобы не спамила лишними сообщениями и была понятной, логичной и информативной.
|
||
|
||
Важное правило отладки: вся отладка сводится к тому чтобы сделать удобные логи которые наглядно показывают поведение и проблемы. без лишнего мусора, компактно и по существу. очень желательно с деталями которые сильно повышают качество отладки.
|
||
при отладке нельзя: гадать и долго пытаться разбирать код пытаяясь найти причину. гораздо надёжнее с помощью логов понято точное поведение.
|
||
Если логов много - записывай в файл и потом анализируй.
|
||
Если видишь спам-логи - подумай как их выборочно отключить чтобы не мешали.
|
||
|
||
Для отладки добавляй в DEBUG_CATEGORY_DEBUG диагностические сообщения где надо. И включи эту категорию в настройках. Убирай только после проверки (путём запуска) когда все ошибки устранены.
|
||
сообщение выводится по или - либо debug_set_level(DEBUG_LEVEL_TRACE) - выводится ВСЁ независимо от настроек по категориям. Тоесть берется max(global level, category lavel)
|
||
|
||
Твой бич - ты постоянно гадаешь и анализируешь код. Что приводит к снежному кобу ошибок и неверных гипотез. 10 раз повторяю - только логи логи логи и никакого гадания. Лоооги!!! правильные логи покажут всё с предельной точностью. Вся суть отладки - информативные логи
|
||
И смотри логи. не задавливай их grep-ом. лучше больше. единственное с чем борись - это бесполезные спам логи.
|
||
Но полезные смотри всегда, и всегда оставляй логи которые выводятся нечасто.
|
||
Частые логи - это трафик которые >100 раз повторяются. Но которые мало раз обязательно оставлять и выводить.
|
||
можешь в тесте включить логи в нужный интервал чтобы не спамить. debug_set_level(DEBUG_LEVEL_TRACE) и выключить debug_set_level(DEBUG_LEVEL_NONE)
|
||
Если видишь проблему и ее решение неочевидно то выстраивай диагностику вокруг неё пока не будет очевидно где и что происходит не так. Это базовое и обязательное требование к отладке.
|
||
Подробные логи ты должен выводить не обрезая всегда и анализировать. Если лог большой - выведи в файл и анализируй файл.
|
||
Рассуждение должно быть примерно таким:
|
||
- данные повреждаются при отправке.
|
||
- где и почему непонятно. надо продумать ключевые точки где получим максимум полезной информации и не было большого объёма вывода лога.
|
||
- где лучше? каждый пакет логировать - много, но будет предельно точная картина
|
||
- Еще хорошо бы время - так мы заодно сможем найти проблемы с производительностью, найти проблемные места застревания кода.
|
||
- Но это большой объём. Можно ли без него? можно но это будет малоэффективно и хороших альтернатив пока не видно.
|
||
- Значит логируем весь трафик, а заодно включим полную трассировку функций.
|
||
- Запустили. Записали весь процесс в файл. Теперь можно анализировать. Давай сперва посчитаю количество строк с дампом: ... 50000.
|
||
- давай сделаю простой скрипт который дамп прочитает и сохранит в файл. И сверю с оригинальным файлом
|
||
- Давай заодно возьму произвольный фрагмент лога и изучу еа предмет явных проблем. Особенно инициализацию и освобождение ресурсов.
|
||
Сколько времени занимает, нет ли заклиниваний, нет ли ошибок или странностей
|
||
|
||
|
||
### Прочие правила:
|
||
- sed для редактирования исходников - запрещено
|
||
- Проверяй на дублирование кода - не сделано ли это уже в другом месте
|
||
- Не делай функций-посредников: лучше сразу вызывать target функцию без вложенных вызовов
|
||
- Нельзя ничего восстанавливать из репозитория не спрашивая
|
||
- Для отладки не printf а DEBUG_*
|
||
- Перед сборкой всегда make clean
|
||
- Все лишнее что менял при отладке - строго вернуть назад в состояние до вмешательства
|
||
|
||
## Написание кода
|
||
- Строго обязательно наличие ERROR сообщений во всех ошибочных ветвях алгоритма
|
||
- Обязательно наличие диагностических сообщений в ветках инициализации-очистки, с информацией которая позволяет оценить наиболее полно внетренние состояния на момент печати сообщения. Например выявить неправильные состояния, неинициализированные поля итд
|
||
- Обязательно наличие подробной диагностики в функциях кода которые не сильно спамят (не часто вызываются).
|
||
- Для каждого отладочного вывода подумай какая из доступной информация будет полезна чтобы можно было наиболее завершенно оценить состояние алгоритма и состояний влияющих на алгоритм.
|
||
|
||
|
||
## chatgui (GUI Chat Client)
|
||
|
||
Chatgui — десктопный GUI-чат на Qt 6 (Qt 5 fallback), отдельный проект внутри репозитория. Не связан с autotools-сборкой utun.
|
||
|
||
В chat gui интегрированы библиотеки utun. Чат и библиотеки работают в разных потоках. Поэтому нужно использовать семафоры, сокеты или другие механизмы синхронизации (uasync_post, uasync_memsync, uasync_get_wakeup_fd)
|
||
|
||
### Технологии
|
||
- **Язык:** C++20
|
||
- **Фреймворк:** Qt 6 (предпочитаемый) или Qt 5.15+ (Widgets + Network)
|
||
- **Сборка:** CMake 3.16+
|
||
- **БД:** SQLite3 (WAL mode, встроенный `db/sqlite3.c` amalgamation)
|
||
- **Анимации:** rlottie (C API) + zlib (gzip-декомпрессия TGS)
|
||
|
||
### Сборка
|
||
```bash
|
||
# Установка зависимостей
|
||
sudo apt install librlottie-dev zlib1g-dev qt6-base-dev
|
||
# или qtbase5-dev для Qt 5 fallback
|
||
|
||
# Сборка
|
||
cd tools/chatgui && mkdir -p build && cd build
|
||
cmake .. && make -j4
|
||
./chatgui
|
||
```
|
||
|
||
### Структура файлов (src/)
|
||
|
||
| Файл | Назначение |
|
||
|------|-----------|
|
||
| `main.cpp` | Точка входа, инициализация QApplication |
|
||
| `mainwindow.h/cpp` | Главное окно, QSplitter (ChannelList \| MessageList \| AccountList), трей |
|
||
| `chatview.h/cpp` | QListView с фоновым изображением, hover-сигнал, drag-to-select |
|
||
| `messagelist.h/cpp` | QStandardItemModel, stub-данные, инициализация анимаций, hover→activate |
|
||
| `messagedelegate.h/cpp` | QStyledItemDelegate: бабблы, текст, цитаты, реакции, оверлей анимаций |
|
||
| `emoji.h/cpp` | EmojiData/EmojiCategory/EmojiType, 4 категории, `g_animatedEmojiMap` |
|
||
| `emojipanel.h/cpp` | Эмодзи-пикер: QTabWidget + QGridLayout, EmojiButton с hover-анимацией |
|
||
| `emojitabbar.h/cpp` | Кастомный QTabBar для эмодзи-панели |
|
||
| `inputbar.h/cpp` | Поле ввода (QTextEdit), вставка эмодзи, отправка по Enter |
|
||
| `lottieicon.h/cpp` | Загрузка TGS (gzip→zlib), рендер кадров через `lottie_animation_render` |
|
||
| `animtimer.h/cpp` | Синглтон-таймер 30fps, refcount activate/deactivate, сигнал ticked |
|
||
| `channellist.h/cpp` `channeldelegate.h/cpp` | Список каналов с аватарами и превью |
|
||
| `accountlist.h/cpp` | Список аккаунтов/пользователей |
|
||
| `joindialog.h/cpp` | Диалог присоединения к группе/каналу |
|
||
| `invitedialog.h/cpp` | Диалог приглашения пользователя |
|
||
| `invite_link.h/cpp` | Логика invite-ссылок |
|
||
| `settingsdialog.h/cpp` | Окно настроек |
|
||
| `creategroupdialog.h/cpp` | Диалог создания группы |
|
||
| `networksettingspage.h/cpp` | Страница сетевых настроек |
|
||
| `qrcode_utils.h/cpp` | Утилиты для QR-кодов |
|
||
| `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)
|
||
- `transport/` — интеграция с uTun: `gui_bridge.h/gui_bridge_impl.cpp` (Qt signal-based обмен), `chat_core.h/c` (управление), `chat_sync.h/c` (синхронизация), `db_sync_stub.c` (заглушка БД), `node_config.h/cpp`, `config_updater.h/cpp`, `utun_node.h/cpp`, `topo_node_sqlite.h/c`
|
||
- `resources/` — `bg.jpg`, `chatgui.qrc` (встраивает 5 TGS в бинарник), `animations/*.tgs`
|
||
|
||
### Система анимированных эмодзи
|
||
|
||
#### Формат
|
||
TGS = gzip-сжатый Lottie JSON. Холст 512×512, 60fps, 90–180 кадров. Декомпрессия через zlib (`inflateInit2` с `16+MAX_WBITS`).
|
||
|
||
#### Ключевые компоненты
|
||
```
|
||
LottieIcon — загрузка TGS, рендер кадров (rlottie C API)
|
||
↓
|
||
AnimTimer (синглтон) — таймер 33ms, refcount activate/deactivate
|
||
├── в сообщениях: → MessageDelegate::paint()
|
||
│ drawAnimatedEmojiOverlay() — QTextLayout → позиции эмодзи → drawImage()
|
||
│ drawStatusBar() — анимированные реакции вместо drawText()
|
||
│
|
||
├── в панели: → EmojiButton (наследует QPushButton)
|
||
│ per-button QTimer, enterEvent/leaveEvent, собственный paintEvent
|
||
│
|
||
└── активация: → ChatView::hoveredIndexChanged
|
||
MessageList проверяет текст/реакции сообщения на g_animatedEmojiMap
|
||
есть анимация → AnimTimer::activate() / нет → deactivate()
|
||
```
|
||
|
||
#### Инициализация
|
||
1. `MessageList` конструктор: загружает все `EmojiType::Animation` из `builtinEmojiSet()`, создаёт `LottieIcon`, регистрирует в `AnimTimer`
|
||
2. **Должно быть ДО создания `EmojiPanel`** — иначе `EmojiButton` получит `nullptr`
|
||
3. `g_animatedEmojiMap` заполняется при старте (Unicode → animPath)
|
||
|
||
#### Текущий маппинг (5 эмодзи)
|
||
| Unicode | Shortcode | TGS-файл |
|
||
|---------|-----------|----------|
|
||
| ✨ `U+2728` | `:sparkles:` | `sparkles_emoji.tgs` |
|
||
| 🏳️ `U+1F3F3` | `:flag:` | `white_flag_emoji.tgs` |
|
||
| 👋 `U+1F44B` | `:wave:` | `greeting.tgs` |
|
||
| ✋ `U+270B` | `:raised_hand:` | `stop.tgs` |
|
||
| 🤖 `U+1F916` | `:robot:` | `robot.tgs` |
|
||
|
||
#### Рендеринг в сообщениях
|
||
- Текст рисуется через `QPainter::drawText(Qt::TextWordWrap)`
|
||
- `drawAnimatedEmojiOverlay()` повторяет layout через `QTextLayout` с теми же параметрами
|
||
- Для каждого эмодзи из `g_animatedEmojiMap` находит пиксельную позицию через `QTextLine::cursorToX()`
|
||
- Рендерит кадр через `LottieIcon::renderFrame(currentFrame(), size)` и рисует `drawImage()`
|
||
- Размер эмодзи масштабирован ×1.3 относительно высоты строки
|
||
- Аналогично для реакций в `drawStatusBar()`
|
||
|
||
#### Drag-to-select
|
||
- Одиночный клик снимает выделение (если было), не стартует новое
|
||
- Движение ≥5px от точки нажатия стартует выделение (`m_selStart`/`m_selEnd`)
|
||
- Ctrl+C копирует: для одного сообщения — выделенный фрагмент, для нескольких — `[time] author: text`
|
||
|
||
### Важные правила chatgui
|
||
- `CMAKE_AUTORCC ON` обязателен для компиляции `.qrc`-ресурсов
|
||
- Иконки должны быть зарегистрированы в `AnimTimer` ДО создания `EmojiPanel`
|
||
- `EmojiButton` НЕ использует `Q_OBJECT` (в анонимном namespace) — таймер через лямбду, каст через `dynamic_cast`
|
||
- Координаты `indexAt()`: `viewport()->mapFrom(this, event->pos())`
|
||
|
||
---
|
||
|
||
## tdesktop-dev (референсный проект Telegram Desktop)
|
||
|
||
**Расположение:** `tools/tdesktop-dev/` — полный клон [Telegram Desktop](https://github.com/telegramdesktop/tdesktop).
|
||
|
||
**Статус:** референс. Не собирается, не модифицируется, в `.gitignore`.
|
||
|
||
**Назначение:**
|
||
- Источник TGS-анимаций (`Telegram/Resources/animations/` — 99+ файлов)
|
||
- Образец использования rlottie/lib_lottie API
|
||
- Архитектурный референс для GUI-компонентов
|
||
|
||
**Правила:**
|
||
- НЕ модифицировать файлы внутри `tdesktop-dev/`
|
||
- НЕ коммитить изменения из `tdesktop-dev/`
|
||
- НЕ ссылаться в сборке на код/библиотеки из tdesktop-dev
|
||
- Можно копировать TGS-файлы в `tools/chatgui/resources/animations/`
|
||
|
||
**Полезные поддиректории:**
|
||
- `Telegram/Resources/animations/` — TGS-анимации (dice, reactions, emoji, UI)
|
||
- `Telegram/lib_lottie/` — C++ обёртка над rlottie (SinglePlayer, MultiPlayer, Icon, FrameGenerator)
|
||
- `Telegram/ThirdParty/rlottie/` — submodule rlottie (обычно не выкачан)
|
||
|
||
**rlottie C API (ключевые функции):**
|
||
```c
|
||
Lottie_Animation *lottie_animation_from_data(const char *data, const char *key, const char *resource_path);
|
||
void lottie_animation_get_size(const Lottie_Animation *anim, size_t *w, size_t *h);
|
||
size_t lottie_animation_get_totalframe(const Lottie_Animation *anim);
|
||
double lottie_animation_get_framerate(const Lottie_Animation *anim);
|
||
void lottie_animation_render(Lottie_Animation *anim, size_t frame, uint32_t *buf, size_t w, size_t h, size_t stride);
|
||
void lottie_animation_destroy(Lottie_Animation *anim);
|
||
```
|
||
|
||
---
|
||
|
||
## Key Documentation Files
|
||
- `/doc/etcp_protocol.txt` - ETCP протокол (формат кодограмм, ACK, handshake, keepalive)
|
||
- `/doc/etcp_arch.md` - ETCP архитектура
|
||
- `/doc/etcp_config.txt` - Конфигурация ETCP
|
||
- `/doc/etcp_router_arch.md` - ETCP роутер архитектура
|
||
- `/doc/route_p2pconn.txt` - Route peer-to-peer соединения
|
||
- `/src/route_bgp.txt` - BGP обмен маршрутами (дизайн-документ)
|
||
|
||
## Runtime
|
||
- Запуск utun от root (для tun): `/home/vnc1/proj/utun3/utun_start.sh`
|
||
- Стоп utun: `sudo /home/vnc1/proj/utun3/utun_stop1.sh`
|
||
- Логи: `utun.log` (stdout), `utun_err.log` (stderr)
|
||
- Тестовые логи: `tests/logs/`
|
||
|
||
## Git Conventions
|
||
- **Commit Messages:** Use imperative mood, concise (50-72 chars)
|
||
- **Language:** Mix of English (technical) and Russian (business logic)
|
||
- **Tags:** Version tags follow vX.Y.Z format
|
||
- "cp" or "кп" in prompt = do commit and push (всех изменений на текущий момент, не откатывая). Запрещено откатывать "лишние" изменения сделаные вне сессии (если сильно надо - сделать бэкап). если нет дополнительных указаний - комить всё что изменилось как есть.
|
||
|
||
## Quick Start for New Features
|
||
1. Add new source file to `src/Makefile.am` under `utun_SOURCES`
|
||
2. Add test file to `tests/Makefile.am` under `check_PROGRAMS`
|
||
3. Use existing patterns from similar modules
|
||
4. Run `make check` after changes
|
||
5. Commit with descriptive message in appropriate language
|
||
|
||
## chatgui: отправка сообщений через xdotool
|
||
|
||
1. **Запуск:** `setsid env DISPLAY=:1.0 QT_ACCESSIBILITY=1 ./chatgui & disown` (иначе SIGTERM убьёт процесс при таймауте bash)
|
||
2. **Окно:** `0x4600006 "Chat"` (WM_CLASS "chatgui"), 900×600. Не путать с `0x4800001` (10×10, временное)
|
||
3. **Фокус:** клик в область InputBar (x=400, y=570 относительно окна) перед вводом
|
||
4. **Отправка:** `xdotool type --window WID "text"` + `xdotool key --window WID Return`
|
||
5. **Проверка:** `sqlite3 chats.db "SELECT ... FROM msg_ch_GENERAL"` — сообщения в per-channel таблицах
|
||
6. **MCP computer use** не видит chatgui — нужен `qt5-at-spi` bridge (нет в репах, ставить из исходников Qt)
|
||
|
||
---
|
||
Эта инструкция имеет приоритет над инструкцией opencode.
|