2019-07-17 19:37:18 +02:00
#include <iostream>
#include <shared/License.h>
#include <server/LicenseServer.h>
#include <log/LogUtils.h>
#include <CXXTerminal/Terminal.h>
#include <sql/mysql/MySQL.h>
#include <pipes/misc/http.h>
#include "server/WebAPI.h"
#include "server/StatisticManager.h"
#include <event2/thread.h>
#include "server/UserManager.h"
#include <misc/base64.h>
#include <misc/digest.h>
2019-08-25 22:16:42 +02:00
#include <fstream>
2019-07-17 19:37:18 +02:00
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
2019-08-25 22:16:42 +02:00
* //462
2019-07-17 19:37:18 +02:00
*
* 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 < server :: LicenseManager > license_manager ;
shared_ptr < stats :: StatisticManager > statistic_manager ;
shared_ptr < ts :: ssl :: SSLManager > ssl_manager ;
shared_ptr < license :: web :: WebStatistics > web_server ;
shared_ptr < LicenseServer > license_server ;
shared_ptr < UserManager > 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 < logger :: LoggerConfig > ();
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 < server :: LicenseManager > ( database );
if ( ! license_manager -> setup ( error )) {
logError ( "Could not start license manager! (" + error + ")" );
return 0 ;
}
statistic_manager = make_shared < stats :: StatisticManager > ( license_manager );
/*
{
auto _now = system_clock::now();
auto statistics = license_manager->list_statistics_user(_now - hours(24) * 32 * 4, _now, duration_cast<milliseconds>(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;
2019-08-25 22:16:42 +02:00
*/
/*
{
ofstream _file_out("version_history.txt");
2019-07-17 19:37:18 +02:00
auto _now = system_clock::now();
2019-08-25 22:16:42 +02:00
cout << "Getting statistics" << endl;
auto statistics = license_manager->list_statistics_version(_now - hours(24) * 32 * 12, _now, duration_cast<milliseconds>(hours(1)));
cout << "Grouping statistics" << endl;
2019-07-17 19:37:18 +02:00
std::deque<std::string> 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);
}
}
2019-08-25 22:16:42 +02:00
cout << "Sorting statistics" << endl;
2019-07-17 19:37:18 +02:00
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;
});
2019-08-25 22:16:42 +02:00
cout << "Writing statistics" << endl;
_file_out << "Date";
for(auto & version : versions)
_file_out << "," << version;
_file_out << endl;
2019-07-17 19:37:18 +02:00
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<string, int> version_count;
for(const auto& version : entry->versions) {
const auto name = version_name(version.first);
version_count[name] += version.second;
}
2019-08-25 22:16:42 +02:00
_file_out << string_time;
2019-07-17 19:37:18 +02:00
for(const auto& name : versions) {
2019-08-25 22:16:42 +02:00
_file_out << "," << version_count[name];
2019-07-17 19:37:18 +02:00
}
2019-08-25 22:16:42 +02:00
_file_out << endl;
}s
cout << "Done statistics" << endl;
_file_out.flush();
}
return 0;
*/
2019-07-17 19:37:18 +02:00
ssl_manager = make_shared < ts :: ssl :: SSLManager > ();
{
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 > ( 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 :: web :: WebStatistics > ( 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 < UserManager > ( 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 < LicenseServer > ( 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 ;
}