diff --git a/src/html/icons/arrow_up.svg b/src/html/icons/arrow_up.svg deleted file mode 100644 index 79e7cde..0000000 --- a/src/html/icons/arrow_up.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/src/webpage.cpp b/src/webpage.cpp new file mode 100644 index 0000000..de20ffa --- /dev/null +++ b/src/webpage.cpp @@ -0,0 +1,296 @@ +/* +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 . +*/ + +#include "webpage.h" +#include "g.h" +#include "statistics.h" + +#include +#include +#include +#include + +const QString WebPage::m_lastDestinationItem = "\ +
  • \n\ + {{VALUE}}\n\ +
  • \n"; +const QString WebPage::m_dailyTopDestinationItem = "\ +
  • \n\ + {{VALUE}}\n\ +
  • \n"; +const QString WebPage::m_totalTopDestinationItem = "\ +
  • \n\ + {{VALUE}}\n\ +
  • \n"; + +const QString WebPage::m_blockedDestinationsBlock = "\ +
    \n\ +
    \n\ + Blocked destinations\n\ +
    \n\ +
      \n\ +{{VALUE}}\n\ +
    \n\ +
    \n"; + +const QString WebPage::m_blockedDestinationItemLvl1 = "\ +
  • \n\ + \n\ + \n\ +
      \n\ +{{LIST}}\n\ +
    \n\ +
  • \n"; + +const QString WebPage::m_blockedDestinationItemLvl2 = "\ +
  • \n\ + {{VALUE}}\n\ +
  • \n"; + +const QString WebPage::m_informationBlock = "\ +
    \n\ +
    \n\ + Information\n\ +
    \n\ +
    \n\ + {{VALUE}}\n\ +
    \n\ +
    \n"; + +QByteArray WebPage::document() +{ + QFile src(":/html/index.html"); + if (not src.open(QIODevice::ReadOnly)) + { + qCritical() << "Can not read built-in index.html"; + return QByteArray(); + } + + QString page = src.readAll(); + src.close(); + + setTitle(page); + customStyles(page); + lastDestinations(page); + trafficBlock(page); + blockedDestinations(page); + informationBlock(page); + copyright(page); + + return page.toUtf8(); +} + +void WebPage::setTitle(QString &document) +{ + document.replace(g::c::HA_PAGE_TITLE, g::p::SERVICE_TITLE); +} + +void WebPage::customStyles(QString &document) +{ + bool exists = QFile::exists(g::p::WORKING_DIR + "/html/styles.css"); + document.replace(g::c::HA_CUSTOM_CSS, exists ? "\n " : ""); +} + +void WebPage::lastDestinations(QString &document) +{ + QStringList dests = Statistics::lastDestinations(); + QString destinationsBlock; + for (const auto& dest: dests) + { + destinationsBlock += lastDestinationItem(dest); + } + document.replace(g::c::HA_LAST_DESTINATIONS_LIST, destinationsBlock); +} + +void WebPage::trafficBlock(QString &document) +{ + auto dailyUpload = bytesToHumanReadableString( Statistics::dailyUpload() ); + document.replace(g::c::HA_DAILY_UPLOAD, dailyUpload.first); + document.replace(g::c::HA_DAILY_UPLOAD_MEASURE, dailyUpload.second); + + auto dailyDownload = bytesToHumanReadableString( Statistics::dailyDownload() ); + document.replace(g::c::HA_DAILY_DOWNLOAD, dailyDownload.first); + document.replace(g::c::HA_DAILY_DOWNLOAD_MEASURE, dailyDownload.second); + + auto totalUpload = bytesToHumanReadableString( Statistics::totalUpload() ); + document.replace(g::c::HA_TOTAL_UPLOAD, totalUpload.first + " " + totalUpload.second); + + auto totalDownload = bytesToHumanReadableString( Statistics::totalDownload() ); + document.replace(g::c::HA_TOTAL_DOWNLOAD, totalDownload.first + " " + totalDownload.second); +} + +void WebPage::topDestinations(QString &document) +{ +// QString dailyTopList; +// for (const auto& dTop: Statistics::dailyTopDestinations()) +// { +// QStringList +// } +} + +void WebPage::blockedDestinations(QString &document) +{ + QMap> uniqueRecords; + + QString blockedDestinationsBlock {m_blockedDestinationsBlock}; + QString blockedDestinationsList; + for (const auto& inst: g::instanses) + { + QMapIterator mIter(inst.second->blackList()); + while (mIter.hasNext()) + { + auto record = mIter.next(); + for (const auto& addr: record.value()) + { + uniqueRecords[record.key()].insert(addr); + } + + if (not uniqueRecords.contains(record.key())) + { + uniqueRecords.insert(record.key(), QSet()); + } + } + } + + QMapIterator> mIter(uniqueRecords); + while (mIter.hasNext()) + { + auto record = mIter.next(); + blockedDestinationsList += blockedDestinationItem(record.key(), record.value().values()); + } + + blockedDestinationsBlock.replace("{{VALUE}}", blockedDestinationsList); + document.replace(g::c::HA_BLOCKED_DESTINTIONS, blockedDestinationsList.isEmpty() ? "" : "\n"+blockedDestinationsBlock); +} + +void WebPage::informationBlock(QString &document) +{ + QFile f(g::p::WORKING_DIR + "/information.html"); + if (not f.exists()) + { + document.replace(g::c::HA_INFORMATION, ""); + return; + } + + QString infoBlock {m_informationBlock}; + QString customText; + if (f.exists()) + { + if (not f.open(QIODevice::ReadOnly)) + { + qWarning() << "information.html exists, but reading failed"; + } + else + { + customText = f.readAll(); + f.close(); + } + } + + infoBlock.replace("{{VALUE}}", customText); + document.replace(g::c::HA_INFORMATION, "\n"+infoBlock); +} + +void WebPage::copyright(QString &document) +{ + document.replace(g::c::HA_COPYRIGHT, g::c::COPYRIGHT); +} + +QString WebPage::lastDestinationItem(const QString &destination) +{ + QString result {m_lastDestinationItem}; + result.replace("{{VALUE}}", destination); + return result; +} + +QString WebPage::dailyTopDestinationItem(const QString &destination) +{ + QString result {m_dailyTopDestinationItem}; + result.replace("{{VALUE}}", destination); + return result; +} + +QString WebPage::totalTopDestinationItem(const QString &destination) +{ + QString result {m_totalTopDestinationItem}; + result.replace("{{VALUE}}", destination); + return result; +} + +QString WebPage::blockedDestinationItem(const QString &destination, const QStringList &addresses) +{ + QString result {m_blockedDestinationItemLvl1}; + result.replace("{{VALUE}}", destination); + QString addressesItems; + for (const auto& addr: addresses) + { + QString addrItem {m_blockedDestinationItemLvl2}; + addrItem.replace("{{VALUE}}", addr); + addressesItems += addrItem; + } + result.replace("{{LIST}}", addressesItems); + return result; +} + +QPair WebPage::bytesToHumanReadableString(quint64 bytes) +{ + QPair result; + + constexpr const qint64 thresh = 1024; + + if (bytes < thresh) + { + result.first = QString::number(bytes); + result.second = "B"; + } + + else if (bytes <= thresh*thresh) + { + result.first = QString::number(bytes/thresh); + result.second = "KiB"; + } + + else if (bytes <= thresh*thresh*thresh) + { + result.first = QString::number(bytes/thresh/thresh); + result.second = "MiB"; + } + + else if (bytes <= thresh*thresh*thresh*thresh) + { + result.first = QString::number(bytes/thresh/thresh/thresh); + result.second = "GiB"; + } + + else if (bytes <= thresh*thresh*thresh*thresh*thresh) + { + result.first = QString::number(bytes/thresh/thresh/thresh/thresh); + result.second = "TiB"; + } + + else if (bytes <= thresh*thresh*thresh*thresh*thresh*thresh) + { + result.first = QString::number(bytes/thresh/thresh/thresh/thresh/thresh); + result.second = "PiB"; + } + + return result; +}