etc/rtt: UPSERT node_update_verified; gui: account delegate (rtt+nat subline), context menu member props (admin/supernode), cleanOrphanedPeers, refreshRtt timer 2s

This commit is contained in:
Evgeny committed 2026-07-22 01:15:33 +03:00
1 parent c367144776
commit 090acc1f00
14 files changed
+496 -32

No files matched your search

+1 -1
View File
@@ -307,7 +307,7 @@ void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uin
DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping_update_rtt: node=%016llx rtt=%u (%llu) group=%016llx",
(unsigned long long)node_id, (unsigned)rtt, (unsigned long long)now, (unsigned long long)g->group_id);
if (groups->instance && groups->instance->topo_sqlite_db)
topo_node_sqlite_nodeinfo_updated(groups->instance->topo_sqlite_db, node_id);
topo_node_sqlite_update_rtt(groups->instance->topo_sqlite_db, node_id, rtt);
}
ge = ge->next;
}
+88 -31
View File
@@ -2,6 +2,7 @@
#include "topo_node.h"
#include "etcp_connections.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include <string.h>
#include <stdio.h>
@@ -248,30 +249,39 @@ int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
if (!db || !channel_id || !name || !x25519_pub || !ed25519_pub || !signature) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[512];
snprintf(sql, sizeof(sql),
"CREATE TABLE IF NOT EXISTS \"%s\" (" // таблица мемберов канала
const char* ddl_tmpl =
"CREATE TABLE IF NOT EXISTS \"%s\" ("
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
" node_id INTEGER NOT NULL UNIQUE," // ид мембера группы
" x25519_pubkey BLOB NOT NULL," // ключ мембера для шифрования
" ed25519_pubkey BLOB NOT NULL," // ключ мембера для подписи
" join_sig BLOB NOT NULL," // подпись мембера неизменяемая (при присоединении) сh_x25519_pubkey(32) || ch_ed25519_pubkey(32) || node_id(8 LE) || node_x25519_pubkey(32) || join_ts(8 LE)
" join_ts INTEGER NOT NULL," // время присоединения
" update_sig BLOB," // подпись мембера изменяемая join_sig(64) || update_ts(8) || userinfo (NUL-terminated)
" update_ts INTEGER DEFAULT 0,"// время подписи
" userinfo TEXT NOT NULL DEFAULT ''," // имя/метаданные узла в канале (json_flat style)
" creator_sig BLOB," // валидация мембера админом канала
" adm_tags TEXT," // тэги которые может менять админ (json_flat style)
" adm_tags_sig BLOB," // подпись тэгов adm_tags (может быть подписана ключом суперадмина или админов - проверяем перебором)
" node_type INTEGER NOT NULL DEFAULT 0," // ENUM(0-'PRIV',1-'NAT',2-'EIM-NAT',3-'PUBLIC',4-SUPERNODE) тип ноды - private (только нода подключается), nat (односторонние подключения), eim-nat (доступны подключения но надо запрашивать ip), public - на прямых ip (но может быть недоступна в чебурнетах), supernode - на прямых ip, рекомендуемая для подключения
" node_RTT INTEGER" // задержка в ms
")", peers_tbl);
char* err = NULL;
sqlite3_exec(db, sql, NULL, NULL, &err);
if (err) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "topo_node_sqlite_channel_put peers: %s", err); sqlite3_free(err); }
snprintf(sql, sizeof(sql),
" node_id INTEGER NOT NULL UNIQUE,"
" x25519_pubkey BLOB NOT NULL,"
" ed25519_pubkey BLOB NOT NULL,"
" join_sig BLOB NOT NULL,"
" join_ts INTEGER NOT NULL,"
" update_sig BLOB,"
" update_ts INTEGER DEFAULT 0,"
" userinfo TEXT NOT NULL DEFAULT '',"
" creator_sig BLOB,"
" adm_tags TEXT,"
" adm_tags_sig BLOB,"
" node_type INTEGER NOT NULL DEFAULT 0,"
" node_RTT INTEGER"
")";
int ddl_sz = snprintf(NULL, 0, ddl_tmpl, peers_tbl);
char* ddl = u_malloc(ddl_sz + 1);
if (ddl) {
snprintf(ddl, ddl_sz + 1, ddl_tmpl, peers_tbl);
char* err = NULL;
sqlite3_exec(db, ddl, NULL, NULL, &err);
if (err) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "topo_node_sqlite_channel_put peers: %s", err); sqlite3_free(err); }
u_free(ddl);
}
char idx_sql[128];
snprintf(idx_sql, sizeof(idx_sql),
"CREATE INDEX IF NOT EXISTS \"idx_%s_type_rtt\" ON \"%s\" (node_type, node_RTT)", peers_tbl, peers_tbl);
sqlite3_exec(db, sql, NULL, NULL, NULL);
sqlite3_exec(db, idx_sql, NULL, NULL, NULL);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db,
@@ -324,17 +334,24 @@ int topo_node_sqlite_member_put(sqlite3* db, const char* channel_id, uint64_t no
int topo_node_sqlite_node_update_verified(sqlite3* db, uint64_t node_id,
const char* name, const uint8_t* x25519, const uint8_t* ed25519, uint64_t update_ts) {
if (!db || !name || !x25519 || !ed25519) return -1;
if (!db || !x25519 || !ed25519) return -1;
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db,
"UPDATE nodes SET name=?, x25519_pubkey=?, ed25519_pubkey=?, update_ts=?"
" WHERE node_id=? AND (update_ts IS NULL OR update_ts < ?)", -1, &stmt, NULL) != SQLITE_OK) return -1;
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 2, x25519, 32, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 3, ed25519, 32, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 4, (sqlite3_int64)update_ts);
sqlite3_bind_int64(stmt, 5, (sqlite3_int64)node_id);
sqlite3_bind_int64(stmt, 6, (sqlite3_int64)update_ts);
"INSERT INTO nodes(node_id, name, x25519_pubkey, ed25519_pubkey, update_ts)"
" VALUES(?,?,?,?,?)"
" ON CONFLICT(node_id) DO UPDATE SET"
" name=CASE WHEN excluded.name IS NOT NULL AND excluded.name != ''"
" THEN excluded.name ELSE nodes.name END,"
" x25519_pubkey=excluded.x25519_pubkey,"
" ed25519_pubkey=excluded.ed25519_pubkey,"
" update_ts=CASE WHEN nodes.update_ts IS NULL OR excluded.update_ts > nodes.update_ts"
" THEN excluded.update_ts ELSE nodes.update_ts END",
-1, &stmt, NULL) != SQLITE_OK) return -1;
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
sqlite3_bind_text(stmt, 2, name && name[0] ? name : "", -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 3, x25519, 32, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 4, ed25519, 32, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 5, (sqlite3_int64)update_ts);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
return 0;
@@ -584,3 +601,43 @@ int topo_node_sqlite_nodeinfo_updated(sqlite3* db, uint64_t node_id) {
(unsigned long long)node_id, best_at, base_type);
return 0;
}
void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt) {
if (!db) return;
{
sqlite3_stmt* s = NULL;
if (sqlite3_prepare_v2(db,
"UPDATE node_addresses SET rtt=? WHERE node_id=?",
-1, &s, NULL) == SQLITE_OK) {
sqlite3_bind_int(s, 1, (int)rtt);
sqlite3_bind_int64(s, 2, (sqlite3_int64)node_id);
sqlite3_step(s);
sqlite3_finalize(s);
}
}
{
sqlite3_stmt* s = NULL;
if (sqlite3_prepare_v2(db,
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'peers\\_%' ESCAPE '\\'",
-1, &s, NULL) != SQLITE_OK) return;
char sql[256];
while (sqlite3_step(s) == SQLITE_ROW) {
const char* tbl = (const char*)sqlite3_column_text(s, 0);
snprintf(sql, sizeof(sql),
"UPDATE \"%s\" SET node_RTT=? WHERE node_id=?", tbl);
sqlite3_stmt* u = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &u, NULL) == SQLITE_OK) {
sqlite3_bind_int(u, 1, (int)rtt);
sqlite3_bind_int64(u, 2, (sqlite3_int64)node_id);
sqlite3_step(u); sqlite3_finalize(u);
}
}
sqlite3_finalize(s);
}
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "sqlite_update_rtt: node=%016llx rtt=%u",
(unsigned long long)node_id, (unsigned)rtt);
}
+3
View File
@@ -52,4 +52,7 @@ int topo_node_sqlite_get_ed25519_pubkey(sqlite3* db, uint64_t node_id, uint8_t p
/** Пересчитывает node_type во всех peers_* таблицах на основе addr_type из node_addresses */
int topo_node_sqlite_nodeinfo_updated(sqlite3* db, uint64_t node_id);
/** Обновляет RTT узла: node_addresses.rtt и все peers_*.node_RTT */
void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt);
#endif