Browse Source

Expose signed storage roles independently of route priority

master
evgeny 6 days ago
parent
commit
e642551dfe
  1. 14
      src/chat/chat_member.c
  2. 6
      src/chat/chat_member.h
  3. 2
      tools/chatgui/src/avatars/avatarmanager.cpp

14
src/chat/chat_member.c

@ -87,6 +87,7 @@ void chat_core_serialize_member(const struct chat_member_display* src, uint8_t*
memcpy(dst + 15, src->name, 64);
mf_put64(dst + 79, src->avatar_server);
memcpy(dst + 87, src->avatar_file, 69);
dst[156] = src->storage_role;
}
int chat_core_deserialize_member(const uint8_t* src, struct chat_member_display* dst) {
@ -102,6 +103,7 @@ int chat_core_deserialize_member(const uint8_t* src, struct chat_member_display*
dst->name[63] = '\0';
dst->avatar_server = mf_get64(src + 79);
memcpy(dst->avatar_file, src + 87, 69); dst->avatar_file[68] = 0;
dst->storage_role = src[156];
return 0;
}
@ -120,6 +122,12 @@ static void member_avatar(struct chat_member_display* m, const char* userinfo) {
if (m->avatar_server) memcpy(m->avatar_file, file, 69);
}
static int member_storage_role(const char* tags, sqlite3_stmt* st, int source, int signature, int deleted) {
char role[16];
return !deleted && sqlite3_column_int(st, source) == 0 && sqlite3_column_bytes(st, signature) == 64 &&
tags && json_flat_get(tags, "storage", role, sizeof(role)) == 0 && !strcmp(role, "yes");
}
/* ─── запрос списка мемберов ─── */
int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count) {
@ -140,7 +148,7 @@ int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uin
snprintf(sql, sizeof(sql),
"SELECT p.node_id, COALESCE(n.name,''),"
" COALESCE(p.local_nick,''), COALESCE(p.adm_tags,''),"
" COALESCE(p.storage,0), COALESCE(p.deleted,0), COALESCE(p.userinfo,'')"
" COALESCE(p.storage,0), COALESCE(p.deleted,0), COALESCE(p.userinfo,''),p.source,p.adm_tags_sig"
" FROM \"%s\" p LEFT JOIN nodes n ON p.node_id=n.node_id"
" ORDER BY p.node_id ASC", peers_tbl);
@ -168,6 +176,7 @@ int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uin
const char* local_nick = (const char*)sqlite3_column_text(st, 2);
const char* adm_tags = (const char*)sqlite3_column_text(st, 3);
m->storage = (uint8_t)sqlite3_column_int(st, 4);
m->storage_role = member_storage_role(adm_tags, st, 7, 8, sqlite3_column_int(st, 5));
m->is_self = (uint8_t)(m->node_id == my_id ? 1 : 0);
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;
@ -268,7 +277,7 @@ int chat_core_get_single_member(struct UTUN_INSTANCE* inst, const char* ch_id, u
snprintf(sql, sizeof(sql),
"SELECT COALESCE(n.name,''),"
" COALESCE(p.local_nick,''), COALESCE(p.adm_tags,''),"
" COALESCE(p.storage,0), COALESCE(p.deleted,0), COALESCE(p.userinfo,'')"
" COALESCE(p.storage,0), COALESCE(p.deleted,0), COALESCE(p.userinfo,''),p.source,p.adm_tags_sig"
" FROM \"%s\" p LEFT JOIN nodes n ON p.node_id=n.node_id"
" WHERE p.node_id=?", peers_tbl);
@ -284,6 +293,7 @@ int chat_core_get_single_member(struct UTUN_INSTANCE* inst, const char* ch_id, u
const char* local_nick = (const char*)sqlite3_column_text(st, 1);
const char* adm_tags = (const char*)sqlite3_column_text(st, 2);
m.storage = (uint8_t)sqlite3_column_int(st, 3);
m.storage_role = member_storage_role(adm_tags, st, 6, 7, sqlite3_column_int(st, 4));
m.is_self = (uint8_t)(node_id == my_id ? 1 : 0);
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;

6
src/chat/chat_member.h

@ -5,7 +5,7 @@
* Live-снимки для всех потребителей формирует chat_core_get_member_list() в uasync-потоке.
* Android дополняет ими свой JSON-список с расширенными свойствами участников.
*
* Формат на проводе (ручная сериализация, фиксированный размер 156 байт):
* Формат на проводе (ручная сериализация, фиксированный размер 157 байт):
* [0-7] node_id uint64_t LE
* [8] online uint8_t
* [9] is_self uint8_t
@ -16,6 +16,7 @@
* [15-78] name char[64] local_nick если задан, иначе node name. \0-padded
* [79-86] avatar_server uint64_t LE; 0 = нет аватарки
* [87-155] avatar_file char[69], sha256.png с NUL
* [156] storage_role uint8_t, подписанная роль, независимо от сетевого приоритета storage
*/
#ifndef CHAT_MEMBER_H
@ -34,7 +35,7 @@ extern "C" {
#define CHAT_MEMBER_FLAG_DELETED 0x08
#define CHAT_MEMBER_FLAG_RADIO 0x10
#define CHAT_MEMBER_DISPLAY_SIZE 156
#define CHAT_MEMBER_DISPLAY_SIZE 157
/* Получить всех мемберов канала. out = u_malloc-массив, count = количество. */
int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count);
@ -58,6 +59,7 @@ struct chat_member_display {
char name[64];
uint64_t avatar_server;
char avatar_file[69];
uint8_t storage_role;
};
void chat_core_serialize_member(const struct chat_member_display* src, uint8_t* dst);

2
tools/chatgui/src/avatars/avatarmanager.cpp

@ -89,7 +89,7 @@ void AvatarManager::onMembers(const QString& channel, int count, const uint8_t*
chat_member_display member{}; chat_core_deserialize_member(data + i * CHAT_MEMBER_DISPLAY_SIZE, &member);
const QString context = key(group, member.node_id); seen.insert(context);
if (member.flags & CHAT_MEMBER_FLAG_DELETED) { removeMember(channel, member.node_id); continue; }
if (member.storage) m_servers[group][member.node_id] = QString::fromUtf8(member.name);
if (member.storage_role) m_servers[group][member.node_id] = QString::fromUtf8(member.name);
else m_servers[group].remove(member.node_id);
Ref ref{group, member.node_id, member.avatar_server, QString::fromLatin1(member.avatar_file).left(64)};
if (!ref.server || !mf_avatar_file_valid(member.avatar_file)) { ref.server = 0; ref.hash.clear(); }

Loading…
Cancel
Save