Raven Core  3.0.0
P2P Digital Currency
peertablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Copyright (c) 2017-2019 The Raven Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "peertablemodel.h"
7 
8 #include "clientmodel.h"
9 #include "guiconstants.h"
10 #include "guiutil.h"
11 
12 #include "validation.h" // for cs_main
13 #include "sync.h"
14 
15 #include <QDebug>
16 #include <QList>
17 #include <QTimer>
18 
19 bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
20 {
21  const CNodeStats *pLeft = &(left.nodeStats);
22  const CNodeStats *pRight = &(right.nodeStats);
23 
24  if (order == Qt::DescendingOrder)
25  std::swap(pLeft, pRight);
26 
27  switch(column)
28  {
30  return pLeft->nodeid < pRight->nodeid;
32  return pLeft->addrName.compare(pRight->addrName) < 0;
34  return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
36  return pLeft->dMinPing < pRight->dMinPing;
38  return pLeft->nSendBytes < pRight->nSendBytes;
40  return pLeft->nRecvBytes < pRight->nRecvBytes;
41  }
42 
43  return false;
44 }
45 
46 // private implementation
48 {
49 public:
51  QList<CNodeCombinedStats> cachedNodeStats;
55  Qt::SortOrder sortOrder;
57  std::map<NodeId, int> mapNodeRows;
58 
60  void refreshPeers()
61  {
62  {
63  cachedNodeStats.clear();
64  std::vector<CNodeStats> vstats;
65  if(g_connman)
66  g_connman->GetNodeStats(vstats);
67 #if QT_VERSION >= 0x040700
68  cachedNodeStats.reserve(vstats.size());
69 #endif
70  for (const CNodeStats& nodestats : vstats)
71  {
72  CNodeCombinedStats stats;
73  stats.nodeStateStats.nMisbehavior = 0;
74  stats.nodeStateStats.nSyncHeight = -1;
75  stats.nodeStateStats.nCommonHeight = -1;
76  stats.fNodeStateStatsAvailable = false;
77  stats.nodeStats = nodestats;
78  cachedNodeStats.append(stats);
79  }
80  }
81 
82  // Try to retrieve the CNodeStateStats for each node.
83  {
84  TRY_LOCK(cs_main, lockMain);
85  if (lockMain)
86  {
87  for (CNodeCombinedStats &stats : cachedNodeStats)
88  stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats);
89  }
90  }
91 
92  if (sortColumn >= 0)
93  // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
94  qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
95 
96  // build index map
97  mapNodeRows.clear();
98  int row = 0;
99  for (const CNodeCombinedStats& stats : cachedNodeStats)
100  mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
101  }
102 
103  int size() const
104  {
105  return cachedNodeStats.size();
106  }
107 
109  {
110  if (idx >= 0 && idx < cachedNodeStats.size())
111  return &cachedNodeStats[idx];
112 
113  return 0;
114  }
115 };
116 
118  QAbstractTableModel(parent),
119  clientModel(parent),
120  timer(0)
121 {
122  columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
123  priv.reset(new PeerTablePriv());
124  // default to unsorted
125  priv->sortColumn = -1;
126 
127  // set up timer for auto refresh
128  timer = new QTimer(this);
129  connect(timer, SIGNAL(timeout()), SLOT(refresh()));
130  timer->setInterval(MODEL_UPDATE_DELAY);
131 
132  // load initial data
133  refresh();
134 }
135 
137 {
138  // Intentionally left empty
139 }
140 
142 {
143  timer->start();
144 }
145 
147 {
148  timer->stop();
149 }
150 
151 int PeerTableModel::rowCount(const QModelIndex &parent) const
152 {
153  Q_UNUSED(parent);
154  return priv->size();
155 }
156 
157 int PeerTableModel::columnCount(const QModelIndex &parent) const
158 {
159  Q_UNUSED(parent);
160  return columns.length();
161 }
162 
163 QVariant PeerTableModel::data(const QModelIndex &index, int role) const
164 {
165  if(!index.isValid())
166  return QVariant();
167 
168  CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
169 
170  if (role == Qt::DisplayRole) {
171  switch(index.column())
172  {
173  case NetNodeId:
174  return (qint64)rec->nodeStats.nodeid;
175  case Address:
176  return QString::fromStdString(rec->nodeStats.addrName);
177  case Subversion:
178  return QString::fromStdString(rec->nodeStats.cleanSubVer);
179  case Ping:
181  case Sent:
183  case Received:
185  }
186  } else if (role == Qt::TextAlignmentRole) {
187  switch (index.column()) {
188  case Ping:
189  case Sent:
190  case Received:
191  return QVariant(Qt::AlignRight | Qt::AlignVCenter);
192  default:
193  return QVariant();
194  }
195  }
196 
197  return QVariant();
198 }
199 
200 QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
201 {
202  if(orientation == Qt::Horizontal)
203  {
204  if(role == Qt::DisplayRole && section < columns.size())
205  {
206  return columns[section];
207  }
208  }
209  return QVariant();
210 }
211 
212 Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
213 {
214  if(!index.isValid())
215  return 0;
216 
217  Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
218  return retval;
219 }
220 
221 QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
222 {
223  Q_UNUSED(parent);
224  CNodeCombinedStats *data = priv->index(row);
225 
226  if (data)
227  return createIndex(row, column, data);
228  return QModelIndex();
229 }
230 
232 {
233  return priv->index(idx);
234 }
235 
237 {
238  Q_EMIT layoutAboutToBeChanged();
239  priv->refreshPeers();
240  Q_EMIT layoutChanged();
241 }
242 
244 {
245  std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
246  if (it == priv->mapNodeRows.end())
247  return -1;
248 
249  return it->second;
250 }
251 
252 void PeerTableModel::sort(int column, Qt::SortOrder order)
253 {
254  priv->sortColumn = column;
255  priv->sortOrder = order;
256  refresh();
257 }
QVariant data(const QModelIndex &index, int role) const
int getRowByNodeId(NodeId nodeid)
bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
CNodeStateStats nodeStateStats
#define TRY_LOCK(cs, name)
Definition: sync.h:178
void refreshPeers()
Pull a full list of peers from vNodes into our cache.
int sortColumn
Column to sort nodes by.
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
Get statistics from node state.
CCriticalSection cs_main
Global state.
Definition: validation.cpp:72
QStringList columns
QString formatBytes(uint64_t bytes)
Definition: guiutil.cpp:1066
CNodeCombinedStats * index(int idx)
std::string cleanSubVer
Definition: net.h:528
NodeLessThan(int nColumn, Qt::SortOrder fOrder)
Qt::SortOrder order
Qt::ItemFlags flags(const QModelIndex &index) const
CNodeStats nodeStats
Qt::SortOrder sortOrder
Order (ascending or descending) to sort nodes by.
int columnCount(const QModelIndex &parent) const
QList< CNodeCombinedStats > cachedNodeStats
Local cache of peer information.
std::unique_ptr< PeerTablePriv > priv
int size() const
uint64_t nRecvBytes
Definition: net.h:534
std::string addrName
Definition: net.h:526
int64_t NodeId
Definition: net.h:93
const CNodeCombinedStats * getNodeStats(int idx)
uint64_t nSendBytes
Definition: net.h:532
QModelIndex index(int row, int column, const QModelIndex &parent) const
Model for Raven network client.
Definition: clientmodel.h:39
QString formatPingTime(double dPingTime)
Definition: guiutil.cpp:1019
std::map< NodeId, int > mapNodeRows
Index of rows by node ID.
double dMinPing
Definition: net.h:539
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:81
void sort(int column, Qt::SortOrder order)
PeerTableModel(ClientModel *parent=0)
int rowCount(const QModelIndex &parent) const
QVariant headerData(int section, Qt::Orientation orientation, int role) const
NodeId nodeid
Definition: net.h:519