Browse Source

Expose live radio subscriptions in member updates

master
evgeny 2 days ago
parent
commit
9dd2dffc80
  1. 25
      src/chat/chat_member.c
  2. 7
      src/chat/chat_member.h
  3. 9
      src/routing_layer/topo_group.c

25
src/chat/chat_member.c

@ -2,7 +2,7 @@
* chat_member.c — единый код запроса мемберов для GUI
*
* Используется: chatgui (desktop), headless CLI, Android.
* Все три потребителя получают данные через chat_core_get_member_list().
* Live-состояние участников читается только в uasync-потоке.
*/
#include "chat_core_priv.h"
@ -32,6 +32,16 @@ int chat_core_member_online(struct UTUN_INSTANCE* inst, const char* ch_id, uint6
return topo_node_find_by_id(g, node_id) != NULL;
}
/* Рация — живая подписка на конкретную CHAT-группу; у self нет записи в group->nodes. */
static uint8_t member_radio_flag(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t node_id) {
if (!inst || !inst->topo_groups || !ch_id || !ch_id[0]) return 0;
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, strtoull(ch_id, NULL, 10));
if (!group || group->group_type != TOPO_GROUP_TYPE_CHAT) return 0;
if (node_id == inst->node_id) return group->radio_active ? CHAT_MEMBER_FLAG_RADIO : 0;
struct TOPO_GROUP_NODE* node = topo_node_find_by_id(group, node_id);
return node && node->radio ? CHAT_MEMBER_FLAG_RADIO : 0;
}
/* ─── парсинг adm_tags в flags ─── */
static uint8_t parse_adm_tags_flags(const char* adm_tags) {
@ -138,7 +148,7 @@ int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uin
const char* adm_tags = (const char*)sqlite3_column_text(st, 3);
m->storage = (uint8_t)sqlite3_column_int(st, 4);
m->is_self = (uint8_t)(m->node_id == my_id ? 1 : 0);
m->flags = parse_adm_tags_flags(adm_tags);
m->flags = parse_adm_tags_flags(adm_tags) | member_radio_flag(inst, ch_id, m->node_id);
if (sqlite3_column_int(st, 5)) m->flags |= CHAT_MEMBER_FLAG_DELETED;
m->rtt = 0xFFFF;
m->nat_type = 0xFF;
@ -253,7 +263,7 @@ int chat_core_get_single_member(struct UTUN_INSTANCE* inst, const char* ch_id, u
const char* adm_tags = (const char*)sqlite3_column_text(st, 2);
m.storage = (uint8_t)sqlite3_column_int(st, 3);
m.is_self = (uint8_t)(node_id == my_id ? 1 : 0);
m.flags = parse_adm_tags_flags(adm_tags);
m.flags = parse_adm_tags_flags(adm_tags) | member_radio_flag(inst, ch_id, node_id);
if (sqlite3_column_int(st, 4)) m.flags |= CHAT_MEMBER_FLAG_DELETED;
m.rtt = 0xFFFF;
m.nat_type = 0xFF;
@ -374,8 +384,15 @@ static void on_member_props_changed(uint64_t node_id, const char* adm_tags, cons
evt[0] = (uint8_t)cl;
memcpy(evt + 1, channel_id, cl);
evt[1 + cl] = 1;
if (chat_core_get_single_member(inst, channel_id, node_id, evt + 1 + cl + 1) == 0)
if (chat_core_get_single_member(inst, channel_id, node_id, evt + 1 + cl + 1) == 0) {
const uint8_t* member = evt + 1 + cl + 1;
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "chat_member: update ch=%s node=%016llx online=%u self=%u radio=%u",
channel_id, (unsigned long long)node_id, member[8], member[9], !!(member[10] & CHAT_MEMBER_FLAG_RADIO));
chat_event_post(inst, CHAT_EVT_MEMBER_UPDATED, evt, 1 + (int)cl + 1 + CHAT_MEMBER_DISPLAY_SIZE);
} else {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "chat_member: cannot build update ch=%s node=%016llx",
channel_id, (unsigned long long)node_id);
}
return;
}
sqlite3_finalize(st);

7
src/chat/chat_member.h

@ -2,14 +2,14 @@
* chat_member.h — единая структура мембера для отображения в GUI
*
* Используется chatgui (desktop), headless CLI, Android.
* Все три потребителя получают данные через chat_core_get_member_list(),
* а не прямыми SQL-запросами.
* Live-снимки для всех потребителей формирует chat_core_get_member_list() в uasync-потоке.
* Android дополняет ими свой JSON-список с расширенными свойствами участников.
*
* Формат на проводе (ручная сериализация, фиксированный размер 79 байт):
* [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
* [10] flags uint8_t 0x01=supernode 0x02=admin 0x04=moder 0x08=deleted 0x10=radio
* [11-12] rtt uint16_t LE (ms, 0xFFFF=нет данных)
* [13] nat_type uint8_t ADDR_TYPE_*
* [14] storage uint8_t
@ -30,6 +30,7 @@ extern "C" {
#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_DISPLAY_SIZE 79

9
src/routing_layer/topo_group.c

@ -896,7 +896,14 @@ void topo_group_set_radio(struct TOPO_GROUP* group, int on) {
group->radio_active = v;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "set_radio: %s grp=%016llx ch=%s",
v ? "ON" : "OFF", (unsigned long long)group->group_id, group->channel_id);
topo_group_update_my_nodeinfo(group->instance, group);
if (topo_group_update_my_nodeinfo(group->instance, group) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "set_radio: cannot update local NODEINFO grp=%016llx ch=%s radio=%u",
(unsigned long long)group->group_id, group->channel_id, v);
return;
}
/* Свой мембер обновляется через те же подписки, что и удалённые BGP-узлы. */
for (struct topo_node_cbk_entry* cb = group->node_cbks; cb; cb = cb->next)
cb->fn(group, group->instance->node_id, TOPO_NODE_EVENT_UPDATE, cb->arg);
if (group->senders_list) {
struct ll_entry* se = group->senders_list->head;
while (se) {

Loading…
Cancel
Save