Add network traffic graph
This commit is contained in:
parent
9269d0e96e
commit
ce14345a89
@ -232,6 +232,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "ping", &ping, true, false, false },
|
{ "ping", &ping, true, false, false },
|
||||||
{ "addnode", &addnode, true, true, false },
|
{ "addnode", &addnode, true, true, false },
|
||||||
{ "getaddednodeinfo", &getaddednodeinfo, true, true, false },
|
{ "getaddednodeinfo", &getaddednodeinfo, true, true, false },
|
||||||
|
{ "getnettotals", &getnettotals, true, true, false },
|
||||||
{ "getdifficulty", &getdifficulty, true, false, false },
|
{ "getdifficulty", &getdifficulty, true, false, false },
|
||||||
{ "getnetworkhashps", &getnetworkhashps, true, false, false },
|
{ "getnetworkhashps", &getnetworkhashps, true, false, false },
|
||||||
{ "getgenerate", &getgenerate, true, false, false },
|
{ "getgenerate", &getgenerate, true, false, false },
|
||||||
|
@ -156,6 +156,7 @@ extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHe
|
|||||||
extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp);
|
extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp);
|
||||||
extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp);
|
extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp);
|
||||||
extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp);
|
extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp);
|
||||||
|
extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fHelp);
|
||||||
|
|
||||||
extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||||
extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
|
extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
|
||||||
|
37
src/net.cpp
37
src/net.cpp
@ -426,8 +426,10 @@ void AddressCurrentlyConnected(const CService& addr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint64 CNode::nTotalBytesRecv = 0;
|
||||||
|
uint64 CNode::nTotalBytesSent = 0;
|
||||||
|
CCriticalSection CNode::cs_totalBytesRecv;
|
||||||
|
CCriticalSection CNode::cs_totalBytesSent;
|
||||||
|
|
||||||
CNode* FindNode(const CNetAddr& ip)
|
CNode* FindNode(const CNetAddr& ip)
|
||||||
{
|
{
|
||||||
@ -731,6 +733,7 @@ void SocketSendData(CNode *pnode)
|
|||||||
pnode->nLastSend = GetTime();
|
pnode->nLastSend = GetTime();
|
||||||
pnode->nSendBytes += nBytes;
|
pnode->nSendBytes += nBytes;
|
||||||
pnode->nSendOffset += nBytes;
|
pnode->nSendOffset += nBytes;
|
||||||
|
pnode->RecordBytesSent(nBytes);
|
||||||
if (pnode->nSendOffset == data.size()) {
|
if (pnode->nSendOffset == data.size()) {
|
||||||
pnode->nSendOffset = 0;
|
pnode->nSendOffset = 0;
|
||||||
pnode->nSendSize -= data.size();
|
pnode->nSendSize -= data.size();
|
||||||
@ -826,10 +829,9 @@ void ThreadSocketHandler()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vNodes.size() != nPrevNodeCount)
|
if(vNodes.size() != nPrevNodeCount) {
|
||||||
{
|
|
||||||
nPrevNodeCount = vNodes.size();
|
nPrevNodeCount = vNodes.size();
|
||||||
uiInterface.NotifyNumConnectionsChanged(vNodes.size());
|
uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1008,6 +1010,7 @@ void ThreadSocketHandler()
|
|||||||
pnode->CloseSocketDisconnect();
|
pnode->CloseSocketDisconnect();
|
||||||
pnode->nLastRecv = GetTime();
|
pnode->nLastRecv = GetTime();
|
||||||
pnode->nRecvBytes += nBytes;
|
pnode->nRecvBytes += nBytes;
|
||||||
|
pnode->RecordBytesRecv(nBytes);
|
||||||
}
|
}
|
||||||
else if (nBytes == 0)
|
else if (nBytes == 0)
|
||||||
{
|
{
|
||||||
@ -1859,3 +1862,27 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
|
|||||||
pnode->PushInventory(inv);
|
pnode->PushInventory(inv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CNode::RecordBytesRecv(uint64 bytes)
|
||||||
|
{
|
||||||
|
LOCK(cs_totalBytesRecv);
|
||||||
|
nTotalBytesRecv += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNode::RecordBytesSent(uint64 bytes)
|
||||||
|
{
|
||||||
|
LOCK(cs_totalBytesSent);
|
||||||
|
nTotalBytesSent += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 CNode::GetTotalBytesRecv()
|
||||||
|
{
|
||||||
|
LOCK(cs_totalBytesRecv);
|
||||||
|
return nTotalBytesRecv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 CNode::GetTotalBytesSent()
|
||||||
|
{
|
||||||
|
LOCK(cs_totalBytesSent);
|
||||||
|
return nTotalBytesSent;
|
||||||
|
}
|
||||||
|
14
src/net.h
14
src/net.h
@ -298,8 +298,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Network usage totals
|
||||||
|
static CCriticalSection cs_totalBytesRecv;
|
||||||
|
static CCriticalSection cs_totalBytesSent;
|
||||||
|
static uint64 nTotalBytesRecv;
|
||||||
|
static uint64 nTotalBytesSent;
|
||||||
|
|
||||||
CNode(const CNode&);
|
CNode(const CNode&);
|
||||||
void operator=(const CNode&);
|
void operator=(const CNode&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
@ -646,6 +653,13 @@ public:
|
|||||||
static bool IsBanned(CNetAddr ip);
|
static bool IsBanned(CNetAddr ip);
|
||||||
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
|
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
|
||||||
void copyStats(CNodeStats &stats);
|
void copyStats(CNodeStats &stats);
|
||||||
|
|
||||||
|
// Network stats
|
||||||
|
static void RecordBytesRecv(uint64 bytes);
|
||||||
|
static void RecordBytesSent(uint64 bytes);
|
||||||
|
|
||||||
|
static uint64 GetTotalBytesRecv();
|
||||||
|
static uint64 GetTotalBytesSent();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \
|
|||||||
moc_optionsmodel.cpp moc_overviewpage.cpp moc_paymentserver.cpp \
|
moc_optionsmodel.cpp moc_overviewpage.cpp moc_paymentserver.cpp \
|
||||||
moc_qrcodedialog.cpp moc_qvalidatedlineedit.cpp moc_qvaluecombobox.cpp \
|
moc_qrcodedialog.cpp moc_qvalidatedlineedit.cpp moc_qvaluecombobox.cpp \
|
||||||
moc_rpcconsole.cpp moc_sendcoinsdialog.cpp moc_sendcoinsentry.cpp \
|
moc_rpcconsole.cpp moc_sendcoinsdialog.cpp moc_sendcoinsentry.cpp \
|
||||||
moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_transactiondesc.cpp \
|
moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_trafficgraphwidget.cpp moc_transactiondesc.cpp \
|
||||||
moc_transactiondescdialog.cpp moc_transactionfilterproxy.cpp \
|
moc_transactiondescdialog.cpp moc_transactionfilterproxy.cpp \
|
||||||
moc_transactiontablemodel.cpp moc_transactionview.cpp moc_walletframe.cpp \
|
moc_transactiontablemodel.cpp moc_transactionview.cpp moc_walletframe.cpp \
|
||||||
moc_walletmodel.cpp moc_walletstack.cpp moc_walletview.cpp
|
moc_walletmodel.cpp moc_walletstack.cpp moc_walletview.cpp
|
||||||
@ -73,7 +73,7 @@ BITCOIN_QT_H = aboutdialog.h addressbookpage.h addresstablemodel.h \
|
|||||||
optionsmodel.h overviewpage.h paymentrequestplus.h paymentserver.h \
|
optionsmodel.h overviewpage.h paymentrequestplus.h paymentserver.h \
|
||||||
qrcodedialog.h qvalidatedlineedit.h qvaluecombobox.h rpcconsole.h \
|
qrcodedialog.h qvalidatedlineedit.h qvaluecombobox.h rpcconsole.h \
|
||||||
sendcoinsdialog.h sendcoinsentry.h signverifymessagedialog.h splashscreen.h \
|
sendcoinsdialog.h sendcoinsentry.h signverifymessagedialog.h splashscreen.h \
|
||||||
transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \
|
trafficgraphwidget.h transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \
|
||||||
transactionrecord.h transactiontablemodel.h transactionview.h walletframe.h \
|
transactionrecord.h transactiontablemodel.h transactionview.h walletframe.h \
|
||||||
walletmodel.h walletmodeltransaction.h walletstack.h walletview.h
|
walletmodel.h walletmodeltransaction.h walletstack.h walletview.h
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ BITCOIN_QT_CPP = aboutdialog.cpp addressbookpage.cpp \
|
|||||||
optionsdialog.cpp optionsmodel.cpp overviewpage.cpp paymentrequestplus.cpp \
|
optionsdialog.cpp optionsmodel.cpp overviewpage.cpp paymentrequestplus.cpp \
|
||||||
paymentserver.cpp qvalidatedlineedit.cpp qvaluecombobox.cpp \
|
paymentserver.cpp qvalidatedlineedit.cpp qvaluecombobox.cpp \
|
||||||
rpcconsole.cpp sendcoinsdialog.cpp sendcoinsentry.cpp \
|
rpcconsole.cpp sendcoinsdialog.cpp sendcoinsentry.cpp \
|
||||||
signverifymessagedialog.cpp splashscreen.cpp transactiondesc.cpp \
|
signverifymessagedialog.cpp splashscreen.cpp trafficgraphwidget.cpp transactiondesc.cpp \
|
||||||
transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp \
|
transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp \
|
||||||
transactiontablemodel.cpp transactionview.cpp walletframe.cpp \
|
transactiontablemodel.cpp transactionview.cpp walletframe.cpp \
|
||||||
walletmodel.cpp walletmodeltransaction.cpp walletstack.cpp walletview.cpp
|
walletmodel.cpp walletmodeltransaction.cpp walletstack.cpp walletview.cpp
|
||||||
|
@ -51,6 +51,16 @@ int ClientModel::getNumBlocksAtStartup()
|
|||||||
return numBlocksAtStartup;
|
return numBlocksAtStartup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint64 ClientModel::getTotalBytesRecv() const
|
||||||
|
{
|
||||||
|
return CNode::GetTotalBytesRecv();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 ClientModel::getTotalBytesSent() const
|
||||||
|
{
|
||||||
|
return CNode::GetTotalBytesSent();
|
||||||
|
}
|
||||||
|
|
||||||
QDateTime ClientModel::getLastBlockDate() const
|
QDateTime ClientModel::getLastBlockDate() const
|
||||||
{
|
{
|
||||||
if (pindexBest)
|
if (pindexBest)
|
||||||
@ -85,6 +95,8 @@ void ClientModel::updateTimer()
|
|||||||
// ensure we return the maximum of newNumBlocksOfPeers and newNumBlocks to not create weird displays in the GUI
|
// ensure we return the maximum of newNumBlocksOfPeers and newNumBlocks to not create weird displays in the GUI
|
||||||
emit numBlocksChanged(newNumBlocks, std::max(newNumBlocksOfPeers, newNumBlocks));
|
emit numBlocksChanged(newNumBlocks, std::max(newNumBlocksOfPeers, newNumBlocks));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientModel::updateNumConnections(int numConnections)
|
void ClientModel::updateNumConnections(int numConnections)
|
||||||
|
@ -35,6 +35,9 @@ public:
|
|||||||
int getNumBlocks() const;
|
int getNumBlocks() const;
|
||||||
int getNumBlocksAtStartup();
|
int getNumBlocksAtStartup();
|
||||||
|
|
||||||
|
quint64 getTotalBytesRecv() const;
|
||||||
|
quint64 getTotalBytesSent() const;
|
||||||
|
|
||||||
double getVerificationProgress() const;
|
double getVerificationProgress() const;
|
||||||
QDateTime getLastBlockDate() const;
|
QDateTime getLastBlockDate() const;
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ signals:
|
|||||||
void numConnectionsChanged(int count);
|
void numConnectionsChanged(int count);
|
||||||
void numBlocksChanged(int count, int countOfPeers);
|
void numBlocksChanged(int count, int countOfPeers);
|
||||||
void alertsChanged(const QString &warnings);
|
void alertsChanged(const QString &warnings);
|
||||||
|
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
|
||||||
|
|
||||||
//! Asynchronous message notification
|
//! Asynchronous message notification
|
||||||
void message(const QString &title, const QString &message, unsigned int style);
|
void message(const QString &title, const QString &message, unsigned int style);
|
||||||
|
@ -445,10 +445,271 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>&Network Traffic</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="TrafficGraphWidget" name="trafficGraph" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="sldGraphRange">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>288</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblGraphRange">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnClearTrafficGraph">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Totals</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="palette">
|
||||||
|
<palette>
|
||||||
|
<active>
|
||||||
|
<colorrole role="Light">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>0</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</active>
|
||||||
|
<inactive>
|
||||||
|
<colorrole role="Light">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>0</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</inactive>
|
||||||
|
<disabled>
|
||||||
|
<colorrole role="Light">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>0</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</disabled>
|
||||||
|
</palette>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_16">
|
||||||
|
<property name="text">
|
||||||
|
<string>In:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblBytesIn">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="palette">
|
||||||
|
<palette>
|
||||||
|
<active>
|
||||||
|
<colorrole role="Light">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</active>
|
||||||
|
<inactive>
|
||||||
|
<colorrole role="Light">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</inactive>
|
||||||
|
<disabled>
|
||||||
|
<colorrole role="Light">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</disabled>
|
||||||
|
</palette>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_17">
|
||||||
|
<property name="text">
|
||||||
|
<string>Out:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblBytesOut">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>407</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>TrafficGraphWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>trafficgraphwidget.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
<slots>
|
||||||
|
<slot>clear()</slot>
|
||||||
|
</slots>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../bitcoin.qrc"/>
|
<include location="../bitcoin.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
const int CONSOLE_HISTORY = 50;
|
const int CONSOLE_HISTORY = 50;
|
||||||
const QSize ICON_SIZE(24, 24);
|
const QSize ICON_SIZE(24, 24);
|
||||||
|
|
||||||
|
const int INITIAL_TRAFFIC_GRAPH_MINS = 30;
|
||||||
|
|
||||||
const struct {
|
const struct {
|
||||||
const char *url;
|
const char *url;
|
||||||
const char *source;
|
const char *source;
|
||||||
@ -204,6 +206,7 @@ RPCConsole::RPCConsole(QWidget *parent) :
|
|||||||
ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
|
ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
|
||||||
|
|
||||||
startExecutor();
|
startExecutor();
|
||||||
|
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@ -253,7 +256,8 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
|
|||||||
|
|
||||||
void RPCConsole::setClientModel(ClientModel *model)
|
void RPCConsole::setClientModel(ClientModel *model)
|
||||||
{
|
{
|
||||||
this->clientModel = model;
|
clientModel = model;
|
||||||
|
ui->trafficGraph->setClientModel(model);
|
||||||
if(model)
|
if(model)
|
||||||
{
|
{
|
||||||
// Keep up to date with client
|
// Keep up to date with client
|
||||||
@ -263,6 +267,9 @@ void RPCConsole::setClientModel(ClientModel *model)
|
|||||||
setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
|
setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
|
||||||
connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
|
connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
|
||||||
|
|
||||||
|
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
|
||||||
|
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
|
||||||
|
|
||||||
// Provide initial values
|
// Provide initial values
|
||||||
ui->clientVersion->setText(model->formatFullVersion());
|
ui->clientVersion->setText(model->formatFullVersion());
|
||||||
ui->clientName->setText(model->clientName());
|
ui->clientName->setText(model->clientName());
|
||||||
@ -431,3 +438,49 @@ void RPCConsole::on_showCLOptionsButton_clicked()
|
|||||||
GUIUtil::HelpMessageBox help;
|
GUIUtil::HelpMessageBox help;
|
||||||
help.exec();
|
help.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RPCConsole::on_sldGraphRange_valueChanged(int value)
|
||||||
|
{
|
||||||
|
const int multiplier = 5; // each position on the slider represents 5 min
|
||||||
|
int mins = value * multiplier;
|
||||||
|
setTrafficGraphRange(mins);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RPCConsole::FormatBytes(quint64 bytes)
|
||||||
|
{
|
||||||
|
if(bytes < 1024)
|
||||||
|
return QString(tr("%1 B")).arg(bytes);
|
||||||
|
if(bytes < 1024 * 1024)
|
||||||
|
return QString(tr("%1 KB")).arg(bytes / 1024);
|
||||||
|
if(bytes < 1024 * 1024 * 1024)
|
||||||
|
return QString(tr("%1 MB")).arg(bytes / 1024 / 1024);
|
||||||
|
|
||||||
|
return QString(tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCConsole::setTrafficGraphRange(int mins)
|
||||||
|
{
|
||||||
|
ui->trafficGraph->setGraphRangeMins(mins);
|
||||||
|
if(mins < 60) {
|
||||||
|
ui->lblGraphRange->setText(QString(tr("%1 m")).arg(mins));
|
||||||
|
} else {
|
||||||
|
int hours = mins / 60;
|
||||||
|
int minsLeft = mins % 60;
|
||||||
|
if(minsLeft == 0) {
|
||||||
|
ui->lblGraphRange->setText(QString(tr("%1 h")).arg(hours));
|
||||||
|
} else {
|
||||||
|
ui->lblGraphRange->setText(QString(tr("%1 h %2 m")).arg(hours).arg(minsLeft));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
|
||||||
|
{
|
||||||
|
ui->lblBytesIn->setText(FormatBytes(totalBytesIn));
|
||||||
|
ui->lblBytesOut->setText(FormatBytes(totalBytesOut));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCConsole::on_btnClearTrafficGraph_clicked()
|
||||||
|
{
|
||||||
|
ui->trafficGraph->clear();
|
||||||
|
}
|
||||||
|
@ -37,6 +37,12 @@ private slots:
|
|||||||
void on_openDebugLogfileButton_clicked();
|
void on_openDebugLogfileButton_clicked();
|
||||||
/** display messagebox with program parameters (same as bitcoin-qt --help) */
|
/** display messagebox with program parameters (same as bitcoin-qt --help) */
|
||||||
void on_showCLOptionsButton_clicked();
|
void on_showCLOptionsButton_clicked();
|
||||||
|
/** change the time range of the network traffic graph */
|
||||||
|
void on_sldGraphRange_valueChanged(int value);
|
||||||
|
/** update traffic statistics */
|
||||||
|
void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut);
|
||||||
|
/** clear traffic graph */
|
||||||
|
void on_btnClearTrafficGraph_clicked();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clear();
|
void clear();
|
||||||
@ -55,6 +61,9 @@ signals:
|
|||||||
void cmdRequest(const QString &command);
|
void cmdRequest(const QString &command);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static QString FormatBytes(quint64 bytes);
|
||||||
|
void setTrafficGraphRange(int mins);
|
||||||
|
|
||||||
Ui::RPCConsole *ui;
|
Ui::RPCConsole *ui;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
QStringList history;
|
QStringList history;
|
||||||
|
169
src/qt/trafficgraphwidget.cpp
Normal file
169
src/qt/trafficgraphwidget.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "trafficgraphwidget.h"
|
||||||
|
#include "clientmodel.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#define DESIRED_SAMPLES 800
|
||||||
|
|
||||||
|
#define XMARGIN 10
|
||||||
|
#define YMARGIN 10
|
||||||
|
|
||||||
|
TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
timer(0),
|
||||||
|
fMax(0.0f),
|
||||||
|
nMins(0),
|
||||||
|
vSamplesIn(),
|
||||||
|
vSamplesOut(),
|
||||||
|
nLastBytesIn(0),
|
||||||
|
nLastBytesOut(0),
|
||||||
|
clientModel(0)
|
||||||
|
{
|
||||||
|
timer = new QTimer(this);
|
||||||
|
connect(timer, SIGNAL(timeout()), SLOT(updateRates()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrafficGraphWidget::setClientModel(ClientModel *model)
|
||||||
|
{
|
||||||
|
clientModel = model;
|
||||||
|
if(model) {
|
||||||
|
nLastBytesIn = model->getTotalBytesRecv();
|
||||||
|
nLastBytesOut = model->getTotalBytesSent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TrafficGraphWidget::getGraphRangeMins() const
|
||||||
|
{
|
||||||
|
return nMins;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
|
||||||
|
{
|
||||||
|
int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
|
||||||
|
int sampleCount = samples.size(), x = XMARGIN + w, y;
|
||||||
|
if(sampleCount > 0) {
|
||||||
|
path.moveTo(x, YMARGIN + h);
|
||||||
|
for(int i = 0; i < sampleCount; ++i) {
|
||||||
|
x = XMARGIN + w - w * i / DESIRED_SAMPLES;
|
||||||
|
y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
|
||||||
|
path.lineTo(x, y);
|
||||||
|
}
|
||||||
|
path.lineTo(x, YMARGIN + h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrafficGraphWidget::paintEvent(QPaintEvent *)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.fillRect(rect(), Qt::black);
|
||||||
|
|
||||||
|
if(fMax <= 0.0f) return;
|
||||||
|
|
||||||
|
QColor axisCol(Qt::gray);
|
||||||
|
int h = height() - YMARGIN * 2;
|
||||||
|
painter.setPen(axisCol);
|
||||||
|
painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
|
||||||
|
|
||||||
|
// decide what order of magnitude we are
|
||||||
|
int base = floor(log10(fMax));
|
||||||
|
float val = pow(10.0f, base);
|
||||||
|
|
||||||
|
const QString units = tr("KB/s");
|
||||||
|
// draw lines
|
||||||
|
painter.setPen(axisCol);
|
||||||
|
painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax, QString("%1 %2").arg(val).arg(units));
|
||||||
|
for(float y = val; y < fMax; y += val) {
|
||||||
|
int yy = YMARGIN + h - h * y / fMax;
|
||||||
|
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
|
||||||
|
}
|
||||||
|
// if we drew 3 or fewer lines, break them up at the next lower order of magnitude
|
||||||
|
if(fMax / val <= 3.0f) {
|
||||||
|
axisCol = axisCol.darker();
|
||||||
|
val = pow(10.0f, base - 1);
|
||||||
|
painter.setPen(axisCol);
|
||||||
|
painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax, QString("%1 %2").arg(val).arg(units));
|
||||||
|
int count = 1;
|
||||||
|
for(float y = val; y < fMax; y += val, count++) {
|
||||||
|
// don't overwrite lines drawn above
|
||||||
|
if(count % 10 == 0)
|
||||||
|
continue;
|
||||||
|
int yy = YMARGIN + h - h * y / fMax;
|
||||||
|
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!vSamplesIn.empty()) {
|
||||||
|
QPainterPath p;
|
||||||
|
paintPath(p, vSamplesIn);
|
||||||
|
painter.fillPath(p, QColor(0, 255, 0, 128));
|
||||||
|
painter.setPen(Qt::green);
|
||||||
|
painter.drawPath(p);
|
||||||
|
}
|
||||||
|
if(!vSamplesOut.empty()) {
|
||||||
|
QPainterPath p;
|
||||||
|
paintPath(p, vSamplesOut);
|
||||||
|
painter.fillPath(p, QColor(255, 0, 0, 128));
|
||||||
|
painter.setPen(Qt::red);
|
||||||
|
painter.drawPath(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrafficGraphWidget::updateRates()
|
||||||
|
{
|
||||||
|
if(!clientModel) return;
|
||||||
|
|
||||||
|
quint64 bytesIn = clientModel->getTotalBytesRecv(),
|
||||||
|
bytesOut = clientModel->getTotalBytesSent();
|
||||||
|
float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
|
||||||
|
float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
|
||||||
|
vSamplesIn.push_front(inRate);
|
||||||
|
vSamplesOut.push_front(outRate);
|
||||||
|
nLastBytesIn = bytesIn;
|
||||||
|
nLastBytesOut = bytesOut;
|
||||||
|
|
||||||
|
while(vSamplesIn.size() > DESIRED_SAMPLES) {
|
||||||
|
vSamplesIn.pop_back();
|
||||||
|
}
|
||||||
|
while(vSamplesOut.size() > DESIRED_SAMPLES) {
|
||||||
|
vSamplesOut.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
float tmax = 0.0f;
|
||||||
|
foreach(float f, vSamplesIn) {
|
||||||
|
if(f > tmax) tmax = f;
|
||||||
|
}
|
||||||
|
foreach(float f, vSamplesOut) {
|
||||||
|
if(f > tmax) tmax = f;
|
||||||
|
}
|
||||||
|
fMax = tmax;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrafficGraphWidget::setGraphRangeMins(int mins)
|
||||||
|
{
|
||||||
|
nMins = mins;
|
||||||
|
int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
|
||||||
|
timer->stop();
|
||||||
|
timer->setInterval(msecsPerSample);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrafficGraphWidget::clear()
|
||||||
|
{
|
||||||
|
timer->stop();
|
||||||
|
|
||||||
|
vSamplesOut.clear();
|
||||||
|
vSamplesIn.clear();
|
||||||
|
fMax = 0.0f;
|
||||||
|
|
||||||
|
if(clientModel) {
|
||||||
|
nLastBytesIn = clientModel->getTotalBytesRecv();
|
||||||
|
nLastBytesOut = clientModel->getTotalBytesSent();
|
||||||
|
}
|
||||||
|
timer->start();
|
||||||
|
}
|
44
src/qt/trafficgraphwidget.h
Normal file
44
src/qt/trafficgraphwidget.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef TRAFFICGRAPHWIDGET_H
|
||||||
|
#define TRAFFICGRAPHWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
class ClientModel;
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QPaintEvent;
|
||||||
|
class QTimer;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class TrafficGraphWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TrafficGraphWidget(QWidget *parent = 0);
|
||||||
|
void setClientModel(ClientModel *model);
|
||||||
|
int getGraphRangeMins() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateRates();
|
||||||
|
void setGraphRangeMins(int mins);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintPath(QPainterPath &path, QQueue<float> &samples);
|
||||||
|
|
||||||
|
QTimer *timer;
|
||||||
|
float fMax;
|
||||||
|
int nMins;
|
||||||
|
QQueue<float> vSamplesIn;
|
||||||
|
QQueue<float> vSamplesOut;
|
||||||
|
quint64 nLastBytesIn;
|
||||||
|
quint64 nLastBytesOut;
|
||||||
|
ClientModel *clientModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRAFFICGRAPHWIDGET_H
|
@ -223,3 +223,17 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value getnettotals(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (fHelp || params.size() > 0)
|
||||||
|
throw runtime_error(
|
||||||
|
"getnettotals\n"
|
||||||
|
"Returns information about network traffic, including bytes in, bytes out,\n"
|
||||||
|
"and current time.");
|
||||||
|
|
||||||
|
Object obj;
|
||||||
|
obj.push_back(Pair("totalbytesrecv", static_cast< boost::uint64_t>(CNode::GetTotalBytesRecv())));
|
||||||
|
obj.push_back(Pair("totalbytessent", static_cast<boost::uint64_t>(CNode::GetTotalBytesSent())));
|
||||||
|
obj.push_back(Pair("timemillis", static_cast<boost::int64_t>(GetTimeMillis())));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user