18 KiB
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-анимаций:
- Gzip-декомпрессия через zlib (
inflateInit2с16+MAX_WBITS) - Парсинг Lottie JSON через rlottie C API (
lottie_animation_from_data) - Рендер кадра:
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
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