#include #include #include #include #include #include #include #include "server/WebAPI.h" #include "server/StatisticManager.h" #include #include "server/UserManager.h" #include #include using namespace std; using namespace std::chrono; using namespace license; /* * Requests/license: SELECT `tmp`.`keyId`, `tmp`.`key`, `tmp`.`ip`, `tmp`.`count`, `license_info`.`username`, `tmp`.`type` FROM (SELECT DISTINCT `license_request`.`keyId`, `key`, `license_request`.`ip`, COUNT(`license_request`.`keyId`) AS `count`, `license`.`type` FROM `license_request` INNER JOIN `license` ON `license`.`keyId` = `license_request`.`keyId` GROUP BY (`license_request`.`ip`)) AS `tmp` INNER JOIN `license_info` ON `license_info`.`keyId` = `tmp`.`keyId` * Different IP's: SELECT `tmp`.`keyId`, `license_info`.`username`, COUNT(`ip`) FROM (SELECT DISTINCT `ip`, `keyId` FROM `license_request`) AS `tmp` LEFT JOIN `license_info` ON `license_info`.`keyId` = `tmp`.`keyId` GROUP BY (`tmp`.`keyId`) * * Requests (license) / ip: SELECT DISTINCT `ip`, COUNT(`ip`) FROM `license_request` WHERE `keyId` = ? GROUP BY `ip` * * SELECT DISTINCT(`ip`), `keyId` FROM `license_request` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000 * * SELECT DISTINCT(`ip`), `license_request`.`keyId`, `license_info`.`username` FROM `license_request` LEFT JOIN `license_info` ON `license_info`.`keyId` = `license_request`.`keyId` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000 * * * Online clients: SELECT SUM(`clients`) FROM (SELECT DISTINCT(`ip`), `clients` FROM `history_online` WHERE `timestamp` > (UNIX_TIMESTAMP() - 60 * 60 * 2) * 1000) AS `a` * Online bots: SELECT SUM(`clients`) FROM (SELECT DISTINCT(`ip`), `clients` FROM `history_online` WHERE `timestamp` > (UNIX_TIMESTAMP() - 60 * 60 * 2) * 1000) AS `a` * Online VS Server: SELECT SUM(`music`) FROM (SELECT DISTINCT(`ip`), `music` FROM `history_online` WHERE `timestamp` > (UNIX_TIMESTAMP() - 60 * 60 * 2) * 1000) AS `a` */ bool handle_command(string& line); shared_ptr license_manager; shared_ptr statistic_manager; shared_ptr ssl_manager; shared_ptr web_server; shared_ptr license_server; shared_ptr user_manager; int main(int argc, char** argv) { if(argc < 2) { cerr << "Invalid arguments! Need MySQL connection" << endl; return 0; } evthread_use_pthreads(); http::decode_url("xxx"); srand(system_clock::now().time_since_epoch().count()); terminal::install(); if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; } auto config = std::make_shared(); config->vs_group_size = 0; config->logfileLevel = spdlog::level::trace; config->terminalLevel = spdlog::level::trace; config->logPath = "logs/log_${time}(%Y-%m-%d_%H:%M:%S).log"; logger::setup(config); string error; sql::SqlManager* database = new sql::mysql::MySQLManager(); bool db_connected = true; ((sql::mysql::MySQLManager*) database)->listener_disconnected = [&](bool wanted){ if(wanted) return; logCritical("Lost connection to MySQL server!"); logCritical("Stopping server!"); db_connected = false; }; //mysql://localhost:3306/license?userName=root&password=markus logMessage(LOG_GENERAL, "Connecting to {}", argv[1]); auto connect_result = database->connect(string(argv[1])); if(!connect_result) { logError("Could not connect to mysql server! (" + connect_result.fmtStr() + ")"); return 0; } #if false sql::command(database, "INSERT INTO license (`key`, type, deleted, issuer) VALUES ('0020', 1, 1, 'Test'); ").execute(); cout << sql::command(database, "SELECT LAST_INSERT_ID();").query([](void*, int length, string* values, string* names) { for(int i = 0; i < length; i++) cout << names[i] << " -> " << values[i] << endl; return 0; }, (void*) nullptr) << endl; #endif license_manager = make_shared(database); if(!license_manager->setup(error)) { logError("Could not start license manager! (" +error + ")"); return 0; } statistic_manager = make_shared(license_manager); /* { auto _now = system_clock::now(); auto statistics = license_manager->list_statistics_user(_now - hours(24) * 32 * 4, _now, duration_cast(hours(2))); cout << "Date,Instances,Servers,Clients,Web Clients,Queries,Music Bots" << endl; for(const auto& entry : statistics) { auto time = system_clock::to_time_t(entry->timestamp); tm* localtm = localtime(&time); string string_time = asctime(localtm); string_time = string_time.substr(0, string_time.length() - 1); //cout << "[" << string_time << "] Users online: " << entry->clients_online << " | Instances: " << entry->instance_online << endl; cout << string_time << "," << entry->instance_online << "," << entry->servers_online << "," << entry->clients_online << "," << entry->web_clients_online << "," << entry->queries_online << "," << entry->bots_online << endl; } } return 0; { auto _now = system_clock::now(); auto statistics = license_manager->list_statistics_version(_now - hours(24) * 9, _now, duration_cast(hours(1))); std::deque versions; const auto version_name = [](const std::string& key) { auto space = key.find(' '); return key.substr(0, space); }; for(const auto& entry : statistics) { for(const auto& version : entry->versions) { const auto name = version_name(version.first); if(name.empty()) { continue; } auto it = find(versions.begin(), versions.end(), name); if(it == versions.end()) versions.push_back(name); } } sort(versions.begin(), versions.end(), [](const std::string& a, const std::string& b) { const auto index_a = a.find_last_of('.'); const auto index_b = b.find_last_of('.'); const auto length_a = a.find('-', index_a) - index_a - 1; const auto length_b = b.find('-', index_b) - index_b - 1; const auto patch_a = stoll(a.substr(index_a + 1, length_a)); const auto patch_b = stoll(b.substr(index_b + 1, length_b)); return patch_a > patch_b; }); cout << "Date"; for(auto it = versions.begin(); it != versions.end(); it++) cout << "," << *it; cout << endl; for(const auto& entry : statistics) { auto time = system_clock::to_time_t(entry->timestamp); tm* localtm = localtime(&time); string string_time = asctime(localtm); string_time = string_time.substr(0, string_time.length() - 1); map version_count; for(const auto& version : entry->versions) { const auto name = version_name(version.first); version_count[name] += version.second; } cout << string_time; for(const auto& name : versions) { cout << "," << version_count[name]; } cout << endl; } } */ ssl_manager = make_shared(); { string key_file = "certificates/web_stats_prv.pem"; string cert_file = "certificates/web_stats_crt.pem"; if(!ssl_manager->initializeContext("web_stats", key_file, cert_file, error, false, make_shared(ts::ssl::SSLGenerator{ .subjects = {}, .issues = {{"O", "TeaSpeak"}, {"OU", "License server"}, {"creator", "WolverinDEV"}} }))) { logCritical(LOG_LICENSE_WEB, "Failed to initialize ssl certificate! Stopping server."); } } { web_server = make_shared(license_manager, statistic_manager); logMessage("Starting web server on [:::]:27788"); if(!web_server->start(error, 27788, ssl_manager->getContext("web_stats"))) { logError(LOG_GENERAL, "Failed to start web statistics server!"); return 0; } } { user_manager = make_shared(database); } { logMessage("Starting license server on [:::]:27786"); struct sockaddr_in listen_addr{}; memset(&listen_addr, 0, sizeof(listen_addr)); listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = INADDR_ANY; listen_addr.sin_port = htons(27786); license_server = make_shared(listen_addr, license_manager, statistic_manager, web_server, user_manager); license_server->startServer(); } while(db_connected && web_server->running() && license_server->isRunning()) { auto line = terminal::instance()->readLine("§a> §f"); if(line.empty()){ usleep(500); continue; } if(!handle_command(line)) { terminal::instance()->writeMessage("§aStopping server..."); break; } } web_server->stop(); license_server->stopServer(); if(database) database->disconnect(); logger::uninstall(); terminal::uninstall(); return 0; } bool handle_command(string& line) { if(line == "end" || line == "stop") return false; //Exit loop if(line == "info web") { logMessage(LOG_LICENSE_WEB, "Currently online clients:"); auto clients = web_server->get_clients(); for(const auto& client : clients) logMessage(LOG_LICENSE_WEB, " - {}", client->client_prefix()); logMessage(LOG_LICENSE_WEB, " {} clients are currently connected!", clients.size()); return true; } logError("Invalid command: " + line); return true; }