2019-07-17 13:37:18 -04:00
//
// Created by wolverindev on 04.09.18.
//
# include <sql/SqlQuery.h>
# include <misc/std_unique_ptr.h>
2020-02-28 05:24:07 -05:00
# include <utility>
2019-07-17 13:37:18 -04:00
# include "StatisticManager.h"
2020-02-28 05:24:07 -05:00
# include "DatabaseHandler.h"
2019-07-17 13:37:18 -04:00
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 ( ) ) ;
}
}
2020-02-28 05:24:07 -05:00
StatisticManager : : StatisticManager ( std : : shared_ptr < license : : server : : database : : DatabaseHandler > manager ) : license_manager { std : : move ( manager ) } { }
StatisticManager : : ~ StatisticManager ( ) = default ;
2019-07-17 13:37:18 -04:00
struct GeneralStatisticEntry {
std : : chrono : : system_clock : : time_point age ;
2020-02-28 05:24:07 -05:00
string unique_id { " " } ;
uint64_t key_id { 0 } ;
uint64_t servers { 0 } ;
uint64_t clients { 0 } ;
uint64_t bots { 0 } ;
2019-07-17 13:37:18 -04:00
} ;
void StatisticManager : : reset_cache_general ( ) {
lock_guard < recursive_mutex > lock ( this - > _general_statistics_lock ) ;
this - > _general_statistics = nullptr ;
}
2020-02-28 05:24:07 -05:00
void parse_general_entry ( std : : deque < std : : unique_ptr < GeneralStatisticEntry > > & entries , bool unique , int length , string * values , string * names ) {
2019-07-17 13:37:18 -04:00
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
2020-02-28 05:24:07 -05:00
. query ( std : : function < decltype ( parse_general_entry ) > { parse_general_entry } , entries , true ) ;
2019-07-17 13:37:18 -04:00
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 ;
}