Files
utun2/src/chat/chat_member.h
T

173 lines
14 KiB
C
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.
/*
* chat_member.h — единая структура мембера для отображения в GUI
*
* Используется chatgui (desktop), headless CLI, Android.
* Бинарные снимки для GUI/JNI формирует chat_core_get_member_list() в uasync-потоке.
* Расширенная JSON-интроспекция с ключами/адресами описана отдельно в chat_core.h.
* Снимок содержит свойства участника и состояние маршрута именно его CHAT-группы.
* Все вызовы — в uasync-потоке. ch_id — канонический десятичный ID1..INT64_MAX.
* В список входят self,placeholders и deleted;deleted показывается offline,self обычно online.
*
* Формат на проводе (ручная сериализация, фиксированный размер 164 байта):
* [0-7] node_id uint64_t LE
* [8] online uint8_t
* [9] is_self uint8_t
* [10] flags uint8_t 0x01=supernode 0x02=admin 0x04=moder 0x08=deleted 0x10=radio 0x20=local radio mute
* 0x40=phone status known, 0x80=busy on a call (live BGP hint)
* [11-12] rtt uint16_t LE (0,1 мс выбранного живого пути, 0xFFFF=нет данных)
* [13] nat_type uint8_t ADDR_TYPE_*
* [14] storage uint8_t
* [15-78] name char[64] local_nick если задан, иначе node name. \0-padded
* [79-86] avatar_server uint64_t LE; 0 = нет аватарки
* [87-156] avatar_file char[70], sha256.json с NUL
* [157] storage_role uint8_t, подписанная роль, независимо от сетевого приоритета storage
* [158] verified uint8_t, административный тег verified=yes
* [159] node_type uint8_t, вычисленный тип узла из peers
* [160] conn_presence uint8_t, известные виды подключения NCONN_*
* [161] conn_up uint8_t, работающие виды подключения NCONN_*
* [162-163] intermediaries uint16_t LE, число посредников выбранного пути
*/
#ifndef CHAT_MEMBER_H
#define CHAT_MEMBER_H
#include <stdint.h>
#include <stddef.h>
struct UTUN_INSTANCE;
#ifdef __cplusplus
extern "C" {
#endif
#define CHAT_MEMBER_FLAG_SUPERNODE 0x01
#define CHAT_MEMBER_FLAG_ADMIN 0x02
#define CHAT_MEMBER_FLAG_MODER 0x04
#define CHAT_MEMBER_FLAG_DELETED 0x08
#define CHAT_MEMBER_FLAG_RADIO 0x10
#define CHAT_MEMBER_FLAG_RADIO_MUTED 0x20 /* локальное отключение голоса участника */
#define CHAT_MEMBER_FLAG_PHONE_KNOWN 0x40 /* опубликовано состояние телефонной занятости */
#define CHAT_MEMBER_FLAG_PHONE_BUSY 0x80 /* занят звонком; цвет трубки в интерфейсе */
#define CHAT_MEMBER_DISPLAY_SIZE 164
/* Снять полный список:0 — успех,-1 — ошибка/более65535 записей. Обязательные out/count сбрасываются в NULL/0.
* out — u_malloc-массив count*CHAT_MEMBER_DISPLAY_SIZE байт,освобождает caller через u_free;пустой список — NULL/0.
* Порядок:online первыми,затем unsigned node_id по возрастанию. SQL/память не дают частичный успешный результат. */
int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count);
/* Снять одного участника:0/-1 (ошибка/нет строки). out — обязательный буфер CHAT_MEMBER_DISPLAY_SIZE байт;
* при отказе не меняется. Формирование полей совпадает с полным списком. */
int chat_core_get_single_member(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t node_id, uint8_t* out);
/* Live-онлайн: маршрутизатор располагает живым путём в группе канала (self всегда онлайн).
Не читает nodes.online и не проверяет членство/deleted;это отдельная проверка транспорта,self всегда1. NULL/неверный ID дают0. */
int chat_core_member_online(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t node_id);
/* Внутренний снимок:поля далее кодируются вручную,struct-layout в wire не передаётся. */
struct chat_member_display {
uint64_t node_id; /* ID участника. */
uint8_t online; /* Живой путь/self,сброшен для deleted. */
uint8_t is_self; /* Совпадение с node_id instance. */
uint8_t flags; /* CHAT_MEMBER_FLAG_*;offline не несёт phone known/busy. */
uint16_t rtt; /* Суммарный RTT выбранного пути,0.1мс;UINT16_MAX — неизвестен/насыщен. */
uint8_t nat_type; /* Агрегированный ADDR_TYPE_* адресов узла;255 — адресов нет. */
uint8_t storage; /* Локальный приоритет хранения,отдельно от подписанной роли. */
char name[64]; /* Local nick,имя nodes или0xNNNN;до63 байт+NUL. */
uint64_t avatar_server; /* Сервер файлового аватара,0 — ссылки нет. */
char avatar_file[70];/* Проверенный sha256.json+NUL. */
uint8_t storage_role; /* source=0,не deleted,adm_tags.storage=yes и64-байтовая подпись owner-блока;доверие записи — у member_sync. */
uint8_t verified; /* административное подтверждение участника */
uint8_t node_type; /* классификация узла, не состояние маршрута */
uint8_t conn_presence; /* известные виды подключения NCONN_* */
uint8_t conn_up; /* работающие виды подключения NCONN_* */
uint16_t intermediaries; /* число посредников выбранного живого пути */
};
/* Копирование фиксированного wire164:src/dst обязательны,caller обеспечивает размеры.
* Serialize завершает/дополняет NUL поля name/avatar_file;NULL только логируется. */
void chat_core_serialize_member(const struct chat_member_display* src, uint8_t* dst);
/* Deserialize читает ровно164 доступных байта;0/-1 при NULL,длину/семантику полей проверяет caller. */
int chat_core_deserialize_member(const uint8_t* src, struct chat_member_display* dst);
/* Трамплин для gui_bridge, только uasync: принимает собственный u_malloc-блок arg и освобождает его.
* ch_id — канонический ID+NUL. Успех: CHAT_EVT_MEMBER_LIST с uint16 native count (0..65535), записи wire164 LE.
* Непредставимый count/ошибка чата/памяти логируются, события нет; ложный/усечённый снимок не отправляется. */
struct chat_member_list_req { struct UTUN_INSTANCE* inst; char ch_id[64]; };
void chat_core_request_member_list_trampoline(void* arg);
/* Владение/поток/аргумент как у list trampoline. Для каждого участника — один полный
* CHAT_EVT_MEMBER_UPDATED, включая остальные live-поля. Пустой список не даёт событий.
* Это снимок актуального состояния без запуска новых сетевых измерений; inst заимствован до выполнения. */
void chat_core_request_member_rtt_trampoline(void* arg);
/* Локальный переключатель рации другого участника:0 — committed,-1 — отказ,чужая транзакция запрещена.
* Снимок готовится до изменения;после radio commit обновлённый флаг приходит MEMBER_UPDATED без нового SQL-чтения.
* Ошибка сохраняет настройку/кэш/звук и не выдаёт успешное событие. */
int chat_core_toggle_member_radio_mute(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t node_id);
struct chat_member_radio_mute_req { struct UTUN_INSTANCE* inst; char ch_id[64]; uint64_t node_id; };
/* Забирает u_malloc-запрос;inst заимствован. Ответ — RADIO_MUTE_RESULT(group,node,success),включая отказ. */
void chat_core_toggle_member_radio_mute_trampoline(void* arg);
/* Подписки свойств/маршрутов → MEMBER_UPDATED; вызываются в uasync при init/destroy чата.
* Свойства публикуются синхронно. Маршруты объединяются по (канал,узел) до следующего posted callback:
* UI получает свежий снимок вне topo dispatch и может удалить канал, не повредив его group/node.
* Ожидающие route-события отменяются при destroy;ошибка памяти логируется без частичного события. */
/* Установить обе подписки0/-1;при отказе частичная регистрация снята. Вызывается один раз из chat_core_init. */
int chat_member_init(struct UTUN_INSTANCE* inst);
void chat_member_destroy(struct UTUN_INSTANCE* inst);
/* Дополнительная диагностика карточки; online/RTT берутся только из chat_member_display.
* Запрос выделяет GUI через u_calloc и передаёт в uasync; trampoline освобождает его.
* Ответ CHAT_EVT_MEMBER_DETAIL всегда повторяет request_id/group_id/node_id, включая ошибки. */
struct chat_member_detail_req {
struct UTUN_INSTANCE* inst; /* ядро, в uasync которого выполняется сбор */
uint64_t group_id; /* конкретная CHAT-группа */
uint64_t node_id; /* выбранный участник */
uint64_t request_id; /* ненулевой ID запроса, не повторяется при смене выбора */
};
/* Wire LE: request:8, group:8, node:8, result:1, transport_flags:1, own_tcp:2,
* hop_count:1, link_count:1, sock_count:1; далее hops:8*, links:94*, socks:48*.
* transport_flags: bit0=conn_present, bit1=links_up, bit2=initialized; не доступность в группе.
* hops — список выбранного пути от назначения к первому посреднику; у offline/self пустой.
* Ошибка содержит только заголовок;INVALID допускает нулевые поля неверного исходного запроса.
* Счётчики own_tcp и ссылок сокета насыщаются на65535;списки ограничены16 элементами каждый.
* link: direction:1 (0=unknown,1=out,2=in),state:1,status:1,has_ip:1,local_family:1,local_addr:16,local_port:2,
* remote_family:1,remote_addr:16,remote_port:2,socket_name:20,protocol:32. Не-IP не имеет адресов/портов.
* sock: id:4,port:2,links_up:2,links_down:2,ifname:38. Строки завершаются NUL. */
#define CHAT_MEMBER_DETAIL_HEADER_SIZE 31
#define CHAT_MEMBER_DETAIL_MAX_HOPS 16
#define CHAT_MEMBER_DETAIL_MAX_LINKS 16
#define CHAT_MEMBER_DETAIL_MAX_SOCKS 16
#define CHAT_MEMBER_DETAIL_LINK_SIZE 94
#define CHAT_MEMBER_DETAIL_SOCK_SIZE 48
#define CHAT_MEMBER_DETAIL_MAX_SIZE (CHAT_MEMBER_DETAIL_HEADER_SIZE + 8 * CHAT_MEMBER_DETAIL_MAX_HOPS + \
CHAT_MEMBER_DETAIL_LINK_SIZE * CHAT_MEMBER_DETAIL_MAX_LINKS + CHAT_MEMBER_DETAIL_SOCK_SIZE * CHAT_MEMBER_DETAIL_MAX_SOCKS)
enum chat_member_detail_result {
CHAT_MEMBER_DETAIL_OK = 0,
CHAT_MEMBER_DETAIL_UNAVAILABLE = 1, /* чат/группа остановлены */
CHAT_MEMBER_DETAIL_NOT_MEMBER = 2, /* запись участника отсутствует */
CHAT_MEMBER_DETAIL_INVALID = 3, /* неверные аргументы запроса */
CHAT_MEMBER_DETAIL_ERROR = 4 /* ошибка чтения данных участника */
};
/* Проверенный view заимствует массивы из входного пакета; живёт не дольше data. */
struct chat_member_detail_view {
uint64_t request_id, group_id, node_id; /* адресат ответа */
uint8_t result, transport_flags; /* результат и состояние физического транспорта */
uint16_t own_tcp_active; /* TCP-соединения self */
uint8_t hop_count, link_count, sock_count; /* длины массивов */
const uint8_t *hops, *links, *socks; /* неизменяемые wire-массивы */
};
/* Проверить весь пакет до применения: 0=успех, -1=ошибка с логом; out при ошибке не меняется. */
int chat_core_parse_member_detail(const uint8_t* data, size_t len, struct chat_member_detail_view* out);
void chat_core_collect_member_detail_trampoline(void* arg);
#ifdef __cplusplus
}
#endif
#endif /* CHAT_MEMBER_H */