docs: update file inventory and module header contracts

Refresh both AGENTS guides and clarify module purpose, usage, ownership, threading, return values and wire formats in headers. Remove the unused timeout_heap freed_count field and unimplemented getter.
This commit is contained in:
evgeny committed 2026-10-04 13:10:01 +02:00
1 parent c19eff67f6
commit a97e8bcc1f
118 files changed
+628 -406

No files matched your search

+36 -8
View File
@@ -19,8 +19,12 @@ tools/chatgui-android/
│ ├── instance_lite.h/c # жизненный цикл (старт/стоп/рестарт, ключи)
│ ├── utun_config_api.h/c # конфиг-провайдер (Kotlin → C)
│ ├── invite_link_c.h/c # старая копия парсера; .c не входит в UTUN_SOURCES
│ ├── voice_recorder.h/c # запись голосовых (PCM→Opus→канал)
│ └── attachment_sender.h/c # отправка файлов в канал
│ ├── voice_recorder.h/c # накопление PCM; voice/file подготовка через общий attachment_send
│ ├── attachment_sender.h/c # отправка обычных файлов в канал
│ ├── photo_sender.h/c # отправка готовых изображений в канал
│ ├── video_sender.h/c # готовый MP4 → attachment_send (канал/PM)
│ ├── standby.h/c # фоновые ACTIVE/SLEEP интервалы и отменяемое ожидание
│ └── tests/test_standby.c # тесты duty-cycle
│
├── headless/ # CLI для Linux (тестирование без Android)
│ ├── CMakeLists.txt
@@ -28,7 +32,8 @@ tools/chatgui-android/
│ └── headless_control.c/h # управляющий TCP-сокет (JSON/text протокол)
│
├── jni_bridge/ # JNI прослойка C ↔ Kotlin
│ └── android_jni_bridge.c/h # C API + JNI-функции (компилятся только для Android)
│ ├── android_jni_bridge.c/h # C API; JNI-функции — только Android
│ └── android_udp_log.c/h # UDP-лог: общий буфер, flush в uasync
│
├── app/ # Android приложение (Gradle + NDK + Compose)
│ ├── build.gradle.kts
@@ -45,20 +50,24 @@ tools/chatgui-android/
│ │ │ ├── InviteLink.kt # парсер utun://base64blob
│ │ │ ├── ConfigProvider.kt # конфиг из DataStore
│ │ │ ├── LogManager.kt # лог-менеджер
│ │ │ └── ServerEntry.kt # модели данных
│ │ │ ├── ServerEntry.kt # модель listen-сокета
│ │ │ ├── CallAudioEngine.kt # capture/playback звонка через native voice stack
│ │ │ ├── RadioAudioEngine.kt # capture/playback и PTT рации
│ │ │ └── UtunConnectionService.kt # Android Telecom ConnectionService для P2P-звонков
│ │ ├── viewmodel/
│ │ │ └── ChatViewModel.kt # StateFlow для UI
│ │ ├── ui/screens/
│ │ │ ├── ChannelListScreen.kt # список каналов + join/create
│ │ │ ├── ChatScreen.kt # сообщения + ввод
│ │ │ ├── JoinChannelDialog.kt # диалог подключения по invite
│ │ │ ├── QrScanScreen.kt # CameraX + ML Kit QR-сканер
│ │ │ ├── QrScannerPreview.kt # CameraX + ML Kit QR-сканер
│ │ │ ├── SettingsScreen.kt # настройки
│ │ │ └── LogScreen.kt # лог-просмотр
│ │ ├── ui/components/
│ │ │ └── MessageBubble.kt # бабблы сообщений + InputBar
│ │ └── headless/
│ │ └── HeadlessService.kt # фоновый сервис
│ │ ├── HeadlessService.kt # foreground-service фонового ядра
│ │ └── BootReceiver.kt # запуск фонового сервиса после загрузки устройства
│ └── res/
│
└── doc/ # документация
@@ -263,15 +272,27 @@ port=9999
- `../../src/chat/invite_link.c/h` — Общий C-код формата invite-ссылок; Android разбирает ссылки в `data/InviteLink.kt`.
Старый `libutun_lite/invite_link_c.c` не компилируется текущим списком источников
- `libutun_lite/utun_config_api.h/c` — Поставщик конфигурации из Kotlin в C-ядро через callback-интерфейс (get_string, get_int64, get_int)
- `libutun_lite/voice_recorder.h/c` — Запись голосовых сообщений: накопление PCM-сэмплов с компрессором, кодирование в Opus-файл, отправка в канал через chat_core
- `libutun_lite/voice_recorder.h/c` — Накопление PCM 48 kHz mono с компрессором; stop передаёт запись в общий attachment_send для фонового кодирования и публикации в канал/PM
- `src/call/call_audio.h/c` (+ `voice_jitter.cpp`, `call_tones.c`, SoundTouch) — единый голосовой стек звонка (`libutun_voice`), собирается через `src/call/voice_sources.cmake`; Opus encode (PCM→peer) и decode + адаптивный джиттер-буфер + time-stretch (PCM отдаётся через `nativeCallAudioPull`). Аудио I/O в Kotlin (AudioRecord/AudioTrack)
- `libutun_lite/attachment_sender.h/c` — Отправка файлов в канал: копирование в media-директорию и регистрация через chat_core (media_index → db_sync)
- `libutun_lite/photo_sender.h/c` — Отправка готового изображения в канал с MIME-типом и размерами; подготовка картинки выполняется в Android
- `libutun_lite/video_sender.h/c` — Отправка подготовленного MP4 в канал/PM через attachment_send; задача владеет временным cache-файлом
- `libutun_lite/standby.h/c` — ACTIVE/SLEEP интервалы фонового режима, callbacks смены фазы и отменяемые wait handles
- `jni_bridge/android_udp_log.h/c` — Потокобезопасный буфер логов; timer flush привязан к текущему uasync и снимается при restart
- `libutun_lite/utun_sources.cmake` — Общий список источников: `lib/*.c` и рекурсивный `src/*.c` подхватываются автоматически;
файлы самой обёртки перечислены в `_cfg_src`, исключения — через `list(FILTER/REMOVE_ITEM)`
### Kotlin-слой
- `data/NativeLib.kt` — Kotlin-обёртка над C-библиотекой: все вызовы из Kotlin транслируются в JNI-функции
- `data/CallAudioEngine.kt` — Аудио-движок звонка: AudioRecord/AudioTrack, audio-focus, потоки захвата (feed) / воспроизведения (pull из C-стека)
- `data/RadioAudioEngine.kt` — Аудио-движок рации: AudioRecord/AudioTrack, feed/pull native-стека и управление capture/PTT
- `data/RadioPttHolds.kt` — Отдельные владельцы ручного PTT: кнопка, overlay и volume-клавиши; отпускание одного не снимает остальные
- `data/RadioOverlayService.kt` — Плавающее окно PTT поверх других приложений
- `data/ConversationTarget.kt` — Типизированный target канала/PM для асинхронных операций
- `data/AudioRecorderManager.kt` — Android-захват PCM голосового сообщения и управление native voice_recorder
- `data/CallController.kt` / `CallState.kt` — Управление состоянием и действиями P2P-звонка
- `data/CallAudioRouter.kt` — Выбор аудиомаршрута звонка: earpiece/speaker/headset
- `data/TelecomCallManager.kt` / `UtunConnection.kt` / `UtunConnectionService.kt` — Интеграция P2P-звонков с Android Telecom
- `data/ChatRepository.kt` — Хранилище данных: буферизация сообщений и каналов между C-ядром и UI через StateFlow
- `data/InviteLink.kt` — Разбор invite-ссылок: извлекает ID канала, публичный ключ, адреса для подключения
- `data/ConfigProvider.kt` — Настройки DataStore и генерация INI-текста для запуска C-ядра
@@ -279,8 +300,15 @@ port=9999
- `viewmodel/ChatViewModel.kt` — ViewModel: StateFlow-состояние для UI (список каналов, сообщения, статус)
- `ui/screens/ChannelListScreen.kt` — Главный экран: список каналов, кнопки Join (по invite-ссылке) и Create
- `ui/screens/ChatScreen.kt` — Экран чата: список сообщений + поле ввода
- `ui/screens/DmChatScreen.kt` — Экран личной беседы
- `ui/screens/MemberListScreen.kt` — Участники канала и действия над выбранным участником
- `ui/screens/CallScreen.kt` / `IncomingCallDialog.kt` — Активный и входящий звонок
- `ui/screens/PhotoRecordScreen.kt` / `VideoRecordScreen.kt` — Съёмка и подготовка media через CameraX
- `ui/screens/PhotoViewerScreen.kt` / `VideoPlayerScreen.kt` — Просмотр локальных изображений и видео
- `ui/screens/InviteLinkDialog.kt` — Выдача invite-ссылки и QR
- `ui/screens/FirstLaunchScreen.kt` — Первичная настройка приложения
- `ui/screens/JoinChannelDialog.kt` — Диалог подключения к каналу: ввод/вставка invite-ссылки, предпросмотр, кнопка Connect
- `ui/screens/QrScanScreen.kt` — QR-сканер для invite-ссылок (CameraX + ML Kit)
- `ui/screens/QrScannerPreview.kt` — QR-сканер для invite-ссылок (CameraX + ML Kit)
- `MainActivity.kt` — Точка входа Android-приложения: навигация между экранами, QrScan → JoinDialog flow
### Headless
@@ -1,32 +1,9 @@
/*
* headless_control.h — JSON control socket for uTun headless mode
*
* JSON line protocol:
* Request: {"id":N,"cmd":"<command>",...params}
* Response: {"id":N,"ok":true,"data":{...}} | {"id":N,"ok":false,"error":"..."}
* Event: {"event":"<type>",...}
*
* Commands:
* ping — alive check
* status — node info, uptime, connections
* connect — STCP connect to peer
* disconnect — STCP disconnect
* connections — list active connections
* create_channel — create chat channel
* channels — list channels
* send — send message to channel
* messages — get messages from channel
* debug_level — get/set debug levels
* subscribe — subscribe to events
* join — join channel via invite link
* quit — disconnect client
*
* Events (after subscribe):
* log — {"event":"log","level":"info","cat":"ETCP","msg":"..."}
* msg — {"event":"msg","ch":"id","author":"hex","ts":123}
* peer_online/offline
* channel_created/joined
*/
/* Каркас TCP-управления Android headless: init → регулярный poll → destroy в одном потоке.
* ua сейчас не используется; основной рабочий API чата — src/chat/chat_headless_control.h.
* JSON line: {"id":N,"cmd":"..."} → {"id":N,"ok":true,"data":...} либо error.
* ping/status/connections/debug_level возвращают заглушки; subscribe/quit управляют клиентом.
* join/chat_setting обращаются к запущенному instance_lite; прочие команды дают not implemented.
* event/broadcast_log отправляют JSON подписанным клиентам. Этот модуль сам ядро не запускает. */
#ifndef HEADLESS_CONTROL_H
#define HEADLESS_CONTROL_H
@@ -2,7 +2,8 @@
* android_jni_bridge.h — JNI bridge API (C side)
*
* Provides lifecycle management and callbacks between C core and Kotlin.
* For Android, compiled via NDK into libutun_lite.so.
* NDK собирает bridge вместе с ядром в libutun.so. Действия передаются в uasync;
* callbacks логов/событий вызываются из native-потоков, UI переносит их в свой поток.
*/
#ifndef ANDROID_JNI_BRIDGE_H
#define ANDROID_JNI_BRIDGE_H
@@ -51,7 +52,8 @@ void utun_bridge_create_channel(const char* name, const char* channel_id);
void utun_bridge_connect_node(const char* address, int port, const char* pubkey_hex);
/* Join channel via invite link.
addr_data format: family(1) + socketId(1) + address(4|16) + port(2 BE) per addr */
addrs_data — результат invite_serialize_addrs: Reality-префикс и
family(1) + socketId(1) + proto(1) + address(4|16) + port(2 BE) для каждого адреса. */
void utun_bridge_join_channel(uint64_t channel_id, uint64_t node_id,
const uint8_t* pubkey_bin,
const uint8_t* addrs_data, int addr_count,
@@ -1,3 +1,6 @@
/* Android-обёртка отправки обычного файла в канал через chat_core_submit_trampoline.
* Строит имя назначения в db_path/media/channel_id, копирование/индексацию выполняет media_index.
* 0 = запрос поставлен в uasync, -1 = отказ подготовки. Исходный файл нужен до завершения media-задачи. */
#ifndef ATTACHMENT_SENDER_H
#define ATTACHMENT_SENDER_H
@@ -1,9 +1,7 @@
/*
* instance_lite.h — lightweight uTun instance lifecycle for Android
*
* Kotlin generates INI config text, passes to instance_lite_start().
* C side parses it, creates uasync+ETCP+bgp+chat stack, runs in a pthread.
* Mirrors UtunNode::runLoop() from tools/chatgui/transport/utun_node.cpp.
* Android-владелец одного ядра: INI из Kotlin → pthread с uasync → core_start + chat_service_start.
* UTUN-сервис не запускается. Поток владеет instance/ua; UI передаёт работу через uasync.
* Полученные handles заимствованы и могут смениться при restart; сохранять их между рестартами нельзя.
*/
#ifndef INSTANCE_LITE_H
#define INSTANCE_LITE_H
@@ -17,14 +15,12 @@ extern "C" {
struct UASYNC;
struct UTUN_INSTANCE;
/* Start full uTun stack from INI config text.
* Creates a pthread for uasync event loop.
* Returns 0 on success, -1 on error.
* Config format: same as utun INI (see node_config.cpp saveFull). */
/* Копирует INI и запускает поток. 0 = поток создан либо уже запущен, -1 = ошибка запуска.
* Готовность самого ядра появляется позже: проверять is_running и события инициализации. */
int instance_lite_start(const char* config_text);
/* Signal stop and wait for thread to exit.
* Calls chat_sync_destroy, chat_core_destroy, utun_instance_destroy, uasync_destroy. */
/* Сигнализировать stop и дождаться потока; поток уничтожает instance, затем uasync.
* Вызывать с управляющего потока при существующем instance, не из callback ядра. */
void instance_lite_stop(void);
/* Returns non-zero if instance is running. */
@@ -44,9 +40,8 @@ void instance_lite_set_event_handler(instance_lite_event_fn handler);
* Call from any thread. Keys are regenerated asynchronously. */
void instance_lite_regenerate_keys(void);
/* Restart the instance internally (no thread kill). Stops chat_sync/chat_core,
* re-parses config, regenerates keys if needed, reopens DB, re-inits.
* Posts to uasync thread — restart happens asynchronously. */
/* Копирует INI, будит poll-loop и пересоздаёт instance и uasync внутри worker.
* Если ядро не работает, выполняет stop/start. Обновление асинхронное; старые handles утрачивают силу. */
void instance_lite_restart(const char* new_config_text);
/* Лёгкое обновление сокетов (auto_sockets=android): перечитывает [server] секции
@@ -1,3 +1,6 @@
/* Старая отдельная копия C-кодека utun://; invite_link_c.c исключён из текущего UTUN_SOURCES.
* Рабочее общее API — src/chat/invite_link.h, Qt/Kotlin используют тот же формат версии 0x03.
* Эти структуры не следует смешивать с InviteData общего API. */
#ifndef INVITE_LINK_C_H
#define INVITE_LINK_C_H
@@ -48,17 +51,17 @@ struct InviteDataC {
};
/* decode utun://base64 link string, returns 0 on success, -1 on error.
error buffer must be at least 256 bytes */
error_buf необязателен, текст ошибки ограничивается error_buf_size. */
int invite_link_decode(const char* link, size_t link_len, struct InviteDataC* out,
char* error_buf, size_t error_buf_size);
/* encode invite data to utun://base64 string.
password may be NULL (v1 format, no password).
out buffer must be large enough (~512 bytes safe).
returns written length (excluding null), or -1 on error */
password=NULL означает пустой пароль в версии 0x03.
out_size включает utun://, base64 и NUL; недостаточная ёмкость даёт -1.
returns base64 length (excluding prefix and null), or -1 on error */
int invite_link_encode(const struct InviteDataC* data, const char* password, char* out, size_t out_size);
/* serialize per-addr format for chat_sync_connect_from_invite():
/* serialize for chat_sync_connect_from_invite(): Reality-префикс + адреса:
family(1) + socketId(1) + proto(1) + address(4|16) + port(2 BE)
returns total bytes written, or -1 if buf too small */
int invite_serialize_addrs(const struct InviteDataC* data, uint8_t* buf, size_t buf_size);
@@ -1,3 +1,6 @@
/* Отправка уже подготовленного изображения в канал: MIME выбирается по расширению, width/height даёт caller.
* Не декодирует и не масштабирует изображение; ставит копирование/индексацию в chat_core/media_index.
* 0 = запрос поставлен в uasync, -1 = отказ. src_file_path должен существовать до завершения задачи. */
#ifndef PHOTO_SENDER_H
#define PHOTO_SENDER_H
@@ -1,9 +1,8 @@
/*
* utun_config_api.h — configuration provider API for Android
*
* C core requests config values from Kotlin via callbacks.
* For headless, a stub provider reads from environment variables.
* For Android, JNI bridge sets callbacks that query Kotlin DataStore.
* Callback-провайдер отдельных настроек native-обёртки. Без провайдера/accessor возвращает default.
* Основной конфиг ядра передаётся INI-текстом в instance_lite_start, а не через этот интерфейс.
* set_provider заимствует таблицу callbacks; она и возвращаемые строки должны жить во время вызовов.
* Провайдер установить до запуска потребителей: синхронизации внутри модуля нет.
*/
#ifndef UTUN_CONFIG_API_H
#define UTUN_CONFIG_API_H
@@ -1,3 +1,7 @@
/* Отправка подготовленного MP4 в канал или dm:conv_id через общий attachment_send.
* Android передаёт duration_ms/width/height; повторного транскодирования здесь нет. db_path не используется.
* 0 = запрос поставлен в uasync, -1 = отказ. Передаётся владение временным cache-файлом:
* задача удаляет src_file_path после подготовки. Результат публикации приходит событием ядра. */
#ifndef VIDEO_SENDER_H
#define VIDEO_SENDER_H
@@ -1,3 +1,8 @@
/* Android-накопитель голосового: init → start(target,48000,1) → feed PCM int16 → stop либо cancel.
* target — channel_id либо dm:conv_id. feed копирует count mono-сэмплов; управление защищено mutex.
* stop отсоединяет PCM/компрессор и ставит attachment_send в uasync: encode/file работа идёт в worker.
* stop=0 означает постановку подготовки либо отбрасывание записи короче 500мс, не доставку сообщения.
* deinit освобождает текущую запись; завершение сетевой отправки отслеживается событиями ядра. */
#ifndef VOICE_RECORDER_H
#define VOICE_RECORDER_H