|
|
|
|
@ -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; |
|
|
|
|
|