296 lines
21 KiB
C
296 lines
21 KiB
C
/* Мост одного desktop GUI ↔ ядра: post копирует бинарное событие в Qt-очередь, callbacks работают в GUI.
|
||
* Инициализация/регистрация callbacks принадлежат GUI; NULL снимает callback. Данные callbacks
|
||
* заимствованы на время вызова, строки не обязательно NUL-terminated, если передана длина.
|
||
* post_uasync_fn передаёт заимствованный arg без копирования; owned_fn принимает отдельный u_malloc-блок.
|
||
* Перед destroy ядра его поток вызывает set_inst(NULL) вне poll/callbacks: закрывает приём команд,
|
||
* отменяет ожидающие post и освобождает переданные мосту аргументы. Затем можно снять и уничтожить uasync.
|
||
* Полученный inst заимствован: само чтение указателя не гарантирует время жизни при stop/finalize.
|
||
* Сырые callbacks (data,len) не заменяют проверку формата в получателе соответствующего codec. */
|
||
#ifndef GUI_BRIDGE_H
|
||
#define GUI_BRIDGE_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <stdint.h>
|
||
#include <stddef.h>
|
||
#include "../../../src/chat/chat_member.h"
|
||
#include "../../../src/chat/chat_event.h"
|
||
|
||
struct UASYNC;
|
||
struct TOPO_GROUP;
|
||
struct TOPO_GROUP_NODE;
|
||
struct UTUN_INSTANCE;
|
||
|
||
/* ── Типы уведомлений uasync→GUI (fire-and-forget) ── */
|
||
|
||
/* Коды/payload определяет chat_event.h; GUI-алиасы не дублируют числовую таблицу ядра. */
|
||
#define GUI_EVT_MSG_RECEIVED CHAT_EVT_MSG_RECEIVED
|
||
#define GUI_EVT_CONNECT_RESULT CHAT_EVT_CONNECT_RESULT
|
||
#define GUI_EVT_NEW_PEER CHAT_EVT_NEW_PEER
|
||
#define GUI_EVT_CHANNEL_UPDATED CHAT_EVT_CHANNEL_UPDATED
|
||
#define GUI_EVT_MEMBERS_CHANGED CHAT_EVT_MEMBERS_CHANGED
|
||
#define GUI_EVT_MY_NODE_ID CHAT_EVT_MY_NODE_ID
|
||
#define GUI_EVT_AUTO_CONNECT_STATUS CHAT_EVT_AUTO_CONNECT_STATUS
|
||
#define GUI_EVT_CHANNEL_PEERS_ONLINE CHAT_EVT_CHANNEL_PEERS_ONLINE
|
||
#define GUI_EVT_DB_READY CHAT_EVT_DB_READY
|
||
#define GUI_EVT_STATUS_REFRESH CHAT_EVT_STATUS_REFRESH
|
||
#define GUI_EVT_KEYS_GENERATED CHAT_EVT_KEYS_GENERATED
|
||
#define GUI_EVT_ATTACHMENT_DOWNLOADED CHAT_EVT_ATTACHMENT_DOWNLOADED
|
||
#define GUI_EVT_DOWNLOAD_PROGRESS CHAT_EVT_DOWNLOAD_PROGRESS
|
||
#define GUI_EVT_NODEINFO_UPDATE CHAT_EVT_NODEINFO_UPDATED
|
||
#define GUI_EVT_CONN_LIST CHAT_EVT_CONN_LIST
|
||
#define GUI_EVT_CONN_METRICS CHAT_EVT_CONN_METRICS
|
||
#define GUI_EVT_MEMBER_DETAIL CHAT_EVT_MEMBER_DETAIL
|
||
#define GUI_EVT_MEMBER_LIST CHAT_EVT_MEMBER_LIST
|
||
#define GUI_EVT_MEMBER_UPDATED CHAT_EVT_MEMBER_UPDATED
|
||
#define GUI_EVT_MEMBER_REMOVED CHAT_EVT_MEMBER_REMOVED
|
||
#define GUI_EVT_ADMIN_KEY_RECEIVED CHAT_EVT_ADMIN_KEY_RECEIVED
|
||
#define GUI_EVT_INVITE_LINK_READY CHAT_EVT_INVITE_LINK_READY
|
||
#define GUI_EVT_INVITE_CANDIDATES CHAT_EVT_INVITE_CANDIDATES
|
||
#define GUI_EVT_DM_MSG_RECEIVED CHAT_EVT_DM_MSG_RECEIVED
|
||
#define GUI_EVT_DM_CONV_UPDATED CHAT_EVT_DM_CONV_UPDATED
|
||
#define GUI_EVT_CALL_INCOMING CHAT_EVT_CALL_INCOMING
|
||
#define GUI_EVT_CALL_RINGING CHAT_EVT_CALL_RINGING
|
||
#define GUI_EVT_CALL_ACCEPTED CHAT_EVT_CALL_ACCEPTED
|
||
#define GUI_EVT_CALL_ENDED CHAT_EVT_CALL_ENDED
|
||
#define GUI_EVT_CALL_DECLINED CHAT_EVT_CALL_DECLINED
|
||
#define GUI_EVT_CALL_STATS CHAT_EVT_CALL_STATS
|
||
#define GUI_EVT_CALL_ERROR CHAT_EVT_CALL_ERROR
|
||
#define GUI_EVT_DM_MESSAGES CHAT_EVT_DM_MESSAGES
|
||
#define GUI_EVT_CALL_PATH CHAT_EVT_CALL_PATH
|
||
#define GUI_EVT_RADIO_TALK CHAT_EVT_RADIO_TALK
|
||
#define GUI_EVT_CALL_CONNECTION CHAT_EVT_CALL_CONNECTION
|
||
|
||
/* ── API ── */
|
||
|
||
/* Идемпотентная инициализация из GUI после создания QCoreApplication, до запуска worker. Она владеет приёмником;
|
||
* все producers должны завершиться до её уничтожения. Повторный init сохраняет очередь и callbacks. */
|
||
void gui_bridge_init(void);
|
||
|
||
/* Установить uasync перед публикацией instance; снять после set_inst(NULL) и завершения worker.
|
||
* Замена uasync при опубликованном instance отклоняется с ERROR. uasync мосту не принадлежит. */
|
||
void gui_bridge_set_uasync(struct UASYNC* ua);
|
||
|
||
/* Опубликовать готовый instance из uasync после set_uasync. NULL снимается в uasync до destroy,
|
||
* вне callbacks: синхронно отменяет ожидающие команды и освобождает аргументы owned-запросов.
|
||
* Начатый callback завершается до остановки poll; отмена ещё не начатой команды не посылает результат в GUI. */
|
||
void gui_bridge_set_inst(struct UTUN_INSTANCE* inst);
|
||
|
||
/* Текущий заимствованный UTUN_INSTANCE (NULL пока не создан/после сброса моста). */
|
||
struct UTUN_INSTANCE* gui_bridge_get_inst(void);
|
||
|
||
/* uasync → GUI: синхронно скопировать data_len байт и поставить событие в Qt::QueuedConnection.
|
||
* len>=0, при len>0 data обязателен; (NULL,0) — пустое событие. Ошибки аргументов/доставки логируются. */
|
||
void gui_bridge_post(int event_type, const uint8_t* data, int data_len);
|
||
|
||
/* GUI → uasync: передать fn(arg) без владения arg. Нужны опубликованные ua/instance.
|
||
* При отказе/остановке fn не вызывается, arg остаётся владельцу; ошибка постановки логируется.
|
||
* Владелец обеспечивает жизнь arg до callback/отмены. Для malloc-команд использовать owned_fn. */
|
||
void gui_bridge_post_uasync_fn(void (*fn)(void*), void* arg);
|
||
/* Передать отдельный u_malloc/u_calloc-блок arg: 0 — мост принял владение, callback обязан освободить arg;
|
||
* отмена до callback освобождает его мостом. -1 — arg остаётся вызывающему. Вложенные ресурсы не освобождаются. */
|
||
int gui_bridge_post_uasync_owned_fn(void (*fn)(void*), void* arg);
|
||
/* Composer-запрос: 0 — владение req передано, callback/отмена освободят блок; -1 — req остаётся вызывающему. */
|
||
struct chat_msg_submit;
|
||
int gui_bridge_submit_message(struct chat_msg_submit* req);
|
||
|
||
/* Проверить наличие опубликованных uasync и instance. Только подсказка готовности, не резервация их lifetime. */
|
||
int gui_bridge_is_uasync_ready(void);
|
||
|
||
/* Callback для результатов подключения (вызывается из GUI-потока) */
|
||
typedef void (*gui_connect_result_fn)(uint64_t node_id, uint64_t channel_id, int result, uint64_t request);
|
||
/* Скопировать invite-ссылку в JOIN port. request обязателен: при 0 записан ID будущего CONNECT_RESULT;
|
||
* <0 — CHAT_CONNECT_* из chat_sync.h, команда не принята и *request не меняется. channel — собственный канал offer. */
|
||
int gui_bridge_offer_link(uint64_t channel, const char* link, size_t len, uint64_t* request);
|
||
int gui_bridge_join_link(const char* link, size_t len, uint64_t* request);
|
||
void gui_bridge_set_connect_result_cb(gui_connect_result_fn cb);
|
||
|
||
/* Callback для входящих сообщений (вызывается из GUI-потока) */
|
||
typedef void (*gui_msg_received_fn)(const char* ch_id, int ch_id_len, uint64_t author, int initial_sync);
|
||
void gui_bridge_set_msg_received_cb(gui_msg_received_fn cb);
|
||
|
||
/* Обновление списка после изменения или завершённого локального удаления канала; GUI-поток. */
|
||
typedef void (*gui_channel_updated_fn)(const char* ch_id, int ch_id_len);
|
||
void gui_bridge_set_channel_updated_cb(gui_channel_updated_fn cb);
|
||
|
||
/* Callback для получения своего node_id после инициализации uTun */
|
||
typedef void (*gui_my_node_id_fn)(uint64_t node_id);
|
||
void gui_bridge_set_my_node_id_cb(gui_my_node_id_fn cb);
|
||
|
||
/* Callback для статуса авто-подключения (вызывается из GUI-потока)
|
||
* status: 0=in_progress, 1=done, 2=stopped */
|
||
typedef void (*gui_auto_connect_status_fn)(uint8_t status, uint16_t total_tried, uint16_t node_count, uint16_t connected);
|
||
void gui_bridge_set_auto_connect_status_cb(gui_auto_connect_status_fn cb);
|
||
|
||
/* Callback для обновления числа онлайн-пиров канала (вызывается из GUI-потока) */
|
||
typedef void (*gui_channel_peers_online_fn)(const char* ch_id, int ch_id_len, uint16_t online_count);
|
||
void gui_bridge_set_channel_peers_online_cb(gui_channel_peers_online_fn cb);
|
||
|
||
/* Callback: DB открыта, таблицы созданы, можно загружать данные (вызывается из GUI-потока) */
|
||
typedef void (*gui_db_ready_fn)(void);
|
||
void gui_bridge_set_db_ready_cb(gui_db_ready_fn cb);
|
||
|
||
/* Callback для обновления статуса (NTP + connections) — text без \0, вызывается из GUI-потока */
|
||
typedef void (*gui_status_refresh_fn)(const char* text, int len);
|
||
void gui_bridge_set_status_refresh_cb(gui_status_refresh_fn cb);
|
||
|
||
/* Секундное среднее CPU uasync, 0..100; callback выполняется в GUI-потоке. */
|
||
typedef void (*gui_cpu_load_fn)(int percent);
|
||
void gui_bridge_set_cpu_load_cb(gui_cpu_load_fn cb);
|
||
int gui_bridge_request_cpu_load(void); // 1 = запрос поставлен в очередь; 0 = ядро недоступно/ошибка
|
||
|
||
/* Callback для завершения загрузки медиа-аттача */
|
||
typedef void (*gui_attachment_downloaded_fn)(const char* ch_id, int ch_id_len, int64_t msg_id);
|
||
void gui_bridge_set_attachment_downloaded_cb(gui_attachment_downloaded_fn cb);
|
||
|
||
/* Callback для прогресса загрузки медиа */
|
||
typedef void (*gui_download_progress_fn)(const char* ch_id, int ch_id_len, int64_t msg_id, int blocks_done, int num_blocks);
|
||
void gui_bridge_set_download_progress_cb(gui_download_progress_fn cb);
|
||
|
||
/* Callback для входящих приглашений (вызывается из GUI-потока)
|
||
data: [ch_id_len:1][ch_id][name_len:1][name][inviter_node_id:8][inviter_name_len:1][inviter_name] */
|
||
typedef void (*gui_invite_received_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_invite_received_cb(gui_invite_received_fn cb);
|
||
|
||
/* Callback для списка ETCP-соединений (вызывается из GUI-потока) */
|
||
typedef void (*gui_conn_list_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_conn_list_cb(gui_conn_list_fn cb);
|
||
|
||
/* Callback для метрик выбранного соединения (вызывается из GUI-потока) */
|
||
typedef void (*gui_conn_metrics_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_conn_metrics_cb(gui_conn_metrics_fn cb);
|
||
|
||
/* Callback для live-снапшота панели деталей участника (вызывается из GUI-потока)
|
||
data: см. CHAT_MEMBER_DETAIL_* в chat_member.h; проверка целого пакета до применения. */
|
||
typedef void (*gui_member_detail_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_member_detail_cb(gui_member_detail_fn cb);
|
||
|
||
/* Callback для получения полного списка мемберов канала (вызывается из GUI-потока)
|
||
data: [ch_id_len:1][ch_id:var][count:2][member:CHAT_MEMBER_DISPLAY_SIZE]* */
|
||
typedef void (*gui_member_list_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_member_list_cb(gui_member_list_fn cb);
|
||
|
||
/* Callback для обновления одного мембера (вызывается из GUI-потока)
|
||
data: [ch_id_len:1][ch_id:var][count:1][member:CHAT_MEMBER_DISPLAY_SIZE] */
|
||
typedef void (*gui_member_updated_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_member_updated_cb(gui_member_updated_fn cb);
|
||
|
||
/* Callback для удаления мембера из канала (вызывается из GUI-потока)
|
||
data: [ch_id_len:1][ch_id:var][node_id:8] */
|
||
typedef void (*gui_member_removed_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_member_removed_cb(gui_member_removed_fn cb);
|
||
|
||
/* Callback: получен канальный приватный ключ (стал совладельцем) — data: [ch_id_len:1][ch_id][from_node_id:8] */
|
||
typedef void (*gui_admin_key_received_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_admin_key_received_cb(gui_admin_key_received_fn cb);
|
||
|
||
/* Готовая invite-ссылка: link — заимствованный NUL-terminated UTF-8; пустая строка при ошибке, детали в логе. */
|
||
typedef void (*gui_invite_link_ready_fn)(const char* ch_id, int ch_id_len, uint64_t request_id, const char* link);
|
||
void gui_bridge_set_invite_link_ready_cb(gui_invite_link_ready_fn cb);
|
||
|
||
/* Callback: список достижимых узлов-кандидатов для invite — data: [auto_node_id:8][count:2][node_id:8]* */
|
||
typedef void (*gui_invite_candidates_fn)(const char* ch_id, int ch_id_len, const uint8_t* data, int len);
|
||
void gui_bridge_set_invite_candidates_cb(gui_invite_candidates_fn cb);
|
||
|
||
/* LAN-события в GUI-потоке; wire-форматы определены CHAT_EVT_LOCAL_* в chat_event.h. */
|
||
typedef void (*gui_local_event_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_local_devices_cb(gui_local_event_fn cb);
|
||
void gui_bridge_set_local_invite_cb(gui_local_event_fn cb);
|
||
void gui_bridge_set_local_delivery_cb(gui_local_event_fn cb);
|
||
|
||
/* Callback для входящего звонка (вызывается из GUI-потока) */
|
||
typedef void (*gui_call_incoming_fn)(const char* ch_id, int ch_id_len, uint64_t caller_node_id, uint64_t call_id);
|
||
void gui_bridge_set_call_incoming_cb(gui_call_incoming_fn cb);
|
||
|
||
/* Callback для звонкового события с call_id (ringing/accepted) */
|
||
typedef void (*gui_call_id_fn)(uint64_t call_id);
|
||
void gui_bridge_set_call_ringing_cb(gui_call_id_fn cb);
|
||
void gui_bridge_set_call_phone_busy_cb(gui_call_id_fn cb);
|
||
void gui_bridge_set_call_accepted_cb(gui_call_id_fn cb);
|
||
|
||
/* Callback для завершения/отклонения звонка (вызывается из GUI-потока) */
|
||
typedef void (*gui_call_ended_fn)(uint64_t call_id, uint8_t reason);
|
||
void gui_bridge_set_call_ended_cb(gui_call_ended_fn cb);
|
||
void gui_bridge_set_call_declined_cb(gui_call_ended_fn cb);
|
||
|
||
/* Callback для ошибки звонка (пир офлайн/нет маршрута). text может быть пустым. */
|
||
typedef void (*gui_call_error_fn)(uint64_t call_id, uint8_t err, const char* text, int len);
|
||
void gui_bridge_set_call_error_cb(gui_call_error_fn cb);
|
||
|
||
/* CALL_STATS: rtt/buffer/minimum/maximum/reserve — мс; tempo — скорость ×100, dropped/underruns — счётчики.
|
||
* Все восемь значений передаются uint16 BE после call_id в native endian; callback получает int.
|
||
* Extrema относятся к последним десяти секундным интервалам. */
|
||
typedef void (*gui_call_stats_fn)(uint64_t call_id, int rtt, int buffer, int tempo_x100,
|
||
int dropped, int underruns, int minimum, int maximum, int reserve);
|
||
void gui_bridge_set_call_stats_cb(gui_call_stats_fn cb);
|
||
|
||
/* Callback для BGP-маршрута звонка (вызывается из GUI-потока) */
|
||
typedef void (*gui_call_path_fn)(uint64_t call_id, const char* text, int len);
|
||
void gui_bridge_set_call_path_cb(gui_call_path_fn cb);
|
||
|
||
typedef void (*gui_call_connection_fn)(uint64_t call_id, uint8_t type, uint64_t next_hop_node_id);
|
||
void gui_bridge_set_call_connection_cb(gui_call_connection_fn cb);
|
||
|
||
/* Callback индикации говорящего в рации (вызывается из GUI-потока)
|
||
* group_id — канал, src_node_id — кто говорит, on — 1=начал / 0=закончил. */
|
||
typedef void (*gui_radio_talk_fn)(uint64_t group_id, uint64_t src_node_id, uint8_t on);
|
||
void gui_bridge_set_radio_talk_cb(gui_radio_talk_fn cb);
|
||
|
||
/* Callback для входящего DM-сообщения (вызывается из GUI-потока)
|
||
* conv_id_len/conv_id — идентификатор беседы (десятичная строка). */
|
||
typedef void (*gui_dm_msg_received_fn)(const char* conv_id, int conv_id_len, uint64_t author);
|
||
void gui_bridge_set_dm_msg_received_cb(gui_dm_msg_received_fn cb);
|
||
|
||
/* Уведомление об изменениях сети, GUI-поток: CHANNEL_UPDATED/MEMBERS_CHANGED, SERVICE_STARTED/STOPPED,
|
||
* NODEINFO_UPDATED/LINK_STATUS_CHANGED, MEMBER_UPDATED/REMOVED, CHANNEL_DELETED и DM_CONV_UPDATED.
|
||
* nodeinfo callback может отправить только сигнал без payload; живые поля карточки получает MEMBER_DETAIL. */
|
||
typedef void (*gui_network_changed_fn)(int event_type);
|
||
void gui_bridge_set_network_changed_cb(gui_network_changed_fn cb);
|
||
void gui_bridge_set_dm_call_route_cb(void (*cb)(const uint8_t* data, int len));
|
||
|
||
/* DM-беседа создана/изменена: conv_id — заимствованная строка длины conv_id_len, generation — версия удаления. */
|
||
typedef void (*gui_dm_conv_updated_fn)(const char* conv_id, int conv_id_len, uint64_t generation);
|
||
void gui_bridge_set_dm_conv_updated_cb(gui_dm_conv_updated_fn cb);
|
||
|
||
/* Callback: расшифрованные сообщения DM-беседы (вызывается из GUI-потока)
|
||
* data: [conv_id_len:1][conv_id:var][generation:8][JSON:utf8]. */
|
||
typedef void (*gui_dm_messages_fn)(const uint8_t* data, int len);
|
||
void gui_bridge_set_dm_messages_cb(gui_dm_messages_fn cb);
|
||
/* CHAT_EVT_DM_INVITE_RESULT: коррелированный результат отправки приглашения. */
|
||
void gui_bridge_set_dm_invite_result_cb(gui_dm_messages_fn cb);
|
||
/* Запрос локального удаления из GUI: 0=поставлен в uasync, -1=отказ до постановки.
|
||
* conv_id — десятичный ID, generation/request_id ненулевые; callback получает CHAT_EVT_DM_DELETE_RESULT в GUI. */
|
||
int gui_bridge_delete_dm(const char* conv_id, uint64_t generation, uint64_t request_id);
|
||
void gui_bridge_set_dm_delete_result_cb(gui_dm_messages_fn cb);
|
||
/* Файловый браузер: wire-ответы и прогресс общих передач, в GUI-потоке. */
|
||
void gui_bridge_set_member_files_response_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_member_files_transfer_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_avatar_result_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_group_avatar_result_cb(gui_dm_messages_fn cb);
|
||
/* Опросы/реакции: адресное изменение и коррелированный ответ команды, в GUI-потоке. */
|
||
void gui_bridge_set_feedback_changed_cb(gui_dm_messages_fn cb);
|
||
/* Изменение локальных запросов/ключей вложения, без секретных данных. */
|
||
void gui_bridge_set_attachment_keys_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_feedback_result_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_msg_submitted_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_msg_updated_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_radio_mute_result_cb(gui_dm_messages_fn cb);
|
||
/* CHAT_EVT_RADIO_CALL: id/group/peer:8LE,state/reason/incoming:1, GUI-поток. */
|
||
void gui_bridge_set_radio_call_cb(gui_dm_messages_fn cb);
|
||
void gui_bridge_set_stream_sources_cb(gui_dm_messages_fn cb);
|
||
/* Переключить локальное приглушение участника. 0 — поставлено в uasync; -1 — ядро/аргументы/память недоступны.
|
||
* channel_id — непустой ID до 63 байт, node_id ненулевой; результат приходит через RADIO_MUTE_RESULT. */
|
||
int gui_bridge_toggle_member_radio_mute(const char* channel_id, uint64_t node_id);
|
||
/* CHAT_EVT_ATTACHMENT_PREPARATION: target + job UUID + state. */
|
||
void gui_bridge_set_attachment_preparation_cb(gui_dm_messages_fn cb);
|
||
|
||
/* uTun nodeinfo callback — registered via utun_add_nodeinfo_cbk, called from uasync thread */
|
||
void gui_nodeinfo_cb_impl(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq, void* arg);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* GUI_BRIDGE_H */
|