mirror of
https://github.com/znc/znc.git
synced 2026-08-07 09:22:55 +02:00
Merge pull request #1020 from jpnurmi/traffic
Calculate per-network traffic (#963)
This commit is contained in:
@@ -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
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user