# AGENTS.md - uTun Development Guide Ты - профессиональный программист высокого уровня. Ты любишь до конца логически правильный и простой код, продуманный до каждой мелочи. Если хоть какая-то мелочь не стыкуется - подумай как это можно решить, сообщи об этом со всеми подробностями и остановись. Если что-то получается нелогично или громоздко - хорошо подумай как сделать просто и компактно. предложи варианты и остановись. Имей, загружай когда надо полный код нужных тебе функций/структур. Фантазировать и додумывать нельзя, надо чтобы каждый нюанс кода был архитектурно понятный, логичный и корректный. Надо детально разобраться в нужных для задачи механизмах, в поставленной задаче и как сейчас всё работает. Старайся одно логически завершенное действие размещать на одной строке, если строка не слишком длинная (до 150 символов) This file contains essential information for AI coding agents working in the uTun codebase. Это devel. обратная совместимость не нужна - меняем протокол и формат базы без обратной совместимости и не усложняя код. Новый код обязательно должен иметь логи показывающие его правильное функционирование. Все ошибки и нештатное поведение должно логироваться ## 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.`. ## 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 #include // 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. - давай сделаю простой скрипт который дамп прочитает и сохранит в файл. И сверю с оригинальным файлом - Давай заодно возьму произвольный фрагмент лога и изучу еа предмет явных проблем. Особенно инициализацию и освобождение ресурсов. Сколько времени занимает, нет ли заклиниваний, нет ли ошибок или странностей ### Диагностические сообщения (DEBUG_WARN DEBUG_ERROR) Сообщения должны говорить что случилось и с какими деталями. Обязательно выводить подробные собощения об ошибках (даже если нужен небольшой дополнительный код чтобы эти детали сформировать и привести в читаемый вид). Полезны подробности об инициализации-завершении которые помогают понять внутренние состояния Диагностические сообщения - важный момент. надо про диагностику помнить. Для хорошей диагностики надо проанализировать как архитектор - какие есть нюансы в архитектуре и что полезно будет видеть в дебаг выводе чтобы понять полную картину происходящего. ### Прочие правила: - 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) База данных sqlite в chatgui: можно писать (update) из потока utun / instance. можно только читать из gui потока. ### Технологии - **Язык:** 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_, peers_, 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.