2016-07-10 01:18:13 +01:00
# include "GatewayHandler.hpp"
# include <boost/algorithm/string.hpp>
2016-08-10 17:07:41 +01:00
# include "DiscordAPI.hpp"
2016-08-04 17:39:48 +01:00
# include "Logger.hpp"
2016-08-05 02:27:46 +01:00
# include "data_structures/GuildMember.hpp"
2016-08-15 17:47:34 +01:00
# include "BotConfig.hpp"
2016-07-10 01:18:13 +01:00
2016-08-15 17:47:34 +01:00
GatewayHandler : : GatewayHandler ( BotConfig & c ) : config ( c ) {
2016-07-10 01:18:13 +01:00
last_seq = 0 ;
2016-08-10 17:07:41 +01:00
CommandHelper : : init ( ) ;
2016-07-10 01:18:13 +01:00
}
void GatewayHandler : : handle_data ( std : : string data , client & c , websocketpp : : connection_hdl & hdl ) {
json decoded = json : : parse ( data ) ;
int op = decoded [ " op " ] ;
switch ( op ) {
case 0 : // Event dispatch
on_dispatch ( decoded , c , hdl ) ;
break ;
case 10 : // Hello
on_hello ( decoded , c , hdl ) ;
break ;
case 11 :
2016-08-04 17:39:48 +01:00
Logger : : write ( " Heartbeat acknowledged " , Logger : : LogLevel : : Debug ) ;
2016-07-10 01:18:13 +01:00
break ;
}
}
2016-08-10 17:07:41 +01:00
void GatewayHandler : : send_heartbeat ( client * c , websocketpp : : connection_hdl hdl , int interval ) {
2016-07-12 23:43:23 +01:00
while ( true ) {
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( interval ) ) ;
2016-08-10 17:07:41 +01:00
if ( ! c ) {
Logger : : write ( " [send_heartbeat] Client pointer is null " , Logger : : LogLevel : : Severe ) ;
break ;
}
else if ( c - > stopped ( ) ) {
break ;
}
2016-07-12 23:43:23 +01:00
json heartbeat = {
{ " op " , 1 } ,
{ " d " , last_seq }
} ;
c - > send ( hdl , heartbeat . dump ( ) , websocketpp : : frame : : opcode : : text ) ;
2016-08-04 17:39:48 +01:00
Logger : : write ( " Sent heartbeat (seq: " + std : : to_string ( last_seq ) + " ) " , Logger : : LogLevel : : Debug ) ;
2016-07-12 23:43:23 +01:00
}
2016-07-10 01:18:13 +01:00
}
2016-08-10 17:07:41 +01:00
void GatewayHandler : : send_identify ( client & c , websocketpp : : connection_hdl & hdl ) {
json identify = {
{ " op " , 2 } ,
{ " d " , {
2016-08-15 17:47:34 +01:00
{ " token " , config . token } ,
2016-08-10 17:07:41 +01:00
{ " properties " , {
{ " $browser " , " Microsoft Windows 10 " } ,
{ " $device " , " TriviaBot-0.0 " } ,
{ " $referrer " , " " } ,
{ " $referring_domain " , " " }
} } ,
{ " compress " , false } ,
{ " large_threshold " , 250 } ,
{ " shard " , { 0 , 1 } }
} }
} ;
c . send ( hdl , identify . dump ( ) , websocketpp : : frame : : opcode : : text ) ;
Logger : : write ( " Sent identify payload " , Logger : : LogLevel : : Debug ) ;
}
void GatewayHandler : : send_request_guild_members ( client & c , websocketpp : : connection_hdl & hdl , std : : string guild_id ) {
json request_guild_members = {
{ " op " , 8 } ,
{ " d " , {
{ " guild_id " , guild_id } ,
{ " query " , " " } ,
{ " limit " , 0 }
} }
} ;
c . send ( hdl , request_guild_members . dump ( ) , websocketpp : : frame : : opcode : : text ) ;
Logger : : write ( " Requested guild members for " + guild_id , Logger : : LogLevel : : Debug ) ;
}
2016-07-10 01:18:13 +01:00
void GatewayHandler : : on_hello ( json decoded , client & c , websocketpp : : connection_hdl & hdl ) {
heartbeat_interval = decoded [ " d " ] [ " heartbeat_interval " ] ;
2016-08-04 17:39:48 +01:00
Logger : : write ( " Heartbeat interval: " + std : : to_string ( heartbeat_interval / 1000.0f ) + " seconds " , Logger : : LogLevel : : Debug ) ;
2016-07-10 01:18:13 +01:00
2016-08-10 17:07:41 +01:00
heartbeat_thread = std : : make_unique < boost : : thread > ( boost : : bind ( & GatewayHandler : : send_heartbeat , this , & c , hdl , heartbeat_interval ) ) ;
2016-07-10 01:18:13 +01:00
2016-08-10 17:07:41 +01:00
send_identify ( c , hdl ) ;
2016-07-10 01:18:13 +01:00
}
2016-08-14 17:46:29 +01:00
void GatewayHandler : : on_dispatch ( json decoded , client & c , websocketpp : : connection_hdl & hdl ) {
2016-07-10 01:18:13 +01:00
last_seq = decoded [ " s " ] ;
std : : string event_name = decoded [ " t " ] ;
json data = decoded [ " d " ] ;
if ( event_name = = " READY " ) {
2016-08-05 02:27:46 +01:00
on_event_ready ( data ) ;
2016-07-10 01:18:13 +01:00
}
else if ( event_name = = " GUILD_CREATE " ) {
2016-08-05 02:27:46 +01:00
on_event_guild_create ( data ) ;
}
else if ( event_name = = " GUILD_UPDATE " ) {
on_event_guild_update ( data ) ;
}
else if ( event_name = = " GUILD_DELETE " ) {
on_event_guild_delete ( data ) ;
}
else if ( event_name = = " GUILD_MEMBER_ADD " ) {
on_event_guild_member_add ( data ) ;
}
else if ( event_name = = " GUILD_MEMBER_UPDATE " ) {
on_event_guild_member_update ( data ) ;
}
else if ( event_name = = " GUILD_MEMBER_REMOVE " ) {
on_event_guild_member_remove ( data ) ;
}
else if ( event_name = = " GUILD_ROLE_CREATE " ) {
on_event_guild_role_create ( data ) ;
}
else if ( event_name = = " GUILD_ROLE_UPDATE " ) {
on_event_guild_role_update ( data ) ;
}
else if ( event_name = = " GUILD_ROLE_DELETE " ) {
on_event_guild_role_delete ( data ) ;
}
else if ( event_name = = " CHANNEL_CREATE " ) {
on_event_channel_create ( data ) ;
}
else if ( event_name = = " CHANNEL_UPDATE " ) {
on_event_channel_update ( data ) ;
}
else if ( event_name = = " CHANNEL_DELETE " ) {
on_event_channel_delete ( data ) ;
}
else if ( event_name = = " MESSAGE_CREATE " ) {
2016-08-14 17:46:29 +01:00
on_event_message_create ( data , c , hdl ) ;
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
else if ( event_name = = " PRESENCE_UPDATE " ) {
on_event_presence_update ( data ) ;
}
2016-08-05 02:27:46 +01:00
}
void GatewayHandler : : on_event_ready ( json data ) {
user_object . load_from_json ( data [ " user " ] ) ;
Logger : : write ( " Sign-on confirmed. (@ " + user_object . username + " # " + user_object . discriminator + " ) " , Logger : : LogLevel : : Info ) ;
}
2016-08-10 17:07:41 +01:00
void GatewayHandler : : on_event_presence_update ( json data ) {
std : : string user_id = data [ " user " ] [ " id " ] ;
auto it = users . find ( user_id ) ;
if ( it ! = users . end ( ) ) {
it - > second . status = data . value ( " status " , " offline " ) ;
if ( data [ " game " ] = = nullptr ) {
it - > second . game = " null " ;
}
else {
it - > second . game = data [ " game " ] . value ( " name " , " null " ) ;
}
}
else {
Logger : : write ( " Tried to add presence for user " + user_id + " who doesn't exist " , Logger : : LogLevel : : Warning ) ;
}
}
2016-08-05 02:27:46 +01:00
void GatewayHandler : : on_event_guild_create ( json data ) {
guilds [ data [ " id " ] ] = DiscordObjects : : Guild ( data ) ;
DiscordObjects : : Guild & guild = guilds [ data [ " id " ] ] ;
2016-08-10 17:07:41 +01:00
Logger : : write ( " Received info for guild " + guild . id + " , now in " + std : : to_string ( guilds . size ( ) ) + " guild(s) " , Logger : : LogLevel : : Info ) ;
2016-08-05 02:27:46 +01:00
2016-08-10 17:07:41 +01:00
int channels_added = 0 , roles_added = 0 , members_added = 0 , presences_added = 0 ;
2016-08-05 02:27:46 +01:00
for ( json channel : data [ " channels " ] ) {
std : : string channel_id = channel [ " id " ] ;
channel [ " guild_id " ] = guild . id ;
channels [ channel_id ] = DiscordObjects : : Channel ( channel ) ;
guilds [ guild . id ] . channels . push_back ( & channels [ channel_id ] ) ;
channels_added + + ;
}
for ( json role : data [ " roles " ] ) {
std : : string role_id = role [ " id " ] ;
roles [ role_id ] = DiscordObjects : : Role ( role ) ;
guilds [ guild . id ] . roles . push_back ( & roles [ role_id ] ) ;
roles_added + + ;
}
for ( json member : data [ " members " ] ) {
std : : string user_id = member [ " user " ] [ " id " ] ;
auto it = users . find ( user_id ) ;
if ( it = = users . end ( ) ) { // new user
users [ user_id ] = DiscordObjects : : User ( member [ " user " ] ) ;
}
users [ user_id ] . guilds . push_back ( guild . id ) ;
2016-08-10 17:07:41 +01:00
DiscordObjects : : GuildMember * guild_member = new DiscordObjects : : GuildMember ( member , & users [ user_id ] ) ;
2016-08-05 02:27:46 +01:00
for ( std : : string role_id : member [ " roles " ] ) {
2016-08-10 17:07:41 +01:00
guild_member - > roles . push_back ( & roles [ role_id ] ) ;
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
guilds [ guild . id ] . members . push_back ( guild_member ) ;
members_added + + ;
}
for ( json presence : data [ " presences " ] ) {
std : : string user_id = presence [ " user " ] [ " id " ] ;
auto it = users . find ( user_id ) ;
if ( it ! = users . end ( ) ) {
it - > second . status = presence . value ( " status " , " offline " ) ;
if ( presence [ " game " ] = = nullptr ) {
it - > second . game = " null " ;
} else {
it - > second . game = presence [ " game " ] . value ( " name " , " null " ) ;
}
presences_added + + ;
}
else {
Logger : : write ( " Tried to add presence for user " + user_id + " who doesn't exist " , Logger : : LogLevel : : Warning ) ;
}
2016-08-05 02:27:46 +01:00
}
if ( v8_instances . count ( guild . id ) = = 0 ) {
2016-08-15 17:47:34 +01:00
v8_instances [ guild . id ] = std : : make_unique < V8Instance > ( config , guild . id , & guilds , & channels , & users , & roles ) ;
2016-08-05 02:27:46 +01:00
Logger : : write ( " Created v8 instance for guild " + guild . id , Logger : : LogLevel : : Debug ) ;
}
2016-08-10 17:07:41 +01:00
Logger : : write ( " Loaded " + std : : to_string ( channels_added ) + " channels, " + std : : to_string ( roles_added ) + " roles and "
+ std : : to_string ( members_added ) + " members (with " + std : : to_string ( presences_added ) + " presences) to guild " + guild . id , Logger : : LogLevel : : Debug ) ;
2016-08-05 02:27:46 +01:00
}
void GatewayHandler : : on_event_guild_update ( json data ) {
std : : string guild_id = data [ " id " ] ;
guilds [ guild_id ] . load_from_json ( data ) ;
Logger : : write ( " Updated guild " + guild_id , Logger : : LogLevel : : Debug ) ;
}
void GatewayHandler : : on_event_guild_delete ( json data ) {
std : : string guild_id = data [ " id " ] ;
bool unavailable = data . value ( " unavailable " , false ) ;
if ( unavailable ) {
Logger : : write ( " Guild " + guild_id + " has become unavailable " , Logger : : LogLevel : : Info ) ;
guilds [ guild_id ] . unavailable = true ;
} else {
int channels_removed = 0 ;
for ( auto it = channels . cbegin ( ) ; it ! = channels . cend ( ) ; ) {
if ( it - > second . guild_id = = guild_id ) {
channels . erase ( it + + ) ;
channels_removed + + ;
} else {
+ + it ;
}
}
guilds . erase ( guilds . find ( guild_id ) ) ;
Logger : : write ( " Guild " + guild_id + " and " + std : : to_string ( channels_removed ) + " channels removed " , Logger : : LogLevel : : Info ) ;
}
}
void GatewayHandler : : on_event_guild_member_add ( json data ) {
std : : string guild_id = data [ " guild_id " ] ;
std : : string user_id = data [ " user " ] [ " id " ] ;
auto it = users . find ( user_id ) ;
if ( it = = users . end ( ) ) { // new user
users [ user_id ] = DiscordObjects : : User ( data [ " user " ] ) ;
}
users [ user_id ] . guilds . push_back ( guild_id ) ;
2016-08-10 17:07:41 +01:00
DiscordObjects : : GuildMember * guild_member = new DiscordObjects : : GuildMember ( data , & users [ user_id ] ) ;
2016-08-05 02:27:46 +01:00
for ( std : : string role_id : data [ " roles " ] ) {
2016-08-10 17:07:41 +01:00
guild_member - > roles . push_back ( & roles [ role_id ] ) ;
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
guilds [ guild_id ] . members . push_back ( guild_member ) ;
2016-08-05 02:27:46 +01:00
2016-08-10 17:07:41 +01:00
Logger : : write ( " Added new member " + guild_member - > user - > id + " to guild " + guild_id , Logger : : LogLevel : : Debug ) ;
2016-08-05 02:27:46 +01:00
}
void GatewayHandler : : on_event_guild_member_update ( json data ) {
std : : string user_id = data [ " user " ] [ " id " ] ;
DiscordObjects : : Guild & guild = guilds [ data [ " guild_id " ] ] ;
2016-08-10 17:07:41 +01:00
auto it = std : : find_if ( guild . members . begin ( ) , guild . members . end ( ) , [ user_id ] ( DiscordObjects : : GuildMember * member ) {
return user_id = = member - > user - > id ;
} ) ;
2016-08-05 02:27:46 +01:00
if ( it ! = guild . members . end ( ) ) {
bool nick_changed = false ;
2016-08-14 17:46:29 +01:00
int roles_change = 0 ;
2016-08-05 02:27:46 +01:00
2016-08-10 17:07:41 +01:00
DiscordObjects : : GuildMember * member = ( * it ) ;
2016-08-05 22:32:47 +01:00
std : : string nick = data . value ( " nick " , " null " ) ;
2016-08-10 17:07:41 +01:00
if ( member - > nick ! = nick ) {
member - > nick = nick ;
2016-08-05 02:27:46 +01:00
nick_changed = true ;
}
2016-08-10 17:07:41 +01:00
roles_change = member - > roles . size ( ) ;
member - > roles . clear ( ) ; // reset and re-fill, changing the differences is probably more expensive anyway.
2016-08-05 02:27:46 +01:00
for ( std : : string role_id : data [ " roles " ] ) {
2016-08-10 17:07:41 +01:00
member - > roles . push_back ( & roles [ role_id ] ) ;
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
roles_change = member - > roles . size ( ) - roles_change ;
2016-08-05 02:27:46 +01:00
std : : string debug_string = " Updated member " + user_id + " of guild " + guild . id ;
if ( nick_changed ) debug_string + = " . Nick changed to " + nick ;
if ( roles_change ! = 0 ) debug_string + = " . No. of roles changed by " + std : : to_string ( roles_change ) ;
debug_string + = " . " ;
Logger : : write ( debug_string , Logger : : LogLevel : : Debug ) ;
}
else {
Logger : : write ( " Tried to update member " + user_id + " (of guild " + guild . id + " ) who does not exist. " , Logger : : LogLevel : : Warning ) ;
}
}
void GatewayHandler : : on_event_guild_member_remove ( json data ) {
DiscordObjects : : Guild & guild = guilds [ data [ " guild_id " ] ] ;
std : : string user_id = data [ " user " ] [ " id " ] ;
2016-08-10 17:07:41 +01:00
auto it = std : : find_if ( guild . members . begin ( ) , guild . members . end ( ) , [ user_id ] ( DiscordObjects : : GuildMember * member ) {
return user_id = = member - > user - > id ;
} ) ;
if ( it ! = guild . members . end ( ) ) {
delete ( * it ) ;
2016-08-05 02:27:46 +01:00
guild . members . erase ( it ) ;
2016-07-10 01:18:13 +01:00
2016-08-10 17:07:41 +01:00
users [ user_id ] . guilds . erase ( std : : remove ( users [ user_id ] . guilds . begin ( ) , users [ user_id ] . guilds . end ( ) , guild . id ) ) ;
2016-08-05 02:27:46 +01:00
2016-08-10 17:07:41 +01:00
if ( users [ user_id ] . guilds . size ( ) = = 0 ) {
2016-08-05 02:27:46 +01:00
users . erase ( users . find ( user_id ) ) ;
Logger : : write ( " User " + user_id + " removed from guild " + guild . id + " and no longer visible, deleted. " , Logger : : LogLevel : : Debug ) ;
}
else {
Logger : : write ( " User " + user_id + " removed from guild " + guild . id , Logger : : LogLevel : : Debug ) ;
2016-07-10 01:18:13 +01:00
}
2016-08-05 02:27:46 +01:00
}
else {
2016-08-05 22:32:47 +01:00
Logger : : write ( " Tried to remove guild member " + user_id + " who doesn't exist " , Logger : : LogLevel : : Warning ) ;
2016-08-05 02:27:46 +01:00
}
}
void GatewayHandler : : on_event_guild_role_create ( json data ) {
std : : string role_id = data [ " role " ] [ " id " ] ;
std : : string guild_id = data [ " guild_id " ] ;
roles [ role_id ] = DiscordObjects : : Role ( data [ " role " ] ) ;
guilds [ guild_id ] . roles . push_back ( & roles [ role_id ] ) ;
Logger : : write ( " Created role " + role_id + " on guild " + guild_id , Logger : : LogLevel : : Debug ) ;
}
2016-08-03 22:04:05 +01:00
2016-08-05 02:27:46 +01:00
void GatewayHandler : : on_event_guild_role_update ( json data ) {
std : : string role_id = data [ " role " ] [ " id " ] ;
roles [ role_id ] . load_from_json ( data [ " role " ] ) ;
}
void GatewayHandler : : on_event_guild_role_delete ( json data ) {
std : : string role_id = data [ " role_id " ] ;
auto it = roles . find ( role_id ) ;
if ( it ! = roles . end ( ) ) {
DiscordObjects : : Guild & guild = guilds [ data [ " guild_id " ] ] ;
auto check_lambda = [ role_id ] ( const DiscordObjects : : Role * r ) {
return r - > id = = role_id ;
} ;
auto it2 = std : : find_if ( guild . roles . begin ( ) , guild . roles . end ( ) , check_lambda ) ;
if ( it2 ! = guild . roles . end ( ) ) {
guild . roles . erase ( it2 ) ;
}
else {
Logger : : write ( " Tried to delete role " + role_id + " from guild " + guild . id + " but it doesn't exist there " , Logger : : LogLevel : : Warning ) ;
2016-08-03 22:04:05 +01:00
}
2016-08-04 17:39:48 +01:00
2016-08-05 02:27:46 +01:00
roles . erase ( it ) ;
Logger : : write ( " Deleted role " + role_id + " (guild " + guild . id + " ). " , Logger : : LogLevel : : Debug ) ;
2016-07-10 01:18:13 +01:00
}
2016-08-05 02:27:46 +01:00
else {
Logger : : write ( " Tried to delete role " + role_id + " but it doesn't exist. " , Logger : : LogLevel : : Warning ) ;
}
}
void GatewayHandler : : on_event_channel_create ( json data ) {
std : : string channel_id = data [ " id " ] ;
std : : string guild_id = data [ " guild_id " ] ;
channels [ channel_id ] = DiscordObjects : : Channel ( data ) ;
Logger : : write ( " Added channel " + channel_id + " to channel list. Now " + std : : to_string ( channels . size ( ) ) + " channels stored " , Logger : : LogLevel : : Debug ) ;
guilds [ guild_id ] . channels . push_back ( & channels [ channel_id ] ) ;
Logger : : write ( " Added channel " + channel_id + " to guild " + guild_id + " 's list. Now " + std : : to_string ( guilds [ guild_id ] . channels . size ( ) ) + " channels stored " , Logger : : LogLevel : : Debug ) ;
}
void GatewayHandler : : on_event_channel_update ( json data ) {
std : : string channel_id = data [ " id " ] ;
auto it = channels . find ( channel_id ) ;
if ( it = = channels . end ( ) ) {
Logger : : write ( " Got channel update for channel " + channel_id + " that doesn't exist. Creating channel instead. " , Logger : : LogLevel : : Warning ) ;
on_event_channel_create ( data ) ;
} else {
channels [ channel_id ] . load_from_json ( data ) ;
Logger : : write ( " Updated channel " + channel_id , Logger : : LogLevel : : Debug ) ;
}
}
void GatewayHandler : : on_event_channel_delete ( json data ) {
std : : string channel_id = data [ " id " ] ;
std : : string guild_id = data [ " guild_id " ] ;
auto it = channels . find ( channel_id ) ;
if ( it = = channels . end ( ) ) {
Logger : : write ( " Tried to delete channel " + channel_id + " which doesn't exist " , Logger : : LogLevel : : Warning ) ;
}
else {
auto it2 = std : : find_if ( guilds [ guild_id ] . channels . begin ( ) , guilds [ guild_id ] . channels . begin ( ) , [ channel_id ] ( const DiscordObjects : : Channel * c ) {
return c - > id = = channel_id ;
} ) ;
guilds [ guild_id ] . channels . erase ( it2 ) ;
Logger : : write ( " Removed channel " + channel_id + " from guild " + guild_id + " 's list. Now "
+ std : : to_string ( guilds [ guild_id ] . channels . size ( ) ) + " channels stored " , Logger : : LogLevel : : Debug ) ;
channels . erase ( it ) ;
Logger : : write ( " Removed channel " + channel_id + " from channel list. Now " + std : : to_string ( channels . size ( ) ) + " channels stored. " , Logger : : LogLevel : : Debug ) ;
}
}
2016-07-10 01:18:13 +01:00
2016-08-14 17:46:29 +01:00
void GatewayHandler : : on_event_message_create ( json data , client & c , websocketpp : : connection_hdl & hdl ) {
2016-08-05 02:27:46 +01:00
std : : string message = data [ " content " ] ;
2016-07-10 01:18:13 +01:00
2016-08-05 22:32:47 +01:00
DiscordObjects : : Channel & channel = channels [ data [ " channel_id " ] ] ;
DiscordObjects : : Guild & guild = guilds [ channel . guild_id ] ;
2016-08-10 17:07:41 +01:00
DiscordObjects : : User & sender = users [ data [ " author " ] [ " id " ] ] ;
2016-08-05 22:32:47 +01:00
2016-08-10 17:07:41 +01:00
if ( sender . bot ) return ;
2016-07-10 19:17:35 +01:00
2016-08-05 02:27:46 +01:00
std : : vector < std : : string > words ;
boost : : split ( words , message , boost : : is_any_of ( " " ) ) ;
2016-08-10 17:07:41 +01:00
CommandHelper : : Command custom_command ;
2016-08-05 02:27:46 +01:00
if ( words [ 0 ] = = " `trivia " | | words [ 0 ] = = " `t " ) {
int questions = 10 ;
int delay = 8 ;
if ( words . size ( ) > 3 ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :exclamation: Invalid arguments! " , config . token , config . cert_location ) ;
2016-08-05 02:27:46 +01:00
return ;
}
else if ( words . size ( ) > 1 ) {
if ( words [ 1 ] = = " help " | | words [ 1 ] = = " h " ) {
std : : string help = " **Base command \\ `t[rivia]**. Arguments: \n " ;
help + = " \\ `trivia **{x}** **{y}**: Makes the game last **x** number of questions, optionally sets the time interval between hints to **y** seconds \n " ;
help + = " \\ `trivia **stop**: stops the ongoing game. \n " ;
help + = " \\ `trivia **help**: prints this message \n " ;
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , help , config . token , config . cert_location ) ;
2016-07-10 19:17:35 +01:00
return ;
}
2016-08-05 02:27:46 +01:00
else if ( words [ 1 ] = = " stop " | | words [ 1 ] = = " s " ) {
if ( games . find ( channel . id ) ! = games . end ( ) ) {
delete_game ( channel . id ) ;
2016-07-10 19:17:35 +01:00
}
2016-08-14 17:46:29 +01:00
else {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :warning: Couldn't find an ongoing trivia game for this channel. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
}
return ;
2016-08-05 02:27:46 +01:00
}
else {
try {
questions = std : : stoi ( words [ 1 ] ) ;
if ( words . size ( ) = = 3 ) {
delay = std : : stoi ( words [ 2 ] ) ;
2016-07-10 19:17:35 +01:00
}
}
2016-08-05 02:27:46 +01:00
catch ( std : : invalid_argument e ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :exclamation: Invalid arguments! " , config . token , config . cert_location ) ;
2016-08-05 02:27:46 +01:00
return ;
2016-07-10 19:17:35 +01:00
}
2016-07-10 01:18:13 +01:00
}
2016-08-05 02:27:46 +01:00
}
2016-07-10 01:18:13 +01:00
2016-08-15 17:47:34 +01:00
games [ channel . id ] = std : : make_unique < TriviaGame > ( config , this , channel . id , questions , delay ) ;
2016-08-05 02:27:46 +01:00
games [ channel . id ] - > start ( ) ;
}
else if ( words [ 0 ] = = " `guilds " ) {
2016-08-14 17:46:29 +01:00
std : : string m = " **Guild List:** \n " ;
2016-08-05 02:27:46 +01:00
for ( auto & gu : guilds ) {
2016-08-14 17:46:29 +01:00
m + = " :small_orange_diamond: " + gu . second . name + " ( " + gu . second . id + " ) Channels: " + std : : to_string ( gu . second . channels . size ( ) ) + " \n " ;
2016-08-05 02:27:46 +01:00
}
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , m , config . token , config . cert_location ) ;
2016-08-05 02:27:46 +01:00
}
else if ( words [ 0 ] = = " `info " ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :information_source: **trivia-bot** by Jack. <http://github.com/jackb-p/TriviaDiscord> " , config . token , config . cert_location ) ;
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
else if ( words [ 0 ] = = " ~js " & & words . size ( ) > 1 ) {
DiscordObjects : : GuildMember * member = * std : : find_if ( guild . members . begin ( ) , guild . members . end ( ) , [ sender ] ( DiscordObjects : : GuildMember * m ) {
return sender . id = = m - > user - > id ;
} ) ;
2016-08-19 17:29:56 +01:00
BotConfig & conf = config ;
bool disallowed = std : : find_if ( member - > roles . begin ( ) , member - > roles . end ( ) , [ conf ] ( DiscordObjects : : Role * r ) - > bool {
return conf . createjs_roles . count ( r - > name ) ;
} ) = = member - > roles . end ( ) ; // checks if the user has the required roles
if ( disallowed ) {
DiscordAPI : : send_message ( channel . id , " :warning: You do not have permission to use this command. " , config . token , config . cert_location ) ;
return ;
}
2016-08-05 02:27:46 +01:00
std : : string js = message . substr ( 4 ) ;
auto it = v8_instances . find ( channel . guild_id ) ;
if ( it ! = v8_instances . end ( ) & & js . length ( ) > 0 ) {
2016-08-10 17:07:41 +01:00
it - > second - > exec_js ( js , & channel , member ) ;
2016-08-05 02:27:46 +01:00
}
}
2016-08-10 17:07:41 +01:00
else if ( words [ 0 ] = = " ~createjs " & & words . size ( ) > 1 ) {
2016-08-14 17:46:29 +01:00
auto & member = * std : : find_if ( guild . members . begin ( ) , guild . members . end ( ) , [ sender ] ( DiscordObjects : : GuildMember * m ) { return sender . id = = m - > user - > id ; } ) ;
2016-08-15 17:47:34 +01:00
BotConfig & conf = config ;
bool disallowed = std : : find_if ( member - > roles . begin ( ) , member - > roles . end ( ) , [ conf ] ( DiscordObjects : : Role * r ) - > bool {
return conf . createjs_roles . count ( r - > name ) ;
2016-08-14 17:46:29 +01:00
} ) = = member - > roles . end ( ) ; // checks if the user has the required roles
2016-08-15 17:47:34 +01:00
if ( disallowed ) {
DiscordAPI : : send_message ( channel . id , " :warning: You do not have permission to use this command. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
}
2016-08-05 02:27:46 +01:00
std : : string args = message . substr ( 10 ) ;
size_t seperator_loc = args . find ( " | " ) ;
if ( seperator_loc ! = std : : string : : npos ) {
std : : string command_name = args . substr ( 0 , seperator_loc ) ;
std : : string script = args . substr ( seperator_loc + 1 ) ;
2016-08-10 17:07:41 +01:00
int result = CommandHelper : : insert_command ( channel . guild_id , command_name , script ) ;
2016-08-05 02:27:46 +01:00
switch ( result ) {
case 0 :
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :warning: Error! " , config . token , config . cert_location ) ; break ;
2016-08-05 02:27:46 +01:00
case 1 :
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :new: Command ` " + command_name + " ` successfully created. " , config . token , config . cert_location ) ; break ;
2016-08-05 02:27:46 +01:00
case 2 :
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :arrow_heading_up: Command ` " + command_name + " ` successfully updated. " , config . token , config . cert_location ) ; break ;
2016-07-10 01:18:13 +01:00
}
}
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
else if ( words [ 0 ] = = " `shutdown " & & sender . id = = " 82232146579689472 " ) { // it me
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :zzz: Goodbye! " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
for ( auto & game : games ) {
delete_game ( game . first ) ;
}
v8_instances . clear ( ) ;
c . close ( hdl , websocketpp : : close : : status : : going_away , " " ) ;
2016-08-05 02:27:46 +01:00
}
else if ( words [ 0 ] = = " `debug " ) {
if ( words [ 1 ] = = " channel " & & words . size ( ) = = 3 ) {
auto it = channels . find ( words [ 2 ] ) ;
2016-08-14 17:46:29 +01:00
if ( it = = channels . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised channel. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
2016-08-05 02:27:46 +01:00
}
2016-08-14 17:46:29 +01:00
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , it - > second . to_debug_string ( ) , config . token , config . cert_location ) ;
2016-07-28 17:15:32 +01:00
}
2016-08-05 02:27:46 +01:00
else if ( words [ 1 ] = = " guild " & & words . size ( ) = = 3 ) {
auto it = guilds . find ( words [ 2 ] ) ;
2016-08-14 17:46:29 +01:00
if ( it = = guilds . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised guild. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
2016-08-03 22:04:05 +01:00
}
2016-08-14 17:46:29 +01:00
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , it - > second . to_debug_string ( ) , config . token , config . cert_location ) ;
2016-08-03 22:04:05 +01:00
}
2016-08-05 02:27:46 +01:00
else if ( words [ 1 ] = = " member " & & words . size ( ) = = 4 ) {
auto it = guilds . find ( words [ 2 ] ) ;
2016-08-14 17:46:29 +01:00
if ( it = = guilds . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised guild. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
}
std : : string user_id = words [ 3 ] ;
auto it2 = std : : find_if ( it - > second . members . begin ( ) , it - > second . members . end ( ) , [ user_id ] ( DiscordObjects : : GuildMember * member ) {
return user_id = = member - > user - > id ;
} ) ;
if ( it2 = = it - > second . members . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised user. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
2016-08-05 02:27:46 +01:00
}
2016-08-14 17:46:29 +01:00
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , ( * it2 ) - > to_debug_string ( ) , config . token , config . cert_location ) ;
2016-08-04 02:41:02 +01:00
}
2016-08-05 02:27:46 +01:00
else if ( words [ 1 ] = = " role " & & words . size ( ) = = 3 ) {
auto it = roles . find ( words [ 2 ] ) ;
2016-08-14 17:46:29 +01:00
if ( it = = roles . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised role. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
2016-08-05 02:27:46 +01:00
}
2016-08-14 17:46:29 +01:00
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , it - > second . to_debug_string ( ) , config . token , config . cert_location ) ;
2016-08-04 02:41:02 +01:00
}
2016-08-05 02:27:46 +01:00
else if ( words [ 1 ] = = " role " & & words . size ( ) = = 4 ) {
std : : string role_name = words [ 3 ] ;
auto it = guilds . find ( words [ 2 ] ) ;
2016-08-14 17:46:29 +01:00
if ( it = = guilds . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised guild. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
}
auto it2 = std : : find_if ( it - > second . roles . begin ( ) , it - > second . roles . end ( ) , [ role_name ] ( DiscordObjects : : Role * r ) {
return role_name = = r - > name ;
} ) ;
if ( it2 = = it - > second . roles . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unrecognised role. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
2016-08-05 02:27:46 +01:00
}
2016-08-14 17:46:29 +01:00
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , ( * it2 ) - > to_debug_string ( ) , config . token , config . cert_location ) ;
2016-08-05 02:27:46 +01:00
}
else {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :question: Unknown parameters. " , config . token , config . cert_location ) ;
2016-08-04 02:41:02 +01:00
}
2016-08-05 02:27:46 +01:00
}
2016-08-10 17:07:41 +01:00
else if ( CommandHelper : : get_command ( channel . guild_id , words [ 0 ] , custom_command ) ) {
2016-08-05 22:32:47 +01:00
std : : string args = " " ;
if ( message . length ( ) > ( words [ 0 ] . length ( ) + 1 ) ) {
args = message . substr ( words [ 0 ] . length ( ) + 1 ) ;
}
2016-08-14 17:46:29 +01:00
if ( custom_command . script . length ( ) = = 0 ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :warning: Script has 0 length. " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
}
2016-08-05 02:27:46 +01:00
auto it = v8_instances . find ( channel . guild_id ) ;
2016-08-14 17:46:29 +01:00
if ( it = = v8_instances . end ( ) ) {
2016-08-15 17:47:34 +01:00
DiscordAPI : : send_message ( channel . id , " :warning: No V8 instance exists for this server - it's our fault not yours! " , config . token , config . cert_location ) ;
2016-08-14 17:46:29 +01:00
return ;
2016-07-10 19:17:35 +01:00
}
2016-08-14 17:46:29 +01:00
DiscordObjects : : GuildMember * member = * std : : find_if ( guild . members . begin ( ) , guild . members . end ( ) , [ sender ] ( DiscordObjects : : GuildMember * m ) {
return sender . id = = m - > user - > id ;
} ) ;
it - > second - > exec_js ( custom_command . script , & channel , member , args ) ;
2016-07-10 01:18:13 +01:00
}
2016-08-14 17:46:29 +01:00
else if ( games . find ( channel . id ) ! = games . end ( ) ) { // message received in channel with ongoing trivia game
2016-08-10 17:07:41 +01:00
games [ channel . id ] - > handle_answer ( message , sender ) ;
2016-08-05 02:27:46 +01:00
}
2016-07-10 01:18:13 +01:00
}
void GatewayHandler : : delete_game ( std : : string channel_id ) {
auto it = games . find ( channel_id ) ;
if ( it ! = games . end ( ) ) {
2016-07-10 19:17:35 +01:00
it - > second - > interrupt ( ) ;
2016-07-10 01:18:13 +01:00
// remove from map
games . erase ( it ) ;
} else {
2016-08-04 17:39:48 +01:00
Logger : : write ( " Tried to delete a game that didn't exist (channel_id: " + channel_id + " ) " , Logger : : LogLevel : : Warning ) ;
2016-07-10 01:18:13 +01:00
}
}