You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

8.3 KiB

AGENTS.md — chatgui-android (Android P2P Chat)

Android-версия чатгуи: P2P чат на STCP (TCP), UI на Jetpack Compose (Kotlin). C-ядро: libutun_lite (выборочная компиляция нужных .c из lib/ и src/).

Весь UDP-стек (ETCP, BBR, loadbalancer, NAT, routing, TUN) исключён. Транспорт: только STCP (X25519 + AES-CCM поверх TCP).

Состав проекта (5 частей)

tools/chatgui-android/
├── libutun_lite/           # C-ядро (статическая библиотека)
│   ├── CMakeLists.txt
│   ├── utun_sources.cmake   # список компилируемых .c файлов
│   ├── utun_config_api.h/c   # конфиг-провайдер (Kotlin → C)
│   └── invite_link_c.h/c     # invite-ссылки (encode/decode, совместимы с десктопом)
│
├── headless/                # CLI для Linux (тестирование без Android)
│   ├── CMakeLists.txt
│   ├── headless_main.c       # точка входа, uasync event loop
│   └── headless_control.c/h  # управляющий TCP-сокет (JSON/text протокол)
│
├── jni_bridge/              # JNI прослойка C ↔ Kotlin
│   └── android_jni_bridge.c/h  # C API + JNI-функции (компилятся только для Android)
│
├── app/                     # Android приложение (Gradle + NDK + Compose)
│   ├── build.gradle.kts
│   └── src/main/
│       ├── AndroidManifest.xml
│       ├── cpp/              # NDK: jni_bridge + libutun_lite → libutun.so
│       │   └── CMakeLists.txt
│       ├── java/com/utun/chat/
│       │   ├── ChatApplication.kt     # Application, инициализация
│       │   ├── MainActivity.kt        # Compose UI, навигация экранов
│       │   ├── data/
│       │   │   ├── NativeLib.kt       # JNI-обёртка
│       │   │   ├── ChatRepository.kt  # репозиторий (JNI + JSON)
│       │   │   ├── InviteLink.kt      # парсер utun://base64blob
│       │   │   ├── ConfigProvider.kt  # конфиг из DataStore
│       │   │   ├── LogManager.kt      # лог-менеджер
│       │   │   └── ServerEntry.kt     # модели данных
│       │   ├── viewmodel/
│       │   │   └── ChatViewModel.kt   # StateFlow для UI
│       │   ├── ui/screens/
│       │   │   ├── ChannelListScreen.kt  # список каналов + join/create
│       │   │   ├── ChatScreen.kt         # сообщения + ввод
│       │   │   ├── JoinChannelDialog.kt  # диалог подключения по invite
│       │   │   ├── QrScanScreen.kt       # CameraX + ML Kit QR-сканер
│       │   │   ├── SettingsScreen.kt     # настройки
│       │   │   └── LogScreen.kt          # лог-просмотр
│       │   ├── ui/components/
│       │   │   └── MessageBubble.kt      # бабблы сообщений + InputBar
│       │   └── headless/
│       │       └── HeadlessService.kt    # фоновый сервис
│       └── res/
│
└── doc/                     # документация
    ├── AGENTS.md            # этот файл
    ├── ARCHITECTURE.md      # подробная архитектура
    └── IMPL_PLAN.md         # план реализации по этапам

Технологии

Слой Язык Фреймворк
C-ядро C99 OpenSSL, SQLite3
Bridge C + JNI Android NDK 29
Android UI Kotlin Jetpack Compose, Material3, CameraX, ML Kit
Сборка C CMake 3.16+ GCC (Linux) / Clang (Android NDK)
Сборка APK Gradle 8.x AGP 8.x, Kotlin 1.9

Сборка

Headless (Linux, для отладки сетевого стека)

cd tools/chatgui-android && mkdir -p build && cd build
cmake .. && make -j4
./headless/headless

APK (Android)

cd tools/chatgui-android
export ANDROID_HOME=/home/user/Android/Sdk
./gradlew assembleDebug
# APK: app/build/outputs/apk/debug/app-debug.apk

Прошивка на телефон

# Проверить доступные устройства
adb devices

# Установить APK
adb -s <serial> install -r app/build/outputs/apk/debug/app-debug.apk

# Смотреть логи
adb logcat -s utun:*

# Control-сокет (при запущенном HeadlessService):
adb forward tcp:9999 tcp:9999
nc localhost 9999
> {"id":1,"cmd":"status"}
> {"id":2,"cmd":"join","link":"utun://..."}

Логирование через logreceiver (только Android)

Debug-сообщения с телефона дублируются через UDP на приёмник tools/logreceiver/.

Запуск (всегда через скрипт, до старта utun):

tools/logreceiver/logreceiver_restart.sh

Скрипт ротирует логи (история 10 запусков: .log → .log.1 → … → .log.10), убивает старый демон и запускает новый на 0.0.0.0:9999, вывод в logreceiver_output.log. При каждом запуске логи фиксируются в истории и начинается свежий лог.

В конфиге Android:

log_udp_ip = <ip хоста>
log_udp_port = 9999

Ключевые файлы для доработок

C-слой

  • libutun_lite/invite_link_c.h/c — invite-ссылки (encode/decode, бинарный формат идентичен десктопу tools/chatgui/src/invite_link.cpp)
  • jni_bridge/android_jni_bridge.h/c — bridge API: utun_bridge_join_channel(), utun_bridge_send_message(), JNI-функции
  • libutun_lite/utun_config_api.h/c — конфиг-провайдер (Kotlin → C через коллбэки)
  • libutun_lite/utun_sources.cmake — список всех .c файлов, компилируемых в libutun_lite

Kotlin-слой

  • data/InviteLink.kt — парсинг utun://base64blob, deriveNodeId() (SHA256 от pubkey), serializeAddrs()
  • data/NativeLib.kt — JNI-обёртка, все external fun native*
  • ui/screens/JoinChannelDialog.kt — диалог: ввод/вставка ссылки, debounce-декодинг, preview, Connect
  • ui/screens/QrScanScreen.kt — CameraX + ML Kit сканер, фильтрует utun:// ссылки
  • ui/screens/ChannelListScreen.kt — список каналов, кнопка Join (QrCode), кнопка Create
  • MainActivity.kt — навигация экранов, QrScan → JoinDialog flow

Headless

  • headless/headless_control.c — управляющий TCP-сокет, команды: join, connect, subscribe, debug_level
  • headless/headless_main.c — точка входа, парсинг аргументов, uasync event loop

Invite-ссылки (механика подключения к каналу)

Формат идентичен десктопной версии:

utun:// + base64(
    version(1B, 0x01) |
    channel_id(8B BE) |
    [header(1B: bits0-1=count-1, bits2-5=family_flags) | pubkey(32B) |
     addrs*(socketId(1B) | address(4B v4/16B v6) | port(2B BE))]+
)

Node ID вычисляется как SHA256(pubkey)[0:8] & 0x7FFFFFFFFFFFFFFF (совместимо с sc_derive_node_id_from_pubkey()).

Правила разработки

  • Все C-файлы: C99, стиль как в корневом AGENTS.md (4 пробела, snake_case, DEBUG_* макросы)
  • Все новые C-файлы добавлять в libutun_lite/utun_sources.cmake
  • Все новые Kotlin-файлы — Compose, Material3, coroutines/StateFlow
  • ViewModel не держит ссылки на Context
  • Логи в C — через debug_set_log_hook → bridge → Kotlin LogManager
  • Конфиг в C — через utun_config_provider_t коллбэки в Kotlin
  • Перед коммитом: головная C-сборка + ./gradlew assembleDebug