mfp seems like ready

This commit is contained in:
partysan
2022-11-19 21:15:33 +03:00
parent 4f46089a87
commit 8073c4bd7b
12 changed files with 550 additions and 210 deletions
+3 -3
View File
@@ -1,11 +1,11 @@
QT -= gui
QT += network
QT += network sql
CONFIG += c++17 console
CONFIG -= app_bundle
SOURCES += \
dailycounter.cpp \
dbmanager.cpp \
g.cpp \
httpdocument.cpp \
httpserver.cpp \
@@ -18,7 +18,7 @@ SOURCES += \
webserverbase.cpp
HEADERS += \
dailycounter.h \
dbmanager.h \
g.h \
httpdocument.h \
httpserver.h \
-86
View File
@@ -1,86 +0,0 @@
/*
3proxy-eagle: Accumulate ethical 3proxy statistics with web interface.
Source code: https://notabug.org/acetone/3proxy-eagle.
Copyright (C) 2022, acetone
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "dailycounter.h"
#include <QDateTime>
DailyCounter::DailyCounter()
{
}
quint64 DailyCounter::value()
{
const auto factDay = getCurrentDay();
if (day() != factDay)
{
m_day = factDay;
m_counter = 0;
}
return m_counter;
}
QString DailyCounter::day() const
{
return m_day;
}
QJsonObject DailyCounter::serialize()
{
QJsonObject me;
me["day"] = day();
me["count"] = QString::number( value() );
return me;
}
void DailyCounter::deserialize(const QJsonObject &json)
{
const QString serializedDay = json.value("day").toString();
const QString factDay = getCurrentDay();
m_day = factDay;
auto serializedCounter = json.value("count").toString().toULongLong();
if (serializedDay == factDay)
{
m_counter = serializedCounter;
}
else
{
m_counter = 0;
}
}
void DailyCounter::increment(quint64 value)
{
const auto factDay = getCurrentDay();
if (day() == factDay)
{
m_counter += value;
}
else
{
m_day = factDay;
m_counter = value;
}
}
QString DailyCounter::getCurrentDay()
{
return QDateTime::currentDateTimeUtc().toString(Qt::DateFormat::RFC2822Date);
}
-40
View File
@@ -1,40 +0,0 @@
/*
3proxy-eagle: Accumulate ethical 3proxy statistics with web interface.
Source code: https://notabug.org/acetone/3proxy-eagle.
Copyright (C) 2022, acetone
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QJsonObject>
#include <QString>
class DailyCounter
{
public:
DailyCounter();
quint64 value();
QString day() const;
QJsonObject serialize();
void deserialize(const QJsonObject& json);
void increment(quint64);
static QString getCurrentDay();
private:
QString m_day;
std::atomic<quint64> m_counter {0};
};
+334
View File
@@ -0,0 +1,334 @@
/*
3proxy-eagle: Accumulate ethical 3proxy statistics with web interface.
Source code: https://notabug.org/acetone/3proxy-eagle.
Copyright (C) 2022, acetone
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "dbmanager.h"
#include "g.h"
#include <QDebug>
#include <QSqlQuery>
#include <QSqlResult>
#include <QSqlError>
#include <QSqlRecord>
#include <QDateTime>
#include <QRegularExpression>
QMutex DBManager::m_mtx;
qint64 DBManager::m_dailyTopTableLastActualizeTimestamp = 0;
qint64 DBManager::m_dailyTrafficTableLastActualizeTimestamp = 0;
constexpr int DB_VERSION = 1;
DBManager::DBManager() : m_connName(g::randomString())
{
m_mtx.lock();
m_db = QSqlDatabase::addDatabase("QSQLITE", m_connName);
m_db.setDatabaseName(g::p::WORKING_DIR+"/statistics.db");
if (not m_db.open())
{
qFatal("Connection with database failed (maybe working directory not found or not writable)");
}
}
void DBManager::initAtStart()
{
QSqlQuery query(m_db);
bool appSettings = query.exec ("CREATE TABLE app_settings(param VARCHAR PRIMARY KEY, val VARCHAR)");
if (appSettings)
{
setStandaloneVariable("db_version", QString::number(DB_VERSION));
}
else
{
QString version = getStandaloneVariable("db_version");
if (version != QString::number(DB_VERSION))
{
qWarning().noquote() << "Your database version is [ " + (version.isEmpty() ? "UNKNOWN" : version) + " ]";
qWarning().noquote() << "Required version is [ " + QString::number(DB_VERSION) + " ]";
qWarning().noquote() << "You should delete old database and restart app. Old statistics will be lost. Database file path: " + g::p::WORKING_DIR + "/statistics.db";
qFatal("Database version error");
}
}
query.exec ("CREATE TABLE IF NOT EXISTS total_history (name VARCHAR PRIMARY KEY, request_counter UNSIGNED BIGINT)");
query.exec ("CREATE TABLE IF NOT EXISTS daily_history (name VARCHAR PRIMARY KEY, request_counter UNSIGNED BIGINT, date_of_record VARCHAR)");
// For traffic used:
// total_download_traffic
// total_upload_traffic
// daily_upload_traffic + daily_upload_traffic_date
// daily_download_traffic + daily_download_traffic_date
query.exec ("VACUUM");
}
TopDestinationList DBManager::totalTop() const
{
QSqlQuery query(m_db);
TopDestinationList result;
if (not query.exec("SELECT * FROM total_history ORDER BY request_counter DESC LIMIT " + QString::number(g::c::LAST_AND_TOP_LIST_SIZE)))
{
qCritical() << "Db query failed:" << query.lastError().text();
}
else
{
while (query.next())
{
result.push_back( {query.value(0).toString(), query.value(1).toULongLong()} );
}
}
return result;
}
TopDestinationList DBManager::dailyTop() const
{
QSqlQuery query(m_db);
TopDestinationList result;
if (not query.exec("SELECT * FROM daily_history ORDER BY request_counter DESC LIMIT " + QString::number(g::c::LAST_AND_TOP_LIST_SIZE)))
{
qCritical() << "Db query failed:" << query.lastError().text();
}
else
{
const QString currd = currentDate();
bool oldExists = false;
while (query.next())
{
if (query.value(2).toString() == currd)
{
result.push_back( {query.value(0).toString(), query.value(1).toULongLong()} );
}
else
{
oldExists = true;
}
}
if (oldExists)
{
actualizeDailyTopTable();
}
}
return result;
}
quint64 DBManager::totalTopCount(const QString &dest) const
{
QSqlQuery query(m_db);
if (not query.exec("SELECT request_counter FROM total_history WHERE name = '" + escaped(dest) + "'"))
{
qCritical() << "Db query failed:" << query.lastError().text();
return 0;
}
if (query.next())
{
return query.value(0).toULongLong();
}
return 0;
}
quint64 DBManager::dailyTopCount(const QString &dest) const
{
QSqlQuery query(m_db);
if (not query.exec("SELECT * FROM daily_history WHERE name = '" + escaped(dest) + "'"))
{
qCritical() << "Db query failed:" << query.lastError().text();
return 0;
}
if (query.next())
{
if (query.value(2).toString() != currentDate())
{
actualizeDailyTopTable();
return 0;
}
else
{
return query.value(1).toULongLong();
}
}
return 0;
}
quint64 DBManager::incrementTotalTopCount(const QString &dest)
{
QSqlQuery query(m_db);
quint64 newValue = totalTopCount(dest) + 1;
if (not query.exec("INSERT OR REPLACE INTO total_history(name, request_counter) VALUES ('"+ escaped(dest) +"', "+ QString::number(newValue) +")"))
{
qCritical() << "Db query failed:" << query.lastError().text();
}
return newValue;
}
quint64 DBManager::incrementDailyTopCount(const QString &dest)
{
QSqlQuery query(m_db);
quint64 newValue = dailyTopCount(dest) + 1;
if (not query.exec("INSERT OR REPLACE INTO daily_history(name, request_counter, date_of_record) VALUES "
"('"+ escaped(dest) +"', '"+ QString::number(newValue) +"', '"+ currentDate() +"')"))
{
qCritical() << "Db query failed:" << query.lastError().text();
}
return newValue;
}
quint64 DBManager::incrementDailyUploadTraffic(quint64 bytes)
{
quint64 newValue = dailyUploadTraffic() + bytes;
setStandaloneVariable("daily_upload_traffic", QString::number(newValue));
return newValue;
}
quint64 DBManager::incrementTotalUploadTraffic(quint64 bytes)
{
quint64 newValue = totalUploadTraffic() + bytes;
setStandaloneVariable("total_upload_traffic", QString::number(newValue));
return newValue;
}
quint64 DBManager::incrementDailyDownloadTraffic(quint64 bytes)
{
quint64 newValue = dailyDownloadTraffic() + bytes;
setStandaloneVariable("daily_download_traffic", QString::number(newValue));
return newValue;
}
quint64 DBManager::incrementTotalDownloadTraffic(quint64 bytes)
{
quint64 newValue = totalDownloadTraffic() + bytes;
setStandaloneVariable("total_download_traffic", QString::number(newValue));
return newValue;
}
quint64 DBManager::dailyUploadTraffic() const
{
const QString currd = currentDate();
if (getStandaloneVariable("daily_upload_traffic_date") != currd)
{
setStandaloneVariable("daily_upload_traffic_date", currd);
setStandaloneVariable("daily_upload_traffic", "0");
return 0;
}
return getStandaloneVariable("daily_upload_traffic").toULongLong();
}
quint64 DBManager::totalUploadTraffic() const
{
return getStandaloneVariable("total_upload_traffic").toULongLong();
}
quint64 DBManager::dailyDownloadTraffic() const
{
const QString currd = currentDate();
if (getStandaloneVariable("daily_download_traffic_date") != currd)
{
setStandaloneVariable("daily_download_traffic_date", currd);
setStandaloneVariable("daily_download_traffic", "0");
return 0;
}
return getStandaloneVariable("daily_download_traffic").toULongLong();
}
quint64 DBManager::totalDownloadTraffic() const
{
return getStandaloneVariable("total_download_traffic").toULongLong();
}
DBManager::~DBManager()
{
m_db.close();
m_db = QSqlDatabase();
QSqlDatabase::removeDatabase(m_connName);
m_mtx.unlock();
}
void DBManager::actualizeDailyTopTable() const
{
qint64 started = QDateTime::currentMSecsSinceEpoch();
if (started - m_dailyTopTableLastActualizeTimestamp < g::c::DB_DAILY_TOP_TABLE_ACTUALIZE_MINIMAL_INTERVAL_MS)
{
qDebug() << "Database daily history table actualizing rejected by minimal interval:" << g::c::DB_DAILY_TOP_TABLE_ACTUALIZE_MINIMAL_INTERVAL_MS << "ms";
return;
}
QSqlQuery query(m_db);
if (not query.exec("DELETE FROM daily_history WHERE date_of_record != '"+ currentDate() + "'"))
{
qCritical() << "Db query failed:" << query.lastError().text();
}
m_dailyTopTableLastActualizeTimestamp = QDateTime::currentMSecsSinceEpoch();
qInfo() << "Daily history database table actualized in" << m_dailyTopTableLastActualizeTimestamp-started << "ms";
}
QString DBManager::currentDate()
{
return QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd");
}
DBManager::ResultPair DBManager::setStandaloneVariable(const QString &key, const QString &value) const
{
QSqlQuery query(m_db);
bool status = query.exec("INSERT OR REPLACE INTO app_settings(param, val) VALUES ('"+ escaped(key) +"', '"+ escaped(value) +"')");
return status ? ResultPair(true) : ResultPair(false, query.lastError().text());
}
QString DBManager::getStandaloneVariable(const QString &key) const
{
QSqlQuery query(m_db);
if (not query.exec("SELECT val FROM app_settings WHERE param = '" + escaped(key) + "'"))
{
qCritical() << "Db query failed:" << query.lastError().text();
return QString();
}
if (query.next())
{
return query.value(0).toString();
}
else
{
qDebug() << "Db query failed (empty result for " + key + "):" << query.lastError().text();
return QString();
}
}
QString DBManager::escaped(const QString &str)
{
QString result {str};
static QRegularExpression rgx("[\\'\\;\\!\\-\\@\\#\\$\\%\\^\\&\\*\\(\\)\\`\\~\\+\\=\\\\/\\]\\[ ]");
result.replace(rgx, "_");
return result;
}
+78
View File
@@ -0,0 +1,78 @@
/*
3proxy-eagle: Accumulate ethical 3proxy statistics with web interface.
Source code: https://notabug.org/acetone/3proxy-eagle.
Copyright (C) 2022, acetone
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "g.h"
#include <QString>
#include <QSqlDatabase>
#include <QMutex>
class DBManager
{
public:
class ResultPair
{
public:
ResultPair (bool status, QString string = QString()) : m_str(string), m_bool(status) {}
bool status() const { return m_bool; }
QString string() const { return m_str; }
private:
QString m_str;
bool m_bool;
};
DBManager();
void initAtStart();
TopDestinationList totalTop() const;
TopDestinationList dailyTop() const;
quint64 totalTopCount(const QString& dest) const;
quint64 dailyTopCount(const QString& dest) const;
quint64 incrementTotalTopCount(const QString& dest);
quint64 incrementDailyTopCount(const QString& dest);
quint64 incrementDailyUploadTraffic(quint64 bytes);
quint64 incrementTotalUploadTraffic(quint64 bytes);
quint64 incrementDailyDownloadTraffic(quint64 bytes);
quint64 incrementTotalDownloadTraffic(quint64 bytes);
quint64 dailyUploadTraffic() const;
quint64 totalUploadTraffic() const;
quint64 dailyDownloadTraffic() const;
quint64 totalDownloadTraffic() const;
static QString currentDate();
static QString escaped(const QString &str);
~DBManager();
private:
void actualizeDailyTopTable() const;
ResultPair setStandaloneVariable(const QString& key, const QString& value) const;
QString getStandaloneVariable(const QString& key) const;
const QString m_connName;
QSqlDatabase m_db;
static QMutex m_mtx;
static qint64 m_dailyTopTableLastActualizeTimestamp;
static qint64 m_dailyTrafficTableLastActualizeTimestamp;
};
+23
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <QCryptographicHash>
#include <QMutex>
#include <QFile>
#include <QRandomGenerator>
#include <iostream>
namespace g {
@@ -32,6 +33,9 @@ namespace c {
const QString SOFTWARE_NAME = "3proxy-eagle";
const QString SOFTWARE_VERSION = "0.0.1a";
const QString COPYRIGHT = "GPLv3 (c) acetone, 2022";
const int LAST_AND_TOP_LIST_SIZE = 10;
const qint64 DB_DAILY_TOP_TABLE_ACTUALIZE_MINIMAL_INTERVAL_MS = 300000; // 5 min
const qint64 CACHE_ACTUALIZE_TOP_LISTS_FROM_DB_MINIMAL_INTERVAL_MS = 5000; // 5 sec
const QString HA_PAGE_TITLE = "{{PAGE_TITLE}}";
const QString HA_CUSTOM_CSS = "{{CUSTOM_CSS}}";
const QString HA_DAILY_UPLOAD = "{{DAILY_UPLOAD}}";
@@ -188,6 +192,25 @@ QString getValue(const QString &string, const QString &key, GetValueType type)
return result;
}
QString randomString(int length)
{
static const QString table
{"0123456789"
"abcdefghij"
"klmnkpqrst"
"uvwxyzABCD"
"EFGHIJKLMN"
"hPQRSTUVWX"};
static const int posLimit = table.size() - 1;
QString value;
while(value.size() < length)
{
value += table[ QRandomGenerator::system()->bounded (0, posLimit) ];
}
return value;
}
QString hash(const QByteArray &data)
{
+10 -2
View File
@@ -19,10 +19,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "proxyinstanse.h"
#include <QString>
#include <QList>
#include <QPair>
class QFile;
class ProxyInstanse;
class QThread;
using TopDestinationList = QList<QPair<QString, quint64>>;
namespace g /* for Global */ {
@@ -30,6 +35,9 @@ namespace c /* for Constants */ {
extern const QString SOFTWARE_NAME;
extern const QString SOFTWARE_VERSION;
extern const QString COPYRIGHT;
extern const int LAST_AND_TOP_LIST_SIZE;
extern const qint64 DB_DAILY_TOP_TABLE_ACTUALIZE_MINIMAL_INTERVAL_MS;
extern const qint64 CACHE_ACTUALIZE_TOP_LISTS_FROM_DB_MINIMAL_INTERVAL_MS;
extern const QString HA_PAGE_TITLE;
extern const QString HA_CUSTOM_CSS;
extern const QString HA_DAILY_UPLOAD;
@@ -50,7 +58,6 @@ namespace p /* for Parameters */ {
extern QString WORKING_DIR;
extern QStringList IGNORED_DESTINATIONS;
extern QString SERVICE_TITLE;
extern uint LAST_AND_TOP_LIST_SIZE;
extern QString BIND_TO_ADDRESS;
extern quint16 BIND_TO_PORT;
} // namespace p
@@ -74,6 +81,7 @@ enum class GetValueType { // QString getValue()
HttpHeader = 3
};
QString getValue(const QString &string, const QString &key, GetValueType type = GetValueType::Default);
QString randomString(int length = 10);
QString hash(const QByteArray &data);
QString hash(QFile file);
+11 -20
View File
@@ -19,6 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "proxyinstanse.h"
#include "httpserver.h"
#include "dbmanager.h"
#include "g.h"
#include <QCoreApplication>
@@ -46,7 +47,6 @@ void usage()
" -i --instanse <3proxy>,<3proxy.cfg>\n"
" -w --working-directory <data>\n"
" -t --service-title <3proxy-eagle>\n"
" -s --last-and-top-list-size <5>\n"
" -I --ignored-destinations <[0.0.0.0],127.0.0.1>\n"
" -a --bind-to-address <127.0.0.1>\n"
" -p --bind-to-port <8161>\n"
@@ -136,18 +136,6 @@ int main(int argc, char *argv[])
g::p::WORKING_DIR = value;
}
else if ((key == "-s" or key == "--last-and-top-list-size") and not value.isEmpty())
{
bool ok = false;
value.toUInt(&ok);
if (not ok)
{
qWarning() << "--last-and-top-list-size parsing failed, not a positive number:" << value;
continue;
}
g::p::LAST_AND_TOP_LIST_SIZE = value.toUInt();
}
else if ((key == "-I" or key == "--ignored-destinations") and not value.isEmpty())
{
g::p::IGNORED_DESTINATIONS = value.split(',');
@@ -182,13 +170,12 @@ int main(int argc, char *argv[])
}
}
qInfo().noquote() << "Instanses count:" << instanses.size();
qInfo().noquote() << "Working directory:" << g::p::WORKING_DIR;
qInfo().noquote() << "Last and top dest list size:" << g::p::LAST_AND_TOP_LIST_SIZE;
qInfo().noquote() << "Ignored destinations:" << g::p::IGNORED_DESTINATIONS;
qInfo().noquote() << "Bind to address:" << g::p::BIND_TO_ADDRESS;
qInfo().noquote() << "Bind to port:" << g::p::BIND_TO_PORT;
qInfo() << "";
if (instanses.isEmpty())
{
qFatal("Instanses not defined. Read --help information");
}
DBManager().initAtStart();
for (const auto& pair: instanses)
{
@@ -203,6 +190,10 @@ int main(int argc, char *argv[])
g::instanses.push_back( {thread, pi} );
}
qInfo().noquote() << "Instanses count:" << instanses.size();
qInfo().noquote() << "Working directory:" << g::p::WORKING_DIR;
qInfo().noquote() << "Ignored destinations:" << g::p::IGNORED_DESTINATIONS;
(new HttpServer)/*->killTheCapitalism()*/;
return a.exec();
+58 -32
View File
@@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "statistics.h"
#include "dbmanager.h"
#include "g.h"
#include <QJsonObject>
@@ -25,68 +26,93 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <QJsonParseError>
#include <QJsonArray>
#include <QDebug>
#include <QMutex>
#include <QFile>
QStringList Statistics::m_lastDestinations;
qint64 Statistics::m_lastSerializeTimestamp = 0;
bool Statistics::m_deserialized = false;
DailyCounter Statistics::m_dailyUpload;
DailyCounter Statistics::m_dailyDownload;
quint64 Statistics::m_totalUpload = 0;
quint64 Statistics::m_totalDownload = 0;
std::atomic<quint64> Statistics::m_dailyUpload {0};
std::atomic<quint64> Statistics::m_dailyDownload {0};
std::atomic<quint64> Statistics::m_totalUpload {0};
std::atomic<quint64> Statistics::m_totalDownload {0};
TopDestinationList Statistics::m_dailyTopDestinations;
TopDestinationList Statistics::m_totalTopDestinations;
bool Statistics::m_cacheUpdatedAfterLastReport = false;
qint64 Statistics::m_actualizeTopListsLastTimestamp = 0;
void Statistics::report(const LogEvent& event)
{
// mutex enabled in ProxyInstanse::reader()
deserialize();
if (g::p::IGNORED_DESTINATIONS.contains(event.dest))
{
qDebug() << "Destination" << event.dest << "ignored";
return;
}
DBManager db;
m_dailyDownload = db.incrementDailyDownloadTraffic(event.from);
m_dailyUpload = db.incrementDailyUploadTraffic(event.to);
m_totalDownload = db.incrementTotalDownloadTraffic(event.from);
m_totalUpload = db.incrementTotalUploadTraffic(event.to);
addToDestinationsList(event.dest);
incrementUpload(event.to);
incrementDownload(event.from);
// type not handled
serialize();
m_cacheUpdatedAfterLastReport = false;
}
void Statistics::incrementUpload(quint64 value)
const QStringList Statistics::lastDestinations()
{
m_dailyUpload.increment(value);
m_totalUpload += value;
return m_lastDestinations;
}
void Statistics::incrementDownload(quint64 value)
const TopDestinationList Statistics::dailyTopDestinations()
{
m_dailyDownload.increment(value);
m_totalDownload += value;
if (not m_cacheUpdatedAfterLastReport)
{
actualizeTopLists();
}
return m_dailyTopDestinations;
}
const TopDestinationList Statistics::totalTopDestinations()
{
return m_totalTopDestinations;
}
void Statistics::addToDestinationsList(const QString &dest)
{
if (static_cast<uint>(lastDestinations().size()) >= g::p::LAST_AND_TOP_LIST_SIZE)
static QMutex mutex;
mutex.lock();
if (lastDestinations().size() >= g::c::LAST_AND_TOP_LIST_SIZE)
{
m_lastDestinations.pop_back();
}
m_lastDestinations.push_front(dest);
mutex.unlock();
DBManager db;
db.incrementTotalTopCount(dest);
db.incrementDailyTopCount(dest);
}
void Statistics::serialize()
void Statistics::actualizeTopLists()
{
QFile file(g::p::WORKING_DIR + "/statistics.json");
}
void Statistics::deserialize()
{
if (m_deserialized) return;
QFile file(g::p::WORKING_DIR + "/statistics.json");
static QMutex mutex;
QMutexLocker lock (&mutex);
qint64 started = QDateTime::currentMSecsSinceEpoch();
if (started - m_actualizeTopListsLastTimestamp < g::c::CACHE_ACTUALIZE_TOP_LISTS_FROM_DB_MINIMAL_INTERVAL_MS)
{
qDebug() << "Cache actualizing rejected by minimal interval:" << g::c::CACHE_ACTUALIZE_TOP_LISTS_FROM_DB_MINIMAL_INTERVAL_MS << "ms";
return;
}
DBManager db;
m_dailyTopDestinations = db.dailyTop();
m_totalTopDestinations = db.totalTop();
m_cacheUpdatedAfterLastReport = true;
m_actualizeTopListsLastTimestamp = QDateTime::currentMSecsSinceEpoch();
qInfo() << "Cache actualized in" << m_actualizeTopListsLastTimestamp-started << "ms";
}
+22 -19
View File
@@ -19,13 +19,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "dailycounter.h"
#include "g.h"
#include <QStringList>
struct LogEvent
{
QString type;
QString type; // not handled
QString dest;
quint64 to = 0;
quint64 from = 0;
@@ -37,28 +37,31 @@ public:
Statistics() = delete;
static void report (const LogEvent& event);
static const QStringList lastDestinations() { return QStringList{"google.com"}; /*m_lastDestinations;*/ }
static const QStringList dailyTopDestinations() { return QStringList{"cloudflare.com", "yahoo.com"}; }
static const QStringList totalTopDestinations() { return QStringList{"domain.com", "top.org"}; }
static quint64 dailyUpload() { return 124; }
static quint64 totalUpload() { return 241298412; }
static quint64 dailyDownload() { return 21312312312412; }
static quint64 totalDownload() { return 23112; }
static const QStringList lastDestinations();
static const TopDestinationList dailyTopDestinations();
static const TopDestinationList totalTopDestinations();
static quint64 dailyUpload() { return m_dailyUpload; }
static quint64 totalUpload() { return m_totalUpload; }
static quint64 dailyDownload() { return m_dailyDownload; }
static quint64 totalDownload() { return m_totalDownload; }
private:
static void incrementUpload(quint64 value);
static void incrementDownload(quint64 value);
static void addToDestinationsList(const QString& dest);
static void serialize();
static void deserialize();
static void actualizeTopLists();
static QStringList m_lastDestinations;
static qint64 m_lastSerializeTimestamp;
static bool m_deserialized;
static DailyCounter m_dailyUpload;
static DailyCounter m_dailyDownload;
static quint64 m_totalUpload;
static quint64 m_totalDownload;
static bool m_cacheUpdatedAfterLastReport;
static qint64 m_actualizeTopListsLastTimestamp;
static std::atomic<quint64> m_dailyUpload;
static std::atomic<quint64> m_dailyDownload;
static std::atomic<quint64> m_totalUpload;
static std::atomic<quint64> m_totalDownload;
static TopDestinationList m_dailyTopDestinations;
static TopDestinationList m_totalTopDestinations;
};
+9 -6
View File
@@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "webpage.h"
#include "proxyinstanse.h"
#include "g.h"
#include "statistics.h"
@@ -31,11 +32,11 @@ const QString WebPage::m_lastDestinationItem = "\
{{VALUE}}\n\
</li>\n";
const QString WebPage::m_dailyTopDestinationItem = "\
<li class=\"topDestinations__item\" title=\"{{VALUE}}\">\n\
<li class=\"topDestinations__item\" title=\"{{COUNT}}\">\n\
{{VALUE}}\n\
</li>\n";
const QString WebPage::m_totalTopDestinationItem = "\
<li class=\"topDestinations__item\" title=\"{{VALUE}}\">\n\
<li class=\"topDestinations__item\" title=\"{{COUNT}}\">\n\
{{VALUE}}\n\
</li>\n";
@@ -143,14 +144,14 @@ void WebPage::topDestinations(QString &document)
QString dailyTopList;
for (const auto& dTop: Statistics::dailyTopDestinations())
{
dailyTopList += dailyTopDestinationItem(dTop);
dailyTopList += dailyTopDestinationItem(dTop.first, dTop.second);
}
document.replace(g::c::HA_DAILY_TOP_DESTINATIONS_LIST, dailyTopList);
QString totalTopList;
for (const auto& dTop: Statistics::totalTopDestinations())
{
totalTopList += totalTopDestinationItem(dTop);
totalTopList += totalTopDestinationItem(dTop.first, dTop.second);
}
document.replace(g::c::HA_TOTAL_TOP_DESTINATIONS_LIST, totalTopList);
}
@@ -230,17 +231,19 @@ QString WebPage::lastDestinationItem(const QString &destination)
return result;
}
QString WebPage::dailyTopDestinationItem(const QString &destination)
QString WebPage::dailyTopDestinationItem(const QString &destination, quint64 count)
{
QString result {m_dailyTopDestinationItem};
result.replace("{{VALUE}}", destination);
result.replace("{{COUNT}}", QString::number(count));
return result;
}
QString WebPage::totalTopDestinationItem(const QString &destination)
QString WebPage::totalTopDestinationItem(const QString &destination, quint64 count)
{
QString result {m_totalTopDestinationItem};
result.replace("{{VALUE}}", destination);
result.replace("{{COUNT}}", QString::number(count));
return result;
}
+2 -2
View File
@@ -39,8 +39,8 @@ private:
static void copyright(QString& document);
static QString lastDestinationItem(const QString& destination);
static QString dailyTopDestinationItem(const QString& destination);
static QString totalTopDestinationItem(const QString& destination);
static QString dailyTopDestinationItem(const QString& destination, quint64 count);
static QString totalTopDestinationItem(const QString& destination, quint64 count);
static QString blockedDestinationItem(const QString& destination, const QStringList& addresses);
static QPair<QString, QString> bytesToHumanReadableString(quint64 bytes); // count, measure