201 lines
6.6 KiB
C++
201 lines
6.6 KiB
C++
|
//
|
||
|
// Created by wolverindev on 04.09.18.
|
||
|
//
|
||
|
|
||
|
#include <sql/SqlQuery.h>
|
||
|
#include <misc/std_unique_ptr.h>
|
||
|
#include "StatisticManager.h"
|
||
|
#include "LicenseManager.h"
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace std::chrono;
|
||
|
using namespace license;
|
||
|
using namespace license::server;
|
||
|
using namespace license::stats;
|
||
|
|
||
|
std::chrono::milliseconds HistoryStatistics::time_period(license::stats::HistoryStatistics::HistoryType type) {
|
||
|
switch (type) {
|
||
|
case HistoryType::LAST_DAY:
|
||
|
case HistoryType::DAY_YESTERDAY:
|
||
|
case HistoryType::DAY_7DAYS_AGO:
|
||
|
return minutes(15);
|
||
|
case HistoryType::LAST_WEEK:
|
||
|
return hours(1);
|
||
|
case HistoryType::LAST_MONTH:
|
||
|
case HistoryType::LAST_HALF_YEAR:
|
||
|
default:
|
||
|
return hours(2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::chrono::milliseconds HistoryStatistics::cache_timeout(license::stats::HistoryStatistics::HistoryType type) {
|
||
|
switch (type) {
|
||
|
case HistoryType::LAST_DAY:
|
||
|
case HistoryType::DAY_YESTERDAY:
|
||
|
case HistoryType::DAY_7DAYS_AGO:
|
||
|
return minutes(15);
|
||
|
case HistoryType::LAST_WEEK:
|
||
|
return hours(1);
|
||
|
case HistoryType::LAST_MONTH:
|
||
|
return hours(2);
|
||
|
|
||
|
case HistoryType::LAST_HALF_YEAR:
|
||
|
default:
|
||
|
return hours(8);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::chrono::milliseconds HistoryStatistics::type_duration(license::stats::HistoryStatistics::HistoryType type) {
|
||
|
switch (type) {
|
||
|
case HistoryType::LAST_DAY:
|
||
|
case HistoryType::DAY_YESTERDAY:
|
||
|
case HistoryType::DAY_7DAYS_AGO:
|
||
|
return hours(24);
|
||
|
case HistoryType::LAST_WEEK:
|
||
|
return hours(24) * 7;
|
||
|
case HistoryType::LAST_MONTH:
|
||
|
return hours(24) * 32;
|
||
|
case HistoryType::LAST_HALF_YEAR:
|
||
|
return hours(24) * 32 * 6;
|
||
|
default:
|
||
|
return hours(24);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
system_clock::time_point HistoryStatistics::align_type(license::stats::HistoryStatistics::HistoryType type, const std::chrono::system_clock::time_point &tp) {
|
||
|
switch (type) {
|
||
|
case HistoryType::LAST_DAY:
|
||
|
case HistoryType::DAY_YESTERDAY:
|
||
|
case HistoryType::DAY_7DAYS_AGO:
|
||
|
return system_clock::time_point() + minutes(duration_cast<minutes>(tp.time_since_epoch()).count());
|
||
|
case HistoryType::LAST_WEEK:
|
||
|
case HistoryType::LAST_MONTH:
|
||
|
case HistoryType::LAST_HALF_YEAR:
|
||
|
default:
|
||
|
return system_clock::time_point() + hours(duration_cast<hours>(tp.time_since_epoch()).count());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StatisticManager::StatisticManager(const std::shared_ptr<license::server::LicenseManager> &manager) : license_manager(manager) {}
|
||
|
StatisticManager::~StatisticManager() {}
|
||
|
|
||
|
struct GeneralStatisticEntry {
|
||
|
std::chrono::system_clock::time_point age;
|
||
|
string unique_id = "";
|
||
|
uint64_t key_id = 0;
|
||
|
uint64_t servers = 0;
|
||
|
uint64_t clients = 0;
|
||
|
uint64_t bots = 0;
|
||
|
};
|
||
|
|
||
|
void StatisticManager::reset_cache_general() {
|
||
|
lock_guard<recursive_mutex> lock(this->_general_statistics_lock);
|
||
|
this->_general_statistics = nullptr;
|
||
|
}
|
||
|
|
||
|
void parse_general_entry(deque<unique_ptr<GeneralStatisticEntry>>& entries, bool unique, int length, string* values, string* names) {
|
||
|
auto entry = make_unique<GeneralStatisticEntry>();
|
||
|
for(int index = 0; index < length; index++) {
|
||
|
if(names[index] == "keyId") {
|
||
|
entry->key_id = stoull(values[index]);
|
||
|
} else if(names[index] == "timestamp") {
|
||
|
entry->age = system_clock::time_point() + milliseconds(stoll(values[index]));
|
||
|
} else if(names[index] == "server") {
|
||
|
entry->servers = stoull(values[index]);
|
||
|
} else if(names[index] == "clients") {
|
||
|
entry->clients = stoull(values[index]);
|
||
|
} else if(names[index] == "music") {
|
||
|
entry->bots = stoull(values[index]);
|
||
|
} else if(names[index] == "unique_id")
|
||
|
entry->unique_id = values[index];
|
||
|
}
|
||
|
|
||
|
if(unique) {
|
||
|
for(auto& e : entries) {
|
||
|
if(e->key_id == entry->key_id && e->unique_id == entry->unique_id) {
|
||
|
if(e->age < entry->age) {
|
||
|
entries.erase(find(entries.begin(), entries.end(), e));
|
||
|
break;
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
entries.push_back(std::move(entry));
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<GeneralStatistics> StatisticManager::general_statistics() {
|
||
|
unique_lock<recursive_mutex> lock(this->_general_statistics_lock);
|
||
|
if(this->_general_statistics && system_clock::now() < this->_general_statistics->age + seconds(300)) return this->_general_statistics;
|
||
|
|
||
|
lock.unlock();
|
||
|
unique_lock create_lock(this->_general_statistics_generate_lock);
|
||
|
lock.lock();
|
||
|
if(this->_general_statistics && system_clock::now() < this->_general_statistics->age + seconds(300)) return this->_general_statistics;
|
||
|
lock.unlock();
|
||
|
|
||
|
deque<unique_ptr<GeneralStatisticEntry>> entries;
|
||
|
|
||
|
auto result = sql::command(this->license_manager->sql(), "SELECT `keyId`, `unique_id`, `timestamp`,`server`,`clients`,`music` FROM `history_online` WHERE `timestamp` > :time ORDER BY `timestamp` ASC",
|
||
|
variable{":time", duration_cast<milliseconds>(system_clock::now().time_since_epoch() - hours(2) - minutes(10)).count()}) //10min as buffer
|
||
|
.query(std::function<decltype(parse_general_entry)>(parse_general_entry), entries, true);
|
||
|
|
||
|
auto stats = make_shared<GeneralStatistics>();
|
||
|
for(auto& entry : entries) {
|
||
|
stats->bots += entry->bots;
|
||
|
stats->clients += entry->clients;
|
||
|
stats->servers += entry->servers;
|
||
|
stats->instances++;
|
||
|
}
|
||
|
stats->age = system_clock::now();
|
||
|
|
||
|
lock.lock();
|
||
|
this->_general_statistics = stats;
|
||
|
lock.unlock();
|
||
|
create_lock.unlock();
|
||
|
return stats;
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<HistoryStatistics> StatisticManager::history(license::stats::HistoryStatistics::HistoryType type) {
|
||
|
lock_guard<recursive_mutex> lock(this->_history_locks[type]);
|
||
|
auto current_time = system_clock::now();
|
||
|
auto& entry = this->_history[type];
|
||
|
|
||
|
if(entry && entry->evaluated + HistoryStatistics::cache_timeout(type) > current_time)
|
||
|
return entry;
|
||
|
|
||
|
entry = make_shared<HistoryStatistics>();
|
||
|
|
||
|
entry->period = HistoryStatistics::time_period(type);
|
||
|
entry->begin = HistoryStatistics::align_type(type, current_time - HistoryStatistics::type_duration(type));
|
||
|
entry->end = HistoryStatistics::align_type(type, current_time);
|
||
|
|
||
|
if(type == HistoryStatistics::DAY_YESTERDAY || type == HistoryStatistics::DAY_7DAYS_AGO) {
|
||
|
auto& reference = this->_history[HistoryStatistics::LAST_DAY];
|
||
|
if(reference) {
|
||
|
entry->begin = reference->begin;
|
||
|
entry->end = reference->end;
|
||
|
entry->evaluated = reference->evaluated;
|
||
|
}
|
||
|
if(type == HistoryStatistics::DAY_YESTERDAY) {
|
||
|
entry->begin -= hours(24);
|
||
|
entry->end -= hours(24);
|
||
|
} else if(type == HistoryStatistics::DAY_7DAYS_AGO) {
|
||
|
entry->begin -= hours(24) * 7;
|
||
|
entry->end -= hours(24) * 7;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
auto statistics = this->license_manager->list_statistics_user(entry->begin, entry->end, entry->period);
|
||
|
|
||
|
entry->statistics = std::move(statistics);
|
||
|
if(entry->evaluated.time_since_epoch().count() == 0)
|
||
|
entry->evaluated = current_time;
|
||
|
|
||
|
if(type == HistoryStatistics::LAST_DAY) {
|
||
|
this->history(HistoryStatistics::DAY_YESTERDAY);
|
||
|
this->history(HistoryStatistics::DAY_7DAYS_AGO);
|
||
|
}
|
||
|
return entry;
|
||
|
}
|