Files
utun2/tools/chatgui/chatgui_doc.md
T

253 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# chatgui
## 1. Назначение
Десктопный GUI-чат (Telegram-подобный) со встроенным P2P uTun-узлом. Приложение объединяет полнофункциональный интерфейс обмена сообщениями и децентрализованный транспортный слой в едином процессе. Рассчитан на работу без центральных серверов — вся маршрутизация, синхронизация и доставка сообщений идут напрямую между узлами по ETCP-протоколу.
Язык интерфейса: русский или английский. По умолчанию используется первый поддерживаемый язык из списка языков интерфейса ОС;
если поддерживаемых языков нет, используется английский. Выбор в «Настройки → Профиль → Язык интерфейса»:
«Язык системы», English или Русский. Смена языка применяется после перезапуска, настройка хранится в `[gui] language=system|en|ru`.
Региональный формат дат и чисел остаётся системным. Диагностические дампы ядра сохраняют исходные имена полей.
Каталоги `translations/chatgui_en.ts` и `translations/chatgui_ru.ts` компилируются `lrelease` и встраиваются в приложение вместе
с `qtbase_ru.qm` для стандартных виджетов Qt. Для сборки нужны инструменты Qt Linguist и пакет переводов Qt
(Debian/Ubuntu: `qt6-tools-dev-tools`, `qt6-translations-l10n`; для Qt 5: `qttools5-dev-tools`, `qttranslations5-l10n`).
После добавления строк обновить каталоги из `tools/chatgui`:
`lupdate src -no-obsolete -locations relative -ts translations/chatgui_en.ts translations/chatgui_ru.ts`,
заполнить новые переводы и пересобрать. Проверка: `ctest --test-dir build -R test_gui_language --output-on-failure`.
## 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 (показать/скрыть/выход). Закрытие окна сворачивает в трей.
**Уведомления о сообщениях** (`src/message_notification.*`, `src/user_activity_monitor.*`): чужое новое сообщение
в канале или личной беседе показывает одно окно возле трея, если главное окно не активно. Загрузка истории не уведомляет:
`MSG_RECEIVED` содержит `[ch_id_len:1][ch_id:var][author_node_id:8][initial_sync:1]`.
Без активности уведомление остаётся; первый ввод запускает отсчёт 10 секунд, дальнейший ввод его не продлевает.
Новое сообщение заменяет содержимое и отменяет прежний отсчёт. Нажатие открывает соответствующий чат; крестик закрывает окно.
Windows использует `GetLastInputInfo`, macOS — CoreGraphics, X11 — опциональную библиотеку Xss (`libxss-dev`).
Wayland/XWayland в GNOME использует асинхронный `org.gnome.Mutter.IdleMonitor` через D-Bus. При нативном Qt Wayland
доступен также опциональный KF6/KF5 KIdleTime с установленным backend композитора; idle inhibitors могут ограничивать его события.
X11 idle time в Wayland-сессии не используется: он не гарантирует активность в других приложениях.
Если системный механизм недоступен, учитываются только события внутри ChatGUI; закрытие крестиком остаётся доступным.
При отсутствии координат трея выбирается угол доступной области экрана; нативный Wayland управляет позицией и порядком окон.
В X11/XWayland уведомление — отдельное overlay-окно (`override_redirect`) типа notification:
оконный менеджер не привязывает его к одному виртуальному столу, оно остаётся доступным при переключении столов.
Уведомление не является дочерним окном главного чата: сворачивание или рабочий стол главного окна не определяют его видимость.
На нативном Wayland поверхность пересоздаётся при новом сообщении, чтобы не сохранять прежний рабочий стол;
выбор текущего стола и возможность показа поверх других окон остаются политикой композитора.
Показ/скрытие и причины ограничений логируются в `general`; запуск отсчёта и первая активность — на уровне `debug`.
Проверка: `ctest --test-dir build -R 'test_message_(notification|events)' --output-on-failure`.
При доступном X11/XWayland: `./build/test_message_notification_x11` проверяет overlay после показа, обновления и скрытия.
**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
```