Merge pull request #1020 from jpnurmi/traffic

Calculate per-network traffic (#963)
This commit is contained in:
J-P Nurmi
2015-09-02 01:01:13 +02:00
10 changed files with 165 additions and 31 deletions
+8
View File
@@ -196,6 +196,12 @@ public:
unsigned short int GetJoinDelay() const { return m_uJoinDelay; }
void SetJoinDelay(unsigned short int uJoinDelay) { m_uJoinDelay = uJoinDelay; }
unsigned long long BytesRead() const { return m_uBytesRead; }
unsigned long long BytesWritten() const { return m_uBytesWritten; }
void AddBytesRead(unsigned long long u) { m_uBytesRead += u; }
void AddBytesWritten(unsigned long long u) { m_uBytesWritten += u; }
CString ExpandString(const CString& sStr) const;
CString& ExpandString(const CString& sStr, CString& sRet) const;
private:
@@ -245,6 +251,8 @@ protected:
CIRCNetworkJoinTimer* m_pJoinTimer;
unsigned short int m_uJoinDelay;
unsigned long long m_uBytesRead;
unsigned long long m_uBytesWritten;
};
#endif // !ZNC_IRCNETWORK_H
+2 -2
View File
@@ -187,8 +187,8 @@ public:
bool AutoClearQueryBuffer() const;
bool IsBeingDeleted() const { return m_bBeingDeleted; }
CString GetTimezone() const { return m_sTimezone; }
unsigned long long BytesRead() const { return m_uBytesRead; }
unsigned long long BytesWritten() const { return m_uBytesWritten; }
unsigned long long BytesRead() const;
unsigned long long BytesWritten() const;
unsigned int JoinTries() const { return m_uMaxJoinTries; }
unsigned int MaxJoins() const { return m_uMaxJoins; }
CString GetSkinName() const;
+1
View File
@@ -92,6 +92,7 @@ public:
// generated through ZNC.
TrafficStatsMap GetTrafficStats(TrafficStatsPair &Users,
TrafficStatsPair &ZNC, TrafficStatsPair &Total);
TrafficStatsMap GetNetworkTrafficStats(const CString& sUsername, TrafficStatsPair& Total);
// Authenticate a user.
// The result is passed back via callbacks to CAuthBase.
+61 -21
View File
@@ -33,6 +33,23 @@
<th>Total IRC Connections</th>
<td><? VAR TotalIRCConnections ?></td>
</tr>
<? ELSE ?>
<tr class="evenrow">
<th>Networks</th>
<td><? VAR TotalNetworks ?></td>
</tr>
<tr class="oddrow">
<th>Attached Networks</th>
<td><? VAR AttachedNetworks ?></td>
</tr>
<tr class="evenrow">
<th>Client Connections</th>
<td><? VAR TotalCConnections ?></td>
</tr>
<tr class="oddrow">
<th>IRC Connections</th>
<td><? VAR TotalIRCConnections ?></td>
</tr>
<? ENDIF ?>
</tbody>
</table>
@@ -40,51 +57,74 @@
</div>
</div>
<? IF IsAdmin && TrafficLoop ?>
<? IF IsAdmin ?>
<div class="section">
<h3>Traffic</h3>
<h3>Total</h3>
<div class="sectionbg">
<div class="sectionbody">
<table>
<thead>
<tr>
<td>Username</td>
<td></td>
<td>In</td>
<td>Out</td>
<td>Total</td>
</tr>
</thead>
<tbody>
<? LOOP TrafficLoop SORTASC=Username ?>
<tr class="<? IF __EVEN__ ?>evenrow<? ELSE ?>oddrow<? ENDIF ?>">
<td><? VAR Username ?></td>
<td><? VAR In ?></td>
<td><? VAR Out ?></td>
<td><? VAR Total ?></td>
</tr>
<? REM ?>Add the totals separately so that if sort is ever used they stay at the bottom
By keeping them inside the loop we can figure out even/odd classes though.
<? ENDREM ?>
<? IF __LAST__ ?>
<tr class="<? IF __EVEN__ ?>oddrow<? ELSE ?>evenrow<? ENDIF ?>">
<td>User Total</td>
<tr class="evenrow">
<td>Users</td>
<td><? VAR UserIn TOP ?></td>
<td><? VAR UserOut TOP ?></td>
<td><? VAR UserTotal TOP ?></td>
</tr>
<tr class="<? IF __EVEN__ ?>evenrow<? ELSE ?>oddrow<? ENDIF ?>">
<td>ZNC Total</td>
<tr class="oddrow">
<td>ZNC</td>
<td><? VAR ZNCIn TOP ?></td>
<td><? VAR ZNCOut TOP ?></td>
<td><? VAR ZNCTotal TOP ?></td>
</tr>
<tr class="<? IF __EVEN__ ?>oddrow<? ELSE ?>evenrow<? ENDIF ?>">
<td>Grand Total</td>
<tr class="evenrow">
<td>Total</td>
<td><? VAR AllIn TOP ?></td>
<td><? VAR AllOut TOP ?></td>
<td><? VAR AllTotal TOP ?></td>
</tr>
<? ENDIF ?>
</tbody>
</table>
</div>
</div>
</div>
<? ENDIF ?>
<? IF TrafficLoop ?>
<div class="section">
<? IF IsAdmin ?>
<h3>Users</h3>
<? ELSE ?>
<h3>Traffic</h3>
<? ENDIF ?>
<div class="sectionbg">
<div class="sectionbody">
<table>
<thead>
<tr>
<td>Username</td>
<td>Network</td>
<td>In</td>
<td>Out</td>
<td>Total</td>
</tr>
</thead>
<tbody>
<? LOOP TrafficLoop ?>
<tr class="<? IF __EVEN__ ?>evenrow<? ELSE ?>oddrow<? ENDIF ?>">
<td><? VAR Username ?></td>
<td><? VAR Network ?></td>
<td><? VAR In ?></td>
<td><? VAR Out ?></td>
<td><? VAR Total ?></td>
</tr>
<? ENDLOOP ?>
</tbody>
</table>
+23 -2
View File
@@ -78,7 +78,7 @@ public:
vParams.push_back(make_pair("user", ""));
AddSubPage(std::make_shared<CWebSubPage>("settings", "Global Settings", CWebSubPage::F_ADMIN));
AddSubPage(std::make_shared<CWebSubPage>("edituser", "Your Settings", vParams));
AddSubPage(std::make_shared<CWebSubPage>("traffic", "Traffic Info", CWebSubPage::F_ADMIN));
AddSubPage(std::make_shared<CWebSubPage>("traffic", "Traffic Info", vParams));
AddSubPage(std::make_shared<CWebSubPage>("listusers", "Manage Users", CWebSubPage::F_ADMIN));
}
@@ -573,7 +573,7 @@ public:
return true;
} else if (sPageName == "listusers" && spSession->IsAdmin()) {
return ListUsersPage(WebSock, Tmpl);
} else if (sPageName == "traffic" && spSession->IsAdmin()) {
} else if (sPageName == "traffic") {
return TrafficPage(WebSock, Tmpl);
} else if (sPageName == "index") {
return true;
@@ -1431,6 +1431,7 @@ public:
}
bool TrafficPage(CWebSock& WebSock, CTemplate& Tmpl) {
std::shared_ptr<CWebSession> spSession = WebSock.GetSession();
Tmpl["Title"] = "Traffic Info";
Tmpl["Uptime"] = CZNC::Get().GetUptime();
@@ -1441,6 +1442,11 @@ public:
for (const auto& it : msUsers) {
CUser* pUser = it.second;
if (!spSession->IsAdmin() && spSession->GetUser() != it.second) {
continue;
}
vector<CIRCNetwork*> vNetworks = pUser->GetNetworks();
for (const CIRCNetwork* pNetwork : vNetworks) {
@@ -1469,12 +1475,27 @@ public:
CZNC::TrafficStatsMap traffic = CZNC::Get().GetTrafficStats(Users, ZNC, Total);
for (const auto& it : traffic) {
if (!spSession->IsAdmin() && !spSession->GetUser()->GetUserName().Equals(it.first)) {
continue;
}
CTemplate& l = Tmpl.AddRow("TrafficLoop");
l["Username"] = it.first;
l["In"] = CString::ToByteStr(it.second.first);
l["Out"] = CString::ToByteStr(it.second.second);
l["Total"] = CString::ToByteStr(it.second.first + it.second.second);
CZNC::TrafficStatsPair NetworkTotal;
CZNC::TrafficStatsMap NetworkTraffic = CZNC::Get().GetNetworkTrafficStats(it.first, NetworkTotal);
for (const auto& it2 : NetworkTraffic) {
CTemplate& l2 = Tmpl.AddRow("TrafficLoop");
l2["Network"] = it2.first;
l2["In"] = CString::ToByteStr(it2.second.first);
l2["Out"] = CString::ToByteStr(it2.second.second);
l2["Total"] = CString::ToByteStr(it2.second.first + it2.second.second);
}
}
Tmpl["UserIn"] = CString::ToByteStr(Users.first);
+12 -1
View File
@@ -143,7 +143,9 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CString& sName)
m_NoticeBuffer(),
m_pPingTimer(nullptr),
m_pJoinTimer(nullptr),
m_uJoinDelay(0)
m_uJoinDelay(0),
m_uBytesRead(0),
m_uBytesWritten(0)
{
SetUser(pUser);
@@ -301,6 +303,7 @@ CIRCNetwork::~CIRCNetwork() {
}
m_vQueries.clear();
CUser* pUser = GetUser();
SetUser(nullptr);
// Make sure we are not in the connection queue
@@ -308,6 +311,14 @@ CIRCNetwork::~CIRCNetwork() {
CZNC::Get().GetManager().DelCronByAddr(m_pPingTimer);
CZNC::Get().GetManager().DelCronByAddr(m_pJoinTimer);
if (pUser) {
pUser->AddBytesRead(m_uBytesRead);
pUser->AddBytesWritten(m_uBytesWritten);
} else {
CZNC::Get().AddBytesRead(m_uBytesRead);
CZNC::Get().AddBytesWritten(m_uBytesWritten);
}
}
void CIRCNetwork::DelServers() {
+2 -2
View File
@@ -130,8 +130,8 @@ CIRCSock::~CIRCSock() {
Quit();
m_msChans.clear();
m_pNetwork->GetUser()->AddBytesRead(GetBytesRead());
m_pNetwork->GetUser()->AddBytesWritten(GetBytesWritten());
m_pNetwork->AddBytesRead(GetBytesRead());
m_pNetwork->AddBytesWritten(GetBytesWritten());
}
void CIRCSock::Quit(const CString& sQuitMsg) {
+6 -1
View File
@@ -407,14 +407,19 @@ CSocket::CSocket(CModule* pModule, const CString& sHostname, unsigned short uPor
CSocket::~CSocket() {
CUser *pUser = nullptr;
CIRCNetwork* pNetwork = nullptr;
// CWebSock could cause us to have a nullptr pointer here
if (m_pModule) {
pUser = m_pModule->GetUser();
pNetwork = m_pModule->GetNetwork();
m_pModule->UnlinkSocket(this);
}
if (pUser && m_pModule && (m_pModule->GetType() != CModInfo::GlobalModule)) {
if (pNetwork && m_pModule && (m_pModule->GetType() == CModInfo::NetworkModule)) {
pNetwork->AddBytesWritten(GetBytesWritten());
pNetwork->AddBytesRead(GetBytesRead());
} else if (pUser && m_pModule && (m_pModule->GetType() == CModInfo::UserModule)) {
pUser->AddBytesWritten(GetBytesWritten());
pUser->AddBytesRead(GetBytesRead());
} else {
+18 -2
View File
@@ -120,8 +120,8 @@ CUser::~CUser() {
CZNC::Get().GetManager().DelCronByAddr(m_pUserTimer);
CZNC::Get().AddBytesRead(BytesRead());
CZNC::Get().AddBytesWritten(BytesWritten());
CZNC::Get().AddBytesRead(m_uBytesRead);
CZNC::Get().AddBytesWritten(m_uBytesWritten);
}
template<class T>
@@ -1278,3 +1278,19 @@ bool CUser::AutoClearQueryBuffer() const { return m_bAutoClearQueryBuffer; }
CString CUser::GetSkinName() const { return m_sSkinName; }
const CString& CUser::GetUserPath() const { if (!CFile::Exists(m_sUserPath)) { CDir::MakeDir(m_sUserPath); } return m_sUserPath; }
// !Getters
unsigned long long CUser::BytesRead() const {
unsigned long long uBytes = m_uBytesRead;
for (const CIRCNetwork* pNetwork : m_vIRCNetworks) {
uBytes += pNetwork->BytesRead();
}
return uBytes;
}
unsigned long long CUser::BytesWritten() const {
unsigned long long uBytes = m_uBytesWritten;
for (const CIRCNetwork* pNetwork : m_vIRCNetworks) {
uBytes += pNetwork->BytesWritten();
}
return uBytes;
}
+32
View File
@@ -1767,6 +1767,38 @@ CZNC::TrafficStatsMap CZNC::GetTrafficStats(TrafficStatsPair &Users,
return ret;
}
CZNC::TrafficStatsMap CZNC::GetNetworkTrafficStats(const CString& sUsername, TrafficStatsPair& Total) {
TrafficStatsMap Networks;
CUser* pUser = FindUser(sUsername);
if (pUser) {
for (const CIRCNetwork* pNetwork : pUser->GetNetworks()) {
Networks[pNetwork->GetName()].first = pNetwork->BytesRead();
Networks[pNetwork->GetName()].second = pNetwork->BytesWritten();
Total.first += pNetwork->BytesRead();
Total.second += pNetwork->BytesWritten();
}
for (Csock* pSock : m_Manager) {
CIRCNetwork *pNetwork = nullptr;
if (pSock->GetSockName().StartsWith("IRC::")) {
pNetwork = ((CIRCSock *) pSock)->GetNetwork();
} else if (pSock->GetSockName().StartsWith("USR::")) {
pNetwork = ((CClient *) pSock)->GetNetwork();
}
if (pNetwork && pNetwork->GetUser() == pUser) {
Networks[pNetwork->GetName()].first = pSock->GetBytesRead();
Networks[pNetwork->GetName()].second = pSock->GetBytesWritten();
Total.first += pSock->GetBytesRead();
Total.second += pSock->GetBytesWritten();
}
}
}
return Networks;
}
void CZNC::AuthUser(std::shared_ptr<CAuthBase> AuthClass) {
// TODO unless the auth module calls it, CUser::IsHostAllowed() is not honoured
bool bReturn = false;