#include "statistics.h" #include #include #include namespace fs = std::filesystem; using namespace std::string_literals; namespace { const fs::path default_statsfilepath{ "stats.db" }; } // anonymous namespace void Statistics::load() { std::lock_guard lock(mMutex); std::cout << "Loading statistics..." << std::endl; std::ifstream file{mPath, std::ios::in | std::ios::binary}; if (file.is_open()) { Reichwein::Serialization::IArchive archive{file}; archive >> mBins; } else { std::cerr << "Warning: Couldn't read statistics" << std::endl; } mChanged = false; } void Statistics::save() { if (mChanged) { std::lock_guard lock(mMutex); std::cout << "Saving statistics..." << std::endl; std::ofstream file{mPath, std::ios::out | std::ios::binary | std::ios::trunc}; if (file.is_open()) { Reichwein::Serialization::OArchive archive{file}; archive << mBins; } else { std::cerr << "Warning: Couldn't write statistics" << std::endl; } mChanged = false; } } Statistics::Statistics(): mPath{default_statsfilepath} { load(); } Statistics::Statistics(const fs::path& path): mPath{path.empty() ? default_statsfilepath : path} { load(); } Statistics::~Statistics() { save(); } bool Statistics::Bin::expired() const { uint64_t now {static_cast(time(nullptr))}; if (now < start_time) std::runtime_error("Statistics time is in the future"); return start_time + binsize < now; } void Statistics::limit() { while (mBins.size() * sizeof(Bin) > maxSize) mBins.pop_front(); // discard oldest element } void Statistics::count(size_t bytes_in, size_t bytes_out, bool error, bool ipv6, bool https) { std::lock_guard lock(mMutex); mChanged = true; if (mBins.empty() || mBins.back().expired()) { mBins.emplace_back(Bin{static_cast((time(nullptr) / binsize) * binsize), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); } Bin& bin{mBins.back()}; bin.requests++; if (error) bin.errors++; bin.bytes_in += bytes_in; bin.bytes_out += bytes_out; if (ipv6) { bin.requests_ipv6++; if (error) bin.errors_ipv6++; bin.bytes_in_ipv6 += bytes_in; bin.bytes_out_ipv6 += bytes_out; } if (https) { bin.requests_https++; if (error) bin.errors_https++; bin.bytes_in_https += bytes_in; bin.bytes_out_https += bytes_out; } limit(); } std::string Statistics::getValues() { std::lock_guard lock(mMutex); std::string result; for (const auto& bin: mBins) { result += std::to_string(bin.start_time) + ","s + std::to_string(bin.requests) + ","s + std::to_string(bin.errors) + ","s + std::to_string(bin.bytes_in) + ","s + std::to_string(bin.bytes_out) + ","s + std::to_string(bin.requests_ipv6) + ","s + std::to_string(bin.errors_ipv6) + ","s + std::to_string(bin.bytes_in_ipv6) + ","s + std::to_string(bin.bytes_out_ipv6) + ","s + std::to_string(bin.requests_https) + ","s + std::to_string(bin.errors_https) + ","s + std::to_string(bin.bytes_in_https) + ","s + std::to_string(bin.bytes_out_https) + "\n"s; } return result; }