- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
217 lines
18 KiB
Markdown
217 lines
18 KiB
Markdown
# chatgui
|
||
|
||
## 1. Назначение
|
||
|
||
Десктопный GUI-чат (Telegram-подобный) со встроенным P2P uTun-узлом. Приложение объединяет полнофункциональный интерфейс обмена сообщениями и децентрализованный транспортный слой в едином процессе. Рассчитан на работу без центральных серверов — вся маршрутизация, синхронизация и доставка сообщений идут напрямую между узлами по ETCP-протоколу.
|
||
|
||
## 2. Архитектура
|
||
|
||
### 2.1. Уровни приложения
|
||
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ GUI (Qt 6/5 Widgets, C++20) │ поток GUI
|
||
│ ├─ MainWindow (QSplitter) │
|
||
│ ├─ ChannelList / MessageList │
|
||
│ ├─ MessageDelegate (бабблы+реакции) │
|
||
│ ├─ EmojiPanel (статика+анимация) │
|
||
│ └─ LottieIcon / AnimTimer │
|
||
├──────────────────────────────────────┤
|
||
│ GuiBridge (Qt signals ↔ uasync) │ очередь событий
|
||
│ gui_bridge_post / uasync_post │
|
||
├──────────────────────────────────────┤
|
||
│ Транспорт (C, поток uasync) │ поток uasync
|
||
│ ├─ UtunNode (std::thread + UTUN_INSTANCE)│
|
||
│ ├─ ChatCore (отправка, БД, invite) │
|
||
│ ├─ ChatSync (P2P синхронизация) │
|
||
│ ├─ MemberSync (мемберы через Merkle)│
|
||
│ └─ MerkleSync (Merkle-дерево, 5 ур.)│
|
||
├──────────────────────────────────────┤
|
||
│ libutun (C, статическая библиотека) │ uasync
|
||
│ ├─ uasync (event loop, таймеры) │
|
||
│ ├─ ETCP (надежная доставка, ACK) │
|
||
│ ├─ SecureChannel (X25519+AES-CCM) │
|
||
│ ├─ conn_mgr (управление подключ.) │
|
||
│ ├─ topo_node/topo_group (BGP) │
|
||
│ └─ ntp_time (синхронизация времени) │
|
||
├──────────────────────────────────────┤
|
||
│ SQLite3 (WAL mode) │ чтение+запись
|
||
│ ├─ DbManager (C++, read-only для GUI)│
|
||
│ └─ chat_core (C, write из uasync) │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
### 2.2. Потоковая модель
|
||
|
||
Приложение работает в двух потоках:
|
||
|
||
- **Поток GUI** — QApplication, все виджеты, отрисовка, QTimer для анимаций (AnimTimer 30fps). Только *чтение* из SQLite через DbManager.
|
||
- **Поток uasync** — UTUN_INSTANCE в выделенном std::thread. Вся сеть, криптография, ETCP, синхронизация, *запись* в SQLite. Один uasync-экземпляр на поток (правило u_async).
|
||
|
||
**Мост между потоками (gui_bridge):**
|
||
- **uasync → GUI:** `gui_bridge_post(event_type, data, len)` — сериализованные события в Qt main event loop через `QMetaObject::invokeMethod` с `Qt::QueuedConnection`. 10 типов событий: MSG_RECEIVED, CONNECT_RESULT, NEW_PEER, CHANNEL_UPDATED, MEMBERS_CHANGED, MY_NODE_ID, AUTO_CONNECT_STATUS, CHANNEL_PEERS_ONLINE, DB_READY, STATUS_REFRESH.
|
||
- **GUI → uasync:** `gui_bridge_post_uasync_fn(fn, arg)` — выполнение функции в uasync-потоке через `uasync_post`. Используется для отправки сообщений, создания каналов, invite-подключений.
|
||
|
||
Всё взаимодействие с БД (INSERT/UPDATE/DELETE) выполняется только из uasync-потока. GUI читает через DbManager (read-only), синхронизация не требуется — SQLite в WAL-режиме обеспечивает одновременное чтение.
|
||
|
||
## 3. Ключевые компоненты
|
||
|
||
### 3.1. GUI-слой
|
||
|
||
**MainWindow** (`src/mainwindow.h`) — главное окно 900×600. Горизонтальный QSplitter из трёх панелей:
|
||
- **ChannelList** — список каналов (QListView + QStandardItemModel), контекстное меню (invite, join, create group, settings).
|
||
- **MessageList** — список сообщений канала (ChatView + QStandardItemModel), поле ввода InputBar, EmojiPanel.
|
||
- **AccountList** — список участников канала (MemberListModel), онлайн-статус, имена.
|
||
|
||
Системный трей: QSystemTrayIcon + QMenu (показать/скрыть/выход). Закрытие окна сворачивает в трей.
|
||
|
||
**ChatView** (`src/chatview.h`) — QListView с фоновым изображением и drag-to-select. При движении >5px от точки нажатия стартует выделение сообщений. Ctrl+C копирует: для одного — выделенный текст, для нескольких — `[time] author: text`. Сигнал `hoveredIndexChanged` используется для активации анимаций эмодзи в MessageList.
|
||
|
||
**MessageList / MessageDelegate** — баббл-интерфейс сообщений:
|
||
- Аватары (32×32, цвет зависит от node_id), бабблы со скруглёнными углами (r=10px) и хвостиком.
|
||
- Цитаты: цветная полоса + мини-аватар + автор + текст.
|
||
- Реакции (эмодзи) в status bar под бабблом.
|
||
- Inline-анимированные эмодзи: при hover над сообщением — перебор кадров из LottieIcon, отрисовка поверх текста через QTextLayout.
|
||
- Растягивающийся InputBar (QTextEdit, Enter — отправка, Shift+Enter — перевод строки).
|
||
|
||
**EmojiPanel** (`src/emojipanel.h`) — QTabWidget с категориями (смайлики, жесты, символы, анимации). Каждая категория — QGridLayout из EmojiButton (QPushButton без Q_OBJECT, hover-анимация через per-widget QTimer). Статические эмодзи — Unicode символы. Анимированные — TGS-файлы, рендерятся в EmojiButton::paintEvent.
|
||
|
||
**LottieIcon** (`src/lottieicon.h`) — загрузка и рендер TGS-анимаций:
|
||
1. Gzip-декомпрессия через zlib (`inflateInit2` с `16+MAX_WBITS`)
|
||
2. Парсинг Lottie JSON через rlottie C API (`lottie_animation_from_data`)
|
||
3. Рендер кадра: `lottie_animation_render` → ARGB32 буфер → QImage
|
||
|
||
5 встроенных TGS-анимаций (вшиты в бинарник через chatgui.qrc): sparkles, white_flag, greeting, stop_hand, robot.
|
||
|
||
**AnimTimer** (`src/animtimer.h`) — синглтон-таймер 30fps с refcount-механизмом:
|
||
- `activate()` / `deactivate()` увеличивают/уменьшают счётчик ссылок.
|
||
- Срабатывает только когда есть активные анимации в видимых сообщениях.
|
||
- Сигнал `ticked` обновляет кадры всех зарегистрированных LottieIcon.
|
||
|
||
**Invite-ссылки** (`src/invite_link.h`) — кодирование/декодирование приглашений в формат `utun://...` (base64, содержит channel_id, pubkey, список адресов). QR-коды через zxing-cpp.
|
||
|
||
### 3.2. Транспортный слой
|
||
|
||
**UtunNode** (`transport/utun_node.h`) — C++ обёртка над UTUN_INSTANCE:
|
||
- Запускает выделенный std::thread с `runLoop()` — создаёт UTUN_INSTANCE, вызывает `utun_instance_start()`, входит в uasync event loop.
|
||
- Приём сообщений: ETCP callback → `QByteArray` → сигнал `messageReceived(uint64_t src, QByteArray data)`.
|
||
- Отправка: `send(dstNodeId, data)` через ETCP поверх экземпляра uTun.
|
||
- Конфигурация: NodeConfig (INI-файл), генерация X25519/Ed25519 ключей при первом запуске.
|
||
- Включает отладку NTP-синхронизации для временных меток сообщений.
|
||
|
||
**NodeConfig** (`transport/node_config.h`) — управление INI-конфигом uTun-узла:
|
||
- Генерация ключей (X25519 + Ed25519), сохранение/загрузка.
|
||
- Секции `[server]` и `[client]` для подключения к другим узлам.
|
||
- `[gui]` секция: путь к БД, настройки отладки.
|
||
- ConfigUpdater — утилита для программного изменения конфиг-файлов (append/replace).
|
||
|
||
**ChatCore** (`transport/chat_core.h`) — центральный API чата в потоке uasync:
|
||
- `chat_core_submit_message` — отправка сообщения: сохранение в локальную БД (таблица `msg_<channel_id>`), рассылка онлайн-пирам через etcp_send.
|
||
- `chat_core_create_channel` — создание канала: генерация X25519/Ed25519 ключей канала, подпись Ed25519, запись в `channels`, членство владельца.
|
||
- `chat_core_connect_from_invite` — подключение к пиру из invite-ссылки.
|
||
- `chat_core_connect_auto` — авто-подключение к узлу из SQLite (topo_node), коллбэк с результатом.
|
||
- Работа с БД: цепочка хешей (chain hash = SHA256(prev_hash || timestamp || data_hash)), список каналов, список пиров.
|
||
|
||
**ChatSync** (`transport/chat_sync.h`) — P2P синхронизация каналов:
|
||
- ETCP-сервисы: `0x30` (chat_sync — синхронизация каналов), `0x31` (member_sync — синхронизация участников).
|
||
- Протокол сообщений: INIT_SYNC → INIT_RESP → SEND_DATA ↔ PUSH+ACK_PUSH → SYNC_DONE.
|
||
- Batch-загрузка: до 32 сообщений за запрос, sparse-синхронизация (до 16 диапазонов).
|
||
- Таймаут пира: 5 секунд.
|
||
- Auto-connect: параллельное подключение до 10 узлов, останавливается при 3 успешных. Переключение группы при смене канала.
|
||
|
||
**MemberSync** (`transport/member_sync.h`) — синхронизация участников канала на основе Merkle-деревьев:
|
||
- Данные: таблицы `peers_<channel_id>`, `nodes`, `node_addresses`.
|
||
- Хеш мембера = SHA256(node_id || x25519 || ed25519 || join_sig || join_ts || update_sig || update_ts || addrs).
|
||
- Автоматический пересчёт дерева при добавлении/удалении/обновлении мембера.
|
||
- Онлайн-статус: `member_sync_set_online(node_id, 0/1)`.
|
||
|
||
**MerkleSync** (`transport/merkle_sync.h`) — универсальный протокол синхронизации на Merkle-деревьях:
|
||
- 5-уровневое префиксное дерево над 64-битными ключами (node_id). 32 бакета на уровень (по 5 бит).
|
||
- SHA256-хеши бакетов. Два пира обмениваются хешами, находят различающиеся бакеты, передают только их.
|
||
- Wire-протокол: MSG_HASHES → MSG_REQUEST → MSG_BATCH, рекурсивно до совпадения хешей.
|
||
- Таймаут 10s, 3 ретрая. Фоновая проверка консистентности (`merkle_sync_bg_check`).
|
||
- Не зависит от типа данных — потребитель предоставляет три коллбэка (update_bucket_hash, get_items, apply_items). member_sync адаптирует это под мемберов каналов.
|
||
|
||
### 3.3. База данных
|
||
|
||
**DbManager** (`db/db_manager.h`) — C++/Qt обёртка над SQLite3 (read-only для GUI-потока):
|
||
- **Схема:** `channels` (каналы с ключами X25519/Ed25519, подписи), `msg_<channel_id>` (per-channel таблицы сообщений с chain_hash), `peers_<channel_id>` (участники), `nodes` (узлы), `node_addresses`, `accounts`, `ui_state`, `merkle_tree_hash`.
|
||
- Чтение: `getChannels()`, `getMessages()`, `getChannelMembers()`, `loadNodeInfo()`, `getAccounts()`.
|
||
- Методы для GUI: список каналов, сообщения с пагинацией, участники, онлайн-статус.
|
||
- Sync-операции (курсоры): `syncListChannels()`, `syncCount()`, `syncChainHashAt()`, `syncCursorOpen/Next/Close()`.
|
||
- Проверка целостности: `integrityCheckQuick()` (PRAGMA quick_check), `integrityCheckFull()` (PRAGMA integrity_check), `integrityOptimize()` (PRAGMA optimize).
|
||
|
||
## 4. Сборка
|
||
|
||
**Система сборки:** CMake 3.16+
|
||
**Стандарты:** C++20 (GUI), C99 (транспорт/libutun)
|
||
**Зависимости:**
|
||
- Qt 6 (Widgets + Network) или Qt 5.15+
|
||
- rlottie (анимированные эмодзи)
|
||
- zlib (gzip-декомпрессия TGS)
|
||
- OpenSSL (X25519, Ed25519, SHA256, AES-CCM)
|
||
- zxing-cpp (QR-коды, встроен как submodule)
|
||
|
||
**Структура сборки:**
|
||
- `libutun/` — статическая библиотека uTun: все исходники из `src/` (кроме utun.c) + lib/ (uasync, ll_queue, memory_pool, etc) + транспорт (chat_sync, member_sync, merkle_sync)
|
||
- `chatgui` — финальный бинарник: GUI-исходники + транспортные C++/C файлы + SQLite3 amalgamation
|
||
- Платформенный TUN: `tun_linux.c` / `tun_freebsd.c` / `tun_windows.c`
|
||
|
||
```bash
|
||
mkdir -p build && cd build
|
||
cmake .. && make -j4
|
||
./chatgui
|
||
```
|
||
|
||
## 5. Файловая структура
|
||
|
||
```
|
||
tools/chatgui/
|
||
├── CMakeLists.txt # проект CMake
|
||
├── build.sh / build.bat # скрипты сборки
|
||
├── src/ # GUI-слой (Qt C++)
|
||
│ ├── main.cpp # точка входа, QApplication
|
||
│ ├── mainwindow.cpp # главное окно, трей
|
||
│ ├── channellist.cpp # список каналов
|
||
│ ├── chatview.cpp # QListView с фоном и drag-to-select
|
||
│ ├── messagelist.cpp # модель сообщений, инициализация анимаций
|
||
│ ├── messagedelegate.cpp # отрисовка бабблов, цитат, реакций, эмодзи
|
||
│ ├── inputbar.cpp # поле ввода + кнопка эмодзи
|
||
│ ├── emojipanel.cpp # QTabWidget с категориями эмодзи
|
||
│ ├── emojitabbar.cpp # кастомный QTabBar
|
||
│ ├── emoji.cpp # данные эмодзи, builtinEmojiSet()
|
||
│ ├── lottieicon.cpp # загрузка TGS, рендер через rlottie
|
||
│ ├── animtimer.cpp # синглтон-таймер 30fps с refcount
|
||
│ ├── accountlist.cpp # список участников канала
|
||
│ ├── memberlistmodel.cpp # модель для AccountList
|
||
│ ├── invite_link.cpp # кодирование/декодирование utun:// ссылок
|
||
│ ├── invitedialog.cpp # диалог приглашения
|
||
│ ├── joindialog.cpp # диалог входа по invite-ссылке
|
||
│ ├── settingsdialog.cpp # окно настроек
|
||
│ ├── networksettingspage.cpp # страница сетевых настроек
|
||
│ ├── databasesettingspage.cpp # настройки БД
|
||
│ ├── statuspage.cpp # страница статуса
|
||
│ ├── creategroupdialog.cpp # создание группы
|
||
│ └── qrcode_utils.cpp # генерация QR-кодов
|
||
├── transport/ # транспортный слой (C/C++)
|
||
│ ├── utun_node.cpp # C++ обёртка UTUN_INSTANCE в std::thread
|
||
│ ├── node_config.cpp # INI-конфиг узла (ключи, серверы, клиенты)
|
||
│ ├── config_updater.cpp # утилита редактирования INI-файлов
|
||
│ ├── gui_bridge_impl.cpp # мост uasync↔Qt (10 типов событий)
|
||
│ ├── chat_core.c # центральный API чата (отправка, БД, invite)
|
||
│ ├── chat_sync.c # P2P синхронизация каналов (ETCP 0x30)
|
||
│ ├── member_sync.c # синхронизация мемберов через Merkle
|
||
│ └── merkle_sync.c # универсальный Merkle-протокол синхронизации
|
||
├── db/ # база данных
|
||
│ ├── db_manager.h/cpp # C++/Qt обёртка SQLite3 (read-only для GUI)
|
||
│ └── sqlite3.c/h # SQLite3 amalgamation (из ../../lib/)
|
||
├── libutun/ # сборка статической библиотеки uTun
|
||
│ └── CMakeLists.txt # uasync + utun = все .c из lib/ и src/
|
||
├── resources/ # ресурсы
|
||
│ ├── chatgui.qrc # Qt resource file (TGS вшиты в бинарник)
|
||
│ └── animations/ # TGS-анимации (5 шт.)
|
||
└── doc/ # документация
|
||
├── desc.txt # описание схемы БД
|
||
└── db_schema.md # детальная схема таблиц SQLite
|
||
```
|