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 ;
}