Browse Source

Include avatar references in member snapshots and change events

master
evgeny 6 days ago
parent
commit
61ef23b885
  1. 25
      src/chat/chat_member.c
  2. 8
      src/chat/chat_member.h
  3. 1
      src/chat/member_sync.c

25
src/chat/chat_member.c

@ -84,6 +84,8 @@ void chat_core_serialize_member(const struct chat_member_display* src, uint8_t*
dst[13] = src->nat_type; dst[13] = src->nat_type;
dst[14] = src->storage; dst[14] = src->storage;
memcpy(dst + 15, src->name, 64); memcpy(dst + 15, src->name, 64);
mf_put64(dst + 79, src->avatar_server);
memcpy(dst + 87, src->avatar_file, 69);
} }
int chat_core_deserialize_member(const uint8_t* src, struct chat_member_display* dst) { int chat_core_deserialize_member(const uint8_t* src, struct chat_member_display* dst) {
@ -97,9 +99,26 @@ int chat_core_deserialize_member(const uint8_t* src, struct chat_member_display*
dst->storage = src[14]; dst->storage = src[14];
memcpy(dst->name, src + 15, 64); memcpy(dst->name, src + 15, 64);
dst->name[63] = '\0'; dst->name[63] = '\0';
dst->avatar_server = mf_get64(src + 79);
memcpy(dst->avatar_file, src + 87, 69); dst->avatar_file[68] = 0;
return 0; return 0;
} }
static void member_avatar(struct chat_member_display* m, const char* userinfo) {
m->avatar_server = 0; memset(m->avatar_file, 0, sizeof(m->avatar_file));
char server[MS_USERINFO_MAX + 1], file[MS_USERINFO_MAX + 1];
if (!userinfo || json_flat_get(userinfo, "avatar_server", server, sizeof(server)) < 0 ||
json_flat_get(userinfo, "avatar_file", file, sizeof(file)) < 0) return;
if (strlen(server) != 16 || !mf_avatar_file_valid(file)) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "avatar: invalid profile reference node=%016llx", (unsigned long long)m->node_id); return;
}
for (int i = 0; i < 16; i++) if (!((server[i] >= '0' && server[i] <= '9') || (server[i] >= 'a' && server[i] <= 'f'))) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "avatar: invalid server ID node=%016llx", (unsigned long long)m->node_id); return;
}
m->avatar_server = strtoull(server, NULL, 16);
if (m->avatar_server) memcpy(m->avatar_file, file, 69);
}
/* ─── запрос списка мемберов ─── */ /* ─── запрос списка мемберов ─── */
int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count) { int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count) {
@ -120,7 +139,7 @@ int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uin
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"SELECT p.node_id, COALESCE(n.name,'')," "SELECT p.node_id, COALESCE(n.name,''),"
" COALESCE(p.local_nick,''), COALESCE(p.adm_tags,'')," " COALESCE(p.local_nick,''), COALESCE(p.adm_tags,''),"
" COALESCE(p.storage,0), COALESCE(p.deleted,0)" " COALESCE(p.storage,0), COALESCE(p.deleted,0), COALESCE(p.userinfo,'')"
" FROM \"%s\" p LEFT JOIN nodes n ON p.node_id=n.node_id" " FROM \"%s\" p LEFT JOIN nodes n ON p.node_id=n.node_id"
" ORDER BY p.node_id ASC", peers_tbl); " ORDER BY p.node_id ASC", peers_tbl);
@ -142,6 +161,7 @@ int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uin
} }
struct chat_member_display* m = &members[cnt]; struct chat_member_display* m = &members[cnt];
m->node_id = (uint64_t)sqlite3_column_int64(st, 0); m->node_id = (uint64_t)sqlite3_column_int64(st, 0);
member_avatar(m, (const char*)sqlite3_column_text(st, 6));
m->online = (uint8_t)chat_core_member_online(inst, ch_id, m->node_id); m->online = (uint8_t)chat_core_member_online(inst, ch_id, m->node_id);
const char* node_name = (const char*)sqlite3_column_text(st, 1); const char* node_name = (const char*)sqlite3_column_text(st, 1);
const char* local_nick = (const char*)sqlite3_column_text(st, 2); const char* local_nick = (const char*)sqlite3_column_text(st, 2);
@ -247,7 +267,7 @@ int chat_core_get_single_member(struct UTUN_INSTANCE* inst, const char* ch_id, u
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"SELECT COALESCE(n.name,'')," "SELECT COALESCE(n.name,''),"
" COALESCE(p.local_nick,''), COALESCE(p.adm_tags,'')," " COALESCE(p.local_nick,''), COALESCE(p.adm_tags,''),"
" COALESCE(p.storage,0), COALESCE(p.deleted,0)" " COALESCE(p.storage,0), COALESCE(p.deleted,0), COALESCE(p.userinfo,'')"
" FROM \"%s\" p LEFT JOIN nodes n ON p.node_id=n.node_id" " FROM \"%s\" p LEFT JOIN nodes n ON p.node_id=n.node_id"
" WHERE p.node_id=?", peers_tbl); " WHERE p.node_id=?", peers_tbl);
@ -257,6 +277,7 @@ int chat_core_get_single_member(struct UTUN_INSTANCE* inst, const char* ch_id, u
struct chat_member_display m; struct chat_member_display m;
m.node_id = node_id; m.node_id = node_id;
member_avatar(&m, (const char*)sqlite3_column_text(st, 5));
m.online = (uint8_t)chat_core_member_online(inst, ch_id, node_id); m.online = (uint8_t)chat_core_member_online(inst, ch_id, node_id);
const char* node_name = (const char*)sqlite3_column_text(st, 0); const char* node_name = (const char*)sqlite3_column_text(st, 0);
const char* local_nick = (const char*)sqlite3_column_text(st, 1); const char* local_nick = (const char*)sqlite3_column_text(st, 1);

8
src/chat/chat_member.h

@ -5,7 +5,7 @@
* Live-снимки для всех потребителей формирует chat_core_get_member_list() в uasync-потоке. * Live-снимки для всех потребителей формирует chat_core_get_member_list() в uasync-потоке.
* Android дополняет ими свой JSON-список с расширенными свойствами участников. * Android дополняет ими свой JSON-список с расширенными свойствами участников.
* *
* Формат на проводе (ручная сериализация, фиксированный размер 79 байт): * Формат на проводе (ручная сериализация, фиксированный размер 156 байт):
* [0-7] node_id uint64_t LE * [0-7] node_id uint64_t LE
* [8] online uint8_t * [8] online uint8_t
* [9] is_self uint8_t * [9] is_self uint8_t
@ -14,6 +14,8 @@
* [13] nat_type uint8_t ADDR_TYPE_* * [13] nat_type uint8_t ADDR_TYPE_*
* [14] storage uint8_t * [14] storage uint8_t
* [15-78] name char[64] local_nick если задан, иначе node name. \0-padded * [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
*/ */
#ifndef CHAT_MEMBER_H #ifndef CHAT_MEMBER_H
@ -32,7 +34,7 @@ extern "C" {
#define CHAT_MEMBER_FLAG_DELETED 0x08 #define CHAT_MEMBER_FLAG_DELETED 0x08
#define CHAT_MEMBER_FLAG_RADIO 0x10 #define CHAT_MEMBER_FLAG_RADIO 0x10
#define CHAT_MEMBER_DISPLAY_SIZE 79 #define CHAT_MEMBER_DISPLAY_SIZE 156
/* Получить всех мемберов канала. out = u_malloc-массив, count = количество. */ /* Получить всех мемберов канала. out = u_malloc-массив, count = количество. */
int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count); int chat_core_get_member_list(struct UTUN_INSTANCE* inst, const char* ch_id, uint8_t** out, int* count);
@ -54,6 +56,8 @@ struct chat_member_display {
uint8_t nat_type; uint8_t nat_type;
uint8_t storage; uint8_t storage;
char name[64]; char name[64];
uint64_t avatar_server;
char avatar_file[69];
}; };
void chat_core_serialize_member(const struct chat_member_display* src, uint8_t* dst); void chat_core_serialize_member(const struct chat_member_display* src, uint8_t* dst);

1
src/chat/member_sync.c

@ -706,6 +706,7 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
static void member_committed(struct UTUN_INSTANCE* inst, const char* ns, uint64_t node_id) { static void member_committed(struct UTUN_INSTANCE* inst, const char* ns, uint64_t node_id) {
merkle_sync_changed(inst, ns); merkle_sync_changed(inst, ns);
_fire_props_changed(inst, node_id, NULL, ns);
struct TOPO_GROUP* g = inst->topo_groups ? topo_groups_find(inst->topo_groups, strtoull(ns, NULL, 10)) : NULL; struct TOPO_GROUP* g = inst->topo_groups ? topo_groups_find(inst->topo_groups, strtoull(ns, NULL, 10)) : NULL;
struct ETCP_CONN* conn = instance_find_conn(inst, node_id); struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
if (g && g->group_type == TOPO_GROUP_TYPE_CHAT) { if (g && g->group_type == TOPO_GROUP_TYPE_CHAT) {

Loading…
Cancel
Save