/* 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); topDestinations(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()) { dailyTopList += dailyTopDestinationItem(dTop); } document.replace(g::c::HA_DAILY_TOP_DESTINATIONS_LIST, dailyTopList); QString totalTopList; for (const auto& dTop: Statistics::totalTopDestinations()) { totalTopList += totalTopDestinationItem(dTop); } document.replace(g::c::HA_TOTAL_TOP_DESTINATIONS_LIST, totalTopList); } 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; }