Browse Source

Classify chat supernodes independently of address type

master
evgeny 1 week ago
parent
commit
1c499dc230
  1. 62
      src/routing_layer/topo_node_sqlite.c
  2. 12
      src/routing_layer/topo_node_sqlite.h

62
src/routing_layer/topo_node_sqlite.c

@ -406,7 +406,7 @@ int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
" adm_tags_sig BLOB," /* Ed25519 подпись над adm_tags (64 байта) канальным ключом */
" node_type INTEGER NOT NULL DEFAULT 0," /* вычисляемый тип узла (topo_node_sqlite_nodeinfo_updated):
0=неизвестно 1=прямой(addr_type NETIF/DIRECT/NAT_STRICT)
2=EIM NAT 3=(не исп.) 4=суперузел(DIRECT+adm_tags.supernode=yes) */
2=EIM NAT 3=(не исп.) 4=суперузел(adm_tags.supernode=yes) */
" node_RTT INTEGER," /* RTT до узла в мс, часть индекса (node_type, node_RTT) */
" connected INTEGER NOT NULL DEFAULT 0," /* 1 = было активное подключение к узлу */
" storage INTEGER NOT NULL DEFAULT 0," /* 1 = приоритетный хранитель аттачей */
@ -837,8 +837,8 @@ int topo_node_sqlite_nodeinfo_updated(sqlite3* db, uint64_t node_id) {
const char* tags = (const char*)sqlite3_column_text(a, 0);
if (tags) {
char buf[64];
if (json_flat_get(tags, "supernode", buf, sizeof(buf)) == 0 && strcmp(buf, "yes") == 0) node_type = 4;
if (best_at == ADDR_TYPE_DIRECT && base_type == 1) {
if (json_flat_get(tags, "supernode", buf, sizeof(buf)) == 0 && strcmp(buf, "yes") == 0) node_type = 4;
if (json_flat_get(tags, "storage", buf, sizeof(buf)) == 0 && strcmp(buf, "yes") == 0) is_storage = 1;
}
is_deleted = adm_tags_deleted(tags);
@ -1146,6 +1146,61 @@ int topo_node_sqlite_set_connected(sqlite3* db, const char* channel_id, uint64_t
return (rc == SQLITE_DONE) ? 0 : -1;
}
/* Читаем тип из уже проверенного snapshot, а не из устаревшей проекции nodes.client_type. */
int topo_node_sqlite_get_connect_peers(sqlite3* db, const char* channel_id,
struct topo_connect_peer** out, size_t* out_count) {
if (!db || !channel_id || !out || !out_count) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid group candidate query arguments"); return -1;
}
*out = NULL; *out_count = 0;
char table[80]; peers_table_name(channel_id, table, sizeof(table));
char sql[512];
snprintf(sql, sizeof(sql),
"SELECT p.node_id,p.adm_tags,s.timestamp,s.record FROM \"%s\" p"
" LEFT JOIN node_snapshots s ON s.node_id=p.node_id WHERE p.deleted=0"
" ORDER BY p.connected DESC,p.node_RTT IS NULL,p.node_RTT,p.node_id", table);
sqlite3_stmt* stmt = NULL;
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group candidate query channel=%s: %s", channel_id, sqlite3_errmsg(db)); return -1;
}
struct topo_connect_peer* peers = NULL;
size_t count = 0, capacity = 0;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
if (count == capacity) {
size_t next = capacity ? capacity * 2 : 16;
struct topo_connect_peer* list = u_realloc(peers, next * sizeof(*list));
if (!list) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group candidate query allocation failed channel=%s", channel_id); break; }
peers = list; capacity = next;
}
struct topo_connect_peer* peer = &peers[count++];
*peer = (struct topo_connect_peer){ .node_id = (uint64_t)sqlite3_column_int64(stmt, 0), .client_type = UINT8_MAX };
const char* tags = (const char*)sqlite3_column_text(stmt, 1);
char value[16];
peer->supernode = tags && json_flat_get(tags, "supernode", value, sizeof(value)) == 0 && strcmp(value, "yes") == 0;
const void* record = sqlite3_column_blob(stmt, 3);
if (record) {
struct TOPOMSG_NODE header;
if (sqlite3_column_bytes(stmt, 3) < (int)sizeof(header)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "short candidate snapshot channel=%s node=%016llx", channel_id,
(unsigned long long)peer->node_id); break;
}
memcpy(&header, record, sizeof(header));
if (header.node_id != peer->node_id || header.timestamp != (uint64_t)sqlite3_column_int64(stmt, 2) ||
header.client_type > CLIENT_TYPE_MOBILE) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid candidate snapshot channel=%s node=%016llx type=%u", channel_id,
(unsigned long long)peer->node_id, header.client_type); break;
}
peer->client_type = header.client_type;
}
}
if (rc != SQLITE_DONE) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group candidate read failed channel=%s rc=%d: %s", channel_id, rc, sqlite3_errmsg(db));
sqlite3_finalize(stmt); u_free(peers); return -1;
}
sqlite3_finalize(stmt); *out = peers; *out_count = count; return 0;
}
int topo_node_sqlite_get_connected_peers(sqlite3* db, const char* channel_id,
uint64_t** out_ids, int* out_count) {
if (!db || !channel_id || !out_ids || !out_count) return -1;
@ -1198,8 +1253,7 @@ int topo_node_sqlite_get_supernode_peers(sqlite3* db, const char* channel_id,
*out_ids = NULL; *out_count = 0;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[256]; snprintf(sql, sizeof(sql),
"SELECT p.node_id FROM \"%s\" p WHERE p.node_type=4 AND p.deleted=0"
" AND EXISTS (SELECT 1 FROM node_addresses na WHERE na.node_id=p.node_id AND na.family IN (4,6))",
"SELECT p.node_id FROM \"%s\" p WHERE p.node_type=4 AND p.deleted=0",
peers_tbl);
sqlite3_stmt* st = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) return -1;

12
src/routing_layer/topo_node_sqlite.h

@ -107,6 +107,18 @@ void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt);
struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id);
int topo_node_sqlite_set_connected(sqlite3* db, const char* channel_id, uint64_t node_id, int connected);
/* Кандидат CHAT-подключения: роль канальная, тип устройства из подписанного snapshot.
* UINT8_MAX означает отсутствие сведений о типе; адреса не ограничивают выборку. */
struct topo_connect_peer {
uint64_t node_id;
uint8_t client_type, supernode;
};
/* Все неудалённые участники, включая self; сначала connected, затем RTT/node_id.
* 0/-1; массив принадлежит вызывающему и освобождается u_free(). */
int topo_node_sqlite_get_connect_peers(sqlite3* db, const char* channel_id,
struct topo_connect_peer** out, size_t* out_count);
int topo_node_sqlite_get_connected_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count);
int topo_node_sqlite_get_public_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count, uint64_t self_node_id);
int topo_node_sqlite_get_local_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count, uint64_t self_node_id);

Loading…
Cancel
Save