diff --git a/src/dbmanager.cpp b/src/dbmanager.cpp index f451625..7d58401 100644 --- a/src/dbmanager.cpp +++ b/src/dbmanager.cpp @@ -78,11 +78,32 @@ void DBManager::initAtStart() query.exec ("VACUUM"); } -TopDestinationList DBManager::totalTop() const +DestinationList DBManager::allHistory() const { QSqlQuery query(m_db); - TopDestinationList result; + DestinationList result; + + if (not query.exec("SELECT * FROM total_history ORDER BY request_counter DESC")) + { + qCritical() << "Db query failed:" << query.lastError().text(); + } + else + { + while (query.next()) + { + result.push_back( {query.value(0).toString(), query.value(1).toULongLong()} ); + } + } + + return result; +} + +DestinationList DBManager::totalTop() const +{ + QSqlQuery query(m_db); + + DestinationList result; if (not query.exec("SELECT * FROM total_history ORDER BY request_counter DESC LIMIT " + QString::number(g::p::LAST_AND_TOP_LIST_SIZE))) { @@ -99,11 +120,11 @@ TopDestinationList DBManager::totalTop() const return result; } -TopDestinationList DBManager::dailyTop() const +DestinationList DBManager::dailyTop() const { QSqlQuery query(m_db); - TopDestinationList result; + DestinationList result; if (not query.exec("SELECT * FROM daily_history ORDER BY request_counter DESC LIMIT " + QString::number(g::p::LAST_AND_TOP_LIST_SIZE))) { diff --git a/src/dbmanager.h b/src/dbmanager.h index bd06f81..04eeb64 100644 --- a/src/dbmanager.h +++ b/src/dbmanager.h @@ -43,8 +43,9 @@ public: DBManager(); void initAtStart(); - TopDestinationList totalTop() const; - TopDestinationList dailyTop() const; + DestinationList allHistory() const; + DestinationList totalTop() const; + DestinationList dailyTop() const; quint64 totalTopCount(const QString& dest) const; quint64 dailyTopCount(const QString& dest) const; quint64 incrementTotalTopCount(const QString& dest); diff --git a/src/g.h b/src/g.h index 5682481..499f074 100644 --- a/src/g.h +++ b/src/g.h @@ -27,7 +27,7 @@ class QFile; class ProxyInstanse; class QThread; -using TopDestinationList = QList>; +using DestinationList = QList>; namespace g /* for Global */ { diff --git a/src/html/index.html b/src/html/index.html index a86d36e..e3338db 100644 --- a/src/html/index.html +++ b/src/html/index.html @@ -99,7 +99,7 @@ {{INFORMATION}}
- Top {{TOP_MEASURE}} + Top {{TOP_MEASURE}} (all)
diff --git a/src/httpdocument.cpp b/src/httpdocument.cpp index 2f1ebef..035ef34 100644 --- a/src/httpdocument.cpp +++ b/src/httpdocument.cpp @@ -82,6 +82,22 @@ void HttpDocument::setBody(const QByteArray &body) m_body = body; } +void HttpDocument::setBody(const QString &body, const QString &oldETag) +{ + QString eTag = g::hash(body.toUtf8()); + + if (oldETag == eTag) + { + qDebug() << "Data cached by user (not file on disk) / Hash:" << oldETag; + + setCode(Code::_304); + return; + } + + setBody(body.toUtf8()); + setHeader(CommonHeader::ETag, eTag); +} + void HttpDocument::setBody(const QJsonObject &body) { m_body = QJsonDocument(body).toJson(QJsonDocument::JsonFormat::Compact); diff --git a/src/httpdocument.h b/src/httpdocument.h index 27e39a0..8c1e821 100644 --- a/src/httpdocument.h +++ b/src/httpdocument.h @@ -74,6 +74,7 @@ public: void setBody(const QByteArray& body); void setBody(const QJsonObject& body); void setBody(QFile&& payload, const QString& eTag = QString()); + void setBody(const QString& body, const QString& eTag); void setBodySingleHTMLLabel(const QString& text, const QString& title = "Notice"); QByteArray body() const { return m_body; } diff --git a/src/socketrunnable.cpp b/src/socketrunnable.cpp index c22dfb5..8ddea07 100644 --- a/src/socketrunnable.cpp +++ b/src/socketrunnable.cpp @@ -18,6 +18,7 @@ along with this program. If not, see . */ #include "socketrunnable.h" +#include "statistics.h" #include "g.h" #include "webpage.h" @@ -49,7 +50,12 @@ void SocketRunnable::get() QString eTag = g::getValue(m_headers, "If-None-Match", g::GetValueType::HttpHeader); - if (urlPath() == "/main.css") + if (urlPath() == "/~stats.txt") + { + httpDocument().setBody(Statistics::statsTxt(), eTag); + httpDocument().setHeader(HttpDocument::CommonHeader::ContentType, HttpDocument::ContentType::TEXT); + } + else if (urlPath() == "/main.css") { httpDocument().setBody(QFile(":/html/main.css"), eTag); } diff --git a/src/statistics.cpp b/src/statistics.cpp index 6fef0d6..5eb5955 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -19,6 +19,7 @@ along with this program. If not, see . #include "statistics.h" #include "dbmanager.h" +#include "webpage.h" #include "g.h" #include @@ -36,8 +37,8 @@ std::atomic Statistics::m_totalUpload {0}; std::atomic Statistics::m_totalDownload {0}; QMutex Statistics::m_topDestinationsMtx; -TopDestinationList Statistics::m_dailyTopDestinations; -TopDestinationList Statistics::m_totalTopDestinations; +DestinationList Statistics::m_dailyTopDestinations; +DestinationList Statistics::m_totalTopDestinations; bool Statistics::m_cacheUpdatedAfterLastReport = false; qint64 Statistics::m_actualizeTopListsLastTimestamp = 0; @@ -91,7 +92,7 @@ const QStringList Statistics::lastDestinations() return m_lastDestinations; } -const TopDestinationList Statistics::dailyTopDestinations() +const DestinationList Statistics::dailyTopDestinations() { if (not m_cacheUpdatedAfterLastReport) { @@ -101,7 +102,7 @@ const TopDestinationList Statistics::dailyTopDestinations() return m_dailyTopDestinations; } -const TopDestinationList Statistics::totalTopDestinations() +const DestinationList Statistics::totalTopDestinations() { QMutexLocker lock (&m_topDestinationsMtx); return m_totalTopDestinations; @@ -116,6 +117,32 @@ void Statistics::initTrafficCounters() m_totalUpload = db.totalUploadTraffic(); } +QString Statistics::statsTxt() +{ + static QMutex mtx; + if (not mtx.tryLock()) + { + return "Service is busy, try again later."; + } + + auto raw = DBManager().allHistory(); + + quint64 totalRequests = 0; + QString result; + + for (const auto& record: raw) + { + result += WebPage::counterToHumanReadableString(record.second) + "\t" + record.first + "\n"; + totalRequests += record.second; + } + + result.push_front("Total destinations: " + WebPage::counterToHumanReadableString(raw.size()) + "\n" + "Total requests: " + WebPage::counterToHumanReadableString(totalRequests) + "\n\n"); + + mtx.unlock(); + return result; +} + void Statistics::actualizeTopLists() { QMutexLocker lock (&m_topDestinationsMtx); diff --git a/src/statistics.h b/src/statistics.h index b0976b0..a59032f 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -40,8 +40,8 @@ public: static const QStringList lastDestinations(); - static const TopDestinationList dailyTopDestinations(); - static const TopDestinationList totalTopDestinations(); + static const DestinationList dailyTopDestinations(); + static const DestinationList totalTopDestinations(); static void initTrafficCounters(); static quint64 dailyUpload() { return m_dailyUpload; } @@ -49,6 +49,8 @@ public: static quint64 dailyDownload() { return m_dailyDownload; } static quint64 totalDownload() { return m_totalDownload; } + static QString statsTxt(); + private: static void actualizeTopLists(); static bool isIpAddress(const QString& dest); @@ -65,7 +67,7 @@ private: static std::atomic m_totalDownload; static QMutex m_topDestinationsMtx; - static TopDestinationList m_dailyTopDestinations; - static TopDestinationList m_totalTopDestinations; + static DestinationList m_dailyTopDestinations; + static DestinationList m_totalTopDestinations; }; diff --git a/src/webpage.cpp b/src/webpage.cpp index 9e5bf77..3838e22 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -192,10 +192,10 @@ quint64 WebPage::trafficBlock(QString &document, quint64 lastTrafficVolume) document.replace(g::c::HA_DAILY_DOWNLOAD_MEASURE, dailyDownload.measure); auto totalUpload = bytesToHumanReadableString( Statistics::totalUpload() ); - document.replace(g::c::HA_TOTAL_UPLOAD, totalUpload.integer + " " + totalUpload.measure); + document.replace(g::c::HA_TOTAL_UPLOAD, totalUpload.integer + totalUpload.decimal + " " + totalUpload.measure); auto totalDownload = bytesToHumanReadableString( Statistics::totalDownload() ); - document.replace(g::c::HA_TOTAL_DOWNLOAD, totalDownload.integer + " " + totalDownload.measure); + document.replace(g::c::HA_TOTAL_DOWNLOAD, totalDownload.integer + totalDownload.decimal + " " + totalDownload.measure); return currentVolume; } diff --git a/src/webpage.h b/src/webpage.h index 10d3e98..4241ce1 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -29,6 +29,7 @@ class WebPage public: WebPage() = delete; static QByteArray document(quint64 lastTrafficVolume, quint64* currentTrafficVolume = nullptr); + static QString counterToHumanReadableString(quint64 count); private: static void setTitle(QString& document); @@ -45,7 +46,6 @@ private: static QString topDestinationItem(const QString& destination, quint64 count); static QString blockedDestinationItem(const QString& destination, const QStringList& addresses); static HumanReadableValue bytesToHumanReadableString(quint64 bytes); - static QString counterToHumanReadableString(quint64 count); static const QString m_lastDestinationItemAllowed; static const QString m_lastDestinationItemBlocked;