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

+83
View File
@@ -20,6 +20,17 @@ QVariant MemberListModel::data(const QModelIndex& index, int role) const {
if (it != m_cache.end()) {
if (role == Qt::DisplayRole) return it->name;
if (role == Qt::DecorationRole) return QVariant::fromValue(QIcon(it->avatar));
if (role == Qt::UserRole + 1) {
QString sub;
if (it->rtt >= 0) sub += QString("rtt=%1ms").arg(it->rtt);
if (it->natType >= 0) {
static const char* nat[] = {"NET","DIR","EIM","STR"};
const char* nt = (it->natType <= 3) ? nat[it->natType] : "?";
if (!sub.isEmpty()) sub += " ";
sub += nt;
}
return sub;
}
if (role == Qt::ToolTipRole)
return QString(it->online ? "online" : "offline") + " | 0x" +
QString("%1").arg(it->nodeId, 16, 16, QChar('0'));
@@ -36,6 +47,7 @@ QVariant MemberListModel::data(const QModelIndex& index, int role) const {
void MemberListModel::setChannel(const QString& channelId) {
beginResetModel();
m_channelId = channelId;
m_db->cleanOrphanedPeers(channelId);
m_totalCount = m_db ? m_db->getChannelMemberCount(channelId) : 0;
m_cache.clear();
m_pendingFrom = -1;
@@ -84,12 +96,83 @@ void MemberListModel::loadBatch(int from, int count) {
QColor c = members[i].online ? QColor("#4CAF50") : QColor("#9E9E9E");
item.avatar = makeAvatar(c, item.name[0]);
}
// batch-загрузка RTT и NAT типа из node_addresses
QStringList idList;
for (int i = 0; i < members.size(); i++)
idList.append(QString::number(members[i].nodeId));
QString ids = idList.isEmpty() ? QString("0") : idList.join(",");
QByteArray sql = QString(
"SELECT node_id, MIN(rtt), MIN(addr_type) FROM node_addresses"
" WHERE node_id IN (%1) AND rtt > 0 GROUP BY node_id"
).arg(ids).toUtf8();
sqlite3_stmt* na = nullptr;
if (sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &na, nullptr) == SQLITE_OK) {
while (sqlite3_step(na) == SQLITE_ROW) {
quint64 nid = (quint64)sqlite3_column_int64(na, 0);
int rttVal = sqlite3_column_int(na, 1);
int at = sqlite3_column_int(na, 2);
for (int i = 0; i < members.size(); i++) {
if (members[i].nodeId == nid) {
int row = from + i;
auto it = m_cache.find(row);
if (it != m_cache.end()) {
it->rtt = rttVal;
it->natType = at;
}
break;
}
}
}
sqlite3_finalize(na);
}
evictDistant(from + BATCH / 2);
int last = from + (int)members.size() - 1;
if (last >= from) emit dataChanged(index(from), index(last));
}
void MemberListModel::refreshRtt() {
if (m_cache.isEmpty() || !m_db || !m_db->m_db) return;
QStringList idList;
for (auto it = m_cache.begin(); it != m_cache.end(); ++it)
idList.append(QString::number(it->nodeId));
if (idList.isEmpty()) return;
QString ids = idList.join(",");
QByteArray sql = QString(
"SELECT node_id, MIN(rtt), MIN(addr_type) FROM node_addresses"
" WHERE node_id IN (%1) AND rtt > 0 GROUP BY node_id"
).arg(ids).toUtf8();
sqlite3_stmt* na = nullptr;
if (sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &na, nullptr) != SQLITE_OK) return;
QList<int> changed;
while (sqlite3_step(na) == SQLITE_ROW) {
quint64 nid = (quint64)sqlite3_column_int64(na, 0);
int rttVal = sqlite3_column_int(na, 1);
int at = sqlite3_column_int(na, 2);
for (auto it = m_cache.begin(); it != m_cache.end(); ++it) {
if (it->nodeId == nid) {
if (it->rtt != rttVal || it->natType != at) {
it->rtt = rttVal;
it->natType = at;
changed.append(it.key());
}
break;
}
}
}
sqlite3_finalize(na);
for (int row : changed) emit dataChanged(index(row), index(row), {Qt::UserRole + 1});
}
void MemberListModel::evictDistant(int centerRow) {
if (m_cache.size() <= MAX_CACHE) return;
int half = MAX_CACHE / 2;