diff --git a/.gitignore b/.gitignore index e155f43..5861706 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,8 @@ /TriviaBot/data_management/questions /TriviaBot/bot/db/trivia.db +# Config file +config.json + # Compiled sqlite file sqlite3.obj \ No newline at end of file diff --git a/TriviaBot/bot/BotConfig.cpp b/TriviaBot/bot/BotConfig.cpp new file mode 100644 index 0000000..ed55ad5 --- /dev/null +++ b/TriviaBot/bot/BotConfig.cpp @@ -0,0 +1,60 @@ +#include "BotConfig.hpp" + +#include +#include +#include + +#include "json/json.hpp" + +#include "Logger.hpp" + +using json = nlohmann::json; + +BotConfig::BotConfig() { + is_new_config = false; + std::stringstream ss; + + std::ifstream config_file("config.json"); + if(!config_file) { + config_file.close(); + create_new_file(); + return; + } + + ss << config_file.rdbuf(); + config_file.close(); + std::string config = ss.str(); + load_from_json(config); +} + +void BotConfig::load_from_json(std::string data) { + json parsed = json::parse(data); + + token = parsed.value("bot_token", ""); + owner_id = parsed.value("owner_id", ""); + cert_location = parsed.value("api_cert_file", "bot/http/DiscordCA.crt"); + + createjs_roles = parsed["v8"].value("createjs_allowed_roles", std::unordered_set { "Admin", "Coder" }); + + Logger::write("config.json file loaded", Logger::LogLevel::Info); +} + +void BotConfig::create_new_file() { + std::string config = json { + { "bot_token", "" }, + { "owner_id", "" }, + { "api_cert_file", "bot/http/DiscordCA.crt" }, + { "v8", { + { "createjs_allowed_roles", { + "Admin", "Coder", "Bot Commander" + } } + } } + }.dump(4); + + std::ofstream config_file("config.json"); + config_file << config; + config_file.close(); + + Logger::write("Created new config.json file", Logger::LogLevel::Info); + is_new_config = true; +} \ No newline at end of file diff --git a/TriviaBot/bot/BotConfig.hpp b/TriviaBot/bot/BotConfig.hpp new file mode 100644 index 0000000..23dc842 --- /dev/null +++ b/TriviaBot/bot/BotConfig.hpp @@ -0,0 +1,23 @@ +#ifndef BOT_BOTCONFIG +#define BOT_BOTCONFIG + +#include +#include + +class BotConfig { +public: + BotConfig(); + + bool is_new_config; + + std::string token; + std::string owner_id; + std::string cert_location; + std::unordered_set createjs_roles; + +private: + void load_from_json(std::string data); + void create_new_file(); +}; + +#endif diff --git a/TriviaBot/bot/ClientConnection.cpp b/TriviaBot/bot/ClientConnection.cpp index 94f35bb..b148d4b 100644 --- a/TriviaBot/bot/ClientConnection.cpp +++ b/TriviaBot/bot/ClientConnection.cpp @@ -3,60 +3,58 @@ #include #include -#include "GatewayHandler.hpp" #include "Logger.hpp" +#include "BotConfig.hpp" -ClientConnection::ClientConnection() { +ClientConnection::ClientConnection(BotConfig &c) : config(c), gh(config) { // Reset the log channels - c.clear_access_channels(websocketpp::log::alevel::all); + cli.clear_access_channels(websocketpp::log::alevel::all); // Only want application logging, logging from the initial connection stages or any error logging - c.set_access_channels(websocketpp::log::alevel::app | websocketpp::log::alevel::connect); - c.set_error_channels(websocketpp::log::elevel::all); + cli.set_access_channels(websocketpp::log::alevel::app | websocketpp::log::alevel::connect); + cli.set_error_channels(websocketpp::log::elevel::all); // Initialize ASIO - c.init_asio(); + cli.init_asio(); // Bind handlers - c.set_socket_init_handler(bind( + cli.set_socket_init_handler(bind( &ClientConnection::on_socket_init, this, websocketpp::lib::placeholders::_1 )); - c.set_tls_init_handler(bind( + cli.set_tls_init_handler(bind( &ClientConnection::on_tls_init, this, websocketpp::lib::placeholders::_1 )); - c.set_message_handler(bind( + cli.set_message_handler(bind( &ClientConnection::on_message, this, websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2 )); - c.set_open_handler(bind( + cli.set_open_handler(bind( &ClientConnection::on_open, this, websocketpp::lib::placeholders::_1 )); - c.set_close_handler(bind( + cli.set_close_handler(bind( &ClientConnection::on_close, this, websocketpp::lib::placeholders::_1 )); - c.set_fail_handler(bind( + cli.set_fail_handler(bind( &ClientConnection::on_fail, this, websocketpp::lib::placeholders::_1 )); - - gh = std::make_unique(); } // Open a connection to the URI provided void ClientConnection::start(std::string uri) { websocketpp::lib::error_code ec; - client::connection_ptr con = c.get_connection(uri, ec); + client::connection_ptr con = cli.get_connection(uri, ec); if (ec) { // failed to create connection Logger::write("Failed to create connection: " + ec.message(), Logger::LogLevel::Severe); @@ -64,8 +62,8 @@ void ClientConnection::start(std::string uri) { } // Open the connection - c.connect(con); - c.run(); + cli.connect(con); + cli.run(); Logger::write("Finished running", Logger::LogLevel::Debug); } @@ -91,7 +89,7 @@ context_ptr ClientConnection::on_tls_init(websocketpp::connection_hdl) { } void ClientConnection::on_fail(websocketpp::connection_hdl hdl) { - client::connection_ptr con = c.get_con_from_hdl(hdl); + client::connection_ptr con = cli.get_con_from_hdl(hdl); // Print as much information as possible Logger::write("Fail handler: \n" + @@ -117,10 +115,10 @@ void ClientConnection::on_message(websocketpp::connection_hdl hdl, message_ptr m // Pass the message to the gateway handler - gh->handle_data(message->get_payload(), c, hdl); + gh.handle_data(message->get_payload(), cli, hdl); } void ClientConnection::on_close(websocketpp::connection_hdl) { Logger::write("Connection closed", Logger::LogLevel::Info); - c.stop(); + cli.stop(); } \ No newline at end of file diff --git a/TriviaBot/bot/ClientConnection.hpp b/TriviaBot/bot/ClientConnection.hpp index 546ae7f..67faa80 100644 --- a/TriviaBot/bot/ClientConnection.hpp +++ b/TriviaBot/bot/ClientConnection.hpp @@ -5,6 +5,8 @@ #include #include "json/json.hpp" +#include "GatewayHandler.hpp" + typedef websocketpp::client client; using websocketpp::lib::bind; @@ -14,15 +16,20 @@ typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; typedef websocketpp::lib::shared_ptr context_ptr; typedef client::connection_ptr connection_ptr; -#include "GatewayHandler.hpp" +class BotConfig; class ClientConnection { public: - ClientConnection(); + ClientConnection(BotConfig &c); // Open a connection to the URI provided void start(std::string uri); +private: + client cli; + BotConfig &config; + GatewayHandler gh; + // Event handlers void on_socket_init(websocketpp::connection_hdl); context_ptr on_tls_init(websocketpp::connection_hdl); @@ -30,10 +37,6 @@ public: void on_open(websocketpp::connection_hdl hdl); void on_message(websocketpp::connection_hdl hdl, message_ptr message); void on_close(websocketpp::connection_hdl); - -private: - client c; - std::unique_ptr gh; }; #endif \ No newline at end of file diff --git a/TriviaBot/bot/DiscordAPI.cpp b/TriviaBot/bot/DiscordAPI.cpp index 3bb582a..6bbbfc7 100644 --- a/TriviaBot/bot/DiscordAPI.cpp +++ b/TriviaBot/bot/DiscordAPI.cpp @@ -4,7 +4,7 @@ #include #include -#include "http/HTTPHelper.hpp" +#include "http/HTTP.hpp" #include "Logger.hpp" using namespace std::chrono_literals; @@ -16,7 +16,7 @@ namespace DiscordAPI { const std::string json_mime_type = "application/json"; - void send_message(std::string channel_id, std::string message) { + void send_message(std::string channel_id, std::string message, std::string token, std::string ca_location) { if (message == "") { Logger::write("[API] [send_message] Tried to send empty message", Logger::LogLevel::Warning); return; @@ -31,9 +31,9 @@ namespace DiscordAPI { std::string first = message.substr(0, 2000); std::string second = message.substr(2000); - send_message(channel_id, first); + send_message(channel_id, first, token, ca_location); std::this_thread::sleep_for(50ms); - send_message(channel_id, second); + send_message(channel_id, second, token, ca_location); return; } @@ -44,14 +44,14 @@ namespace DiscordAPI { std::string response; long response_code = 0; - response = HTTP::post_request(url, json_mime_type, data.dump(), &response_code); + response = HTTP::post_request(url, json_mime_type, data.dump(), &response_code, token, ca_location); int retries = 0; while (response_code != 200 && retries < 2) { Logger::write("[API] [send_message] Got non-200 response code, retrying", Logger::LogLevel::Warning); std::this_thread::sleep_for(100ms); // try 3 times. usually enough to prevent 502 bad gateway issues - response = HTTP::post_request(url, json_mime_type, data.dump(), &response_code); + response = HTTP::post_request(url, json_mime_type, data.dump(), &response_code, token, ca_location); retries++; } @@ -60,17 +60,17 @@ namespace DiscordAPI { } } - json get_gateway() { + json get_gateway(std::string ca_location) { std::string response; long response_code; - response = HTTP::get_request(gateway_url, &response_code); + response = HTTP::get_request(gateway_url, &response_code, "", ca_location); int retries = 0; while (response_code != 200 && retries < 4) { Logger::write("[API] [get_gateway] Got non-200 response code, retrying", Logger::LogLevel::Warning); std::this_thread::sleep_for(100ms); // try 3 times. usually enough to prevent 502 bad gateway issues - response = HTTP::get_request(gateway_url, &response_code); + response = HTTP::get_request(gateway_url, &response_code, "", ca_location); retries++; } diff --git a/TriviaBot/bot/DiscordAPI.hpp b/TriviaBot/bot/DiscordAPI.hpp index 2c389d7..a5005fe 100644 --- a/TriviaBot/bot/DiscordAPI.hpp +++ b/TriviaBot/bot/DiscordAPI.hpp @@ -7,11 +7,11 @@ using json = nlohmann::json; -class HTTPHelper; +class BotConfig; namespace DiscordAPI { - json get_gateway(); - void send_message(std::string channel_id, std::string message); + json get_gateway(std::string ca_location); + void send_message(std::string channel_id, std::string message, std::string token, std::string ca_location); } #endif \ No newline at end of file diff --git a/TriviaBot/bot/GatewayHandler.cpp b/TriviaBot/bot/GatewayHandler.cpp index 26c79d1..9a1d0e4 100644 --- a/TriviaBot/bot/GatewayHandler.cpp +++ b/TriviaBot/bot/GatewayHandler.cpp @@ -5,10 +5,9 @@ #include "DiscordAPI.hpp" #include "Logger.hpp" #include "data_structures/GuildMember.hpp" +#include "BotConfig.hpp" -extern std::string bot_token; - -GatewayHandler::GatewayHandler() { +GatewayHandler::GatewayHandler(BotConfig &c) : config(c) { last_seq = 0; CommandHelper::init(); @@ -59,7 +58,7 @@ void GatewayHandler::send_identify(client &c, websocketpp::connection_hdl &hdl) json identify = { { "op", 2 }, { "d", { - { "token", bot_token }, + { "token", config.token }, { "properties",{ { "$browser", "Microsoft Windows 10" }, { "$device", "TriviaBot-0.0" }, @@ -239,7 +238,7 @@ void GatewayHandler::on_event_guild_create(json data) { } if (v8_instances.count(guild.id) == 0) { - v8_instances[guild.id] = std::make_unique(guild.id, &guilds, &channels, &users, &roles); + v8_instances[guild.id] = std::make_unique(config, guild.id, &guilds, &channels, &users, &roles); Logger::write("Created v8 instance for guild " + guild.id, Logger::LogLevel::Debug); } @@ -465,7 +464,7 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: int delay = 8; if (words.size() > 3) { - DiscordAPI::send_message(channel.id, ":exclamation: Invalid arguments!"); + DiscordAPI::send_message(channel.id, ":exclamation: Invalid arguments!", config.token, config.cert_location); return; } else if (words.size() > 1) { @@ -475,7 +474,7 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: help += "\\`trivia **stop**: stops the ongoing game.\n"; help += "\\`trivia **help**: prints this message\n"; - DiscordAPI::send_message(channel.id, help); + DiscordAPI::send_message(channel.id, help, config.token, config.cert_location); return; } else if (words[1] == "stop" || words[1] == "s") { @@ -483,7 +482,7 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: delete_game(channel.id); } else { - DiscordAPI::send_message(channel.id, ":warning: Couldn't find an ongoing trivia game for this channel."); + DiscordAPI::send_message(channel.id, ":warning: Couldn't find an ongoing trivia game for this channel.", config.token, config.cert_location); } return; } @@ -495,13 +494,13 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: } } catch (std::invalid_argument e) { - DiscordAPI::send_message(channel.id, ":exclamation: Invalid arguments!"); + DiscordAPI::send_message(channel.id, ":exclamation: Invalid arguments!", config.token, config.cert_location); return; } } } - games[channel.id] = std::make_unique(this, channel.id, questions, delay); + games[channel.id] = std::make_unique(config, this, channel.id, questions, delay); games[channel.id]->start(); } else if (words[0] == "`guilds") { @@ -509,10 +508,10 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: for (auto &gu : guilds) { m += ":small_orange_diamond: " + gu.second.name + " (" + gu.second.id + ") Channels: " + std::to_string(gu.second.channels.size()) + "\n"; } - DiscordAPI::send_message(channel.id, m); + DiscordAPI::send_message(channel.id, m, config.token, config.cert_location); } else if (words[0] == "`info") { - DiscordAPI::send_message(channel.id, ":information_source: **trivia-bot** by Jack. "); + DiscordAPI::send_message(channel.id, ":information_source: **trivia-bot** by Jack. ", config.token, config.cert_location); } else if (words[0] == "~js" && words.size() > 1) { DiscordObjects::GuildMember *member = *std::find_if(guild.members.begin(), guild.members.end(), [sender](DiscordObjects::GuildMember *m) { @@ -526,12 +525,13 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: } else if (words[0] == "~createjs" && words.size() > 1) { auto &member = *std::find_if(guild.members.begin(), guild.members.end(), [sender](DiscordObjects::GuildMember *m) { return sender.id == m->user->id; }); - bool allowed = std::find_if(member->roles.begin(), member->roles.end(), [](DiscordObjects::Role *r) { - return r->name == "Admin" || r->name == "Moderator" || r->name == "Coder"; // TODO: customisation here + 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 (!allowed) { - DiscordAPI::send_message(channel.id, ":warning: You do not have permission to use this command."); + if (disallowed) { + DiscordAPI::send_message(channel.id, ":warning: You do not have permission to use this command.", config.token, config.cert_location); return; } @@ -543,16 +543,16 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: int result = CommandHelper::insert_command(channel.guild_id, command_name, script); switch (result) { case 0: - DiscordAPI::send_message(channel.id, ":warning: Error!"); break; + DiscordAPI::send_message(channel.id, ":warning: Error!", config.token, config.cert_location); break; case 1: - DiscordAPI::send_message(channel.id, ":new: Command `" + command_name + "` successfully created."); break; + DiscordAPI::send_message(channel.id, ":new: Command `" + command_name + "` successfully created.", config.token, config.cert_location); break; case 2: - DiscordAPI::send_message(channel.id, ":arrow_heading_up: Command `" + command_name + "` successfully updated."); break; + DiscordAPI::send_message(channel.id, ":arrow_heading_up: Command `" + command_name + "` successfully updated.", config.token, config.cert_location); break; } } } else if (words[0] == "`shutdown" && sender.id == "82232146579689472") { // it me - DiscordAPI::send_message(channel.id, ":zzz: Goodbye!"); + DiscordAPI::send_message(channel.id, ":zzz: Goodbye!", config.token, config.cert_location); for (auto &game : games) { delete_game(game.first); } @@ -563,25 +563,25 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: if (words[1] == "channel" && words.size() == 3) { auto it = channels.find(words[2]); if (it == channels.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised channel."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised channel.", config.token, config.cert_location); return; } - DiscordAPI::send_message(channel.id, it->second.to_debug_string()); + DiscordAPI::send_message(channel.id, it->second.to_debug_string(), config.token, config.cert_location); } else if (words[1] == "guild" && words.size() == 3) { auto it = guilds.find(words[2]); if (it == guilds.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised guild."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised guild.", config.token, config.cert_location); return; } - DiscordAPI::send_message(channel.id, it->second.to_debug_string()); + DiscordAPI::send_message(channel.id, it->second.to_debug_string(), config.token, config.cert_location); } else if (words[1] == "member" && words.size() == 4) { auto it = guilds.find(words[2]); if (it == guilds.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised guild."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised guild.", config.token, config.cert_location); return; } @@ -590,27 +590,27 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: return user_id == member->user->id; }); if (it2 == it->second.members.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised user."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised user.", config.token, config.cert_location); return; } - DiscordAPI::send_message(channel.id, (*it2)->to_debug_string()); + DiscordAPI::send_message(channel.id, (*it2)->to_debug_string(), config.token, config.cert_location); } else if (words[1] == "role" && words.size() == 3) { auto it = roles.find(words[2]); if (it == roles.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised role."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised role.", config.token, config.cert_location); return; } - DiscordAPI::send_message(channel.id, it->second.to_debug_string()); + DiscordAPI::send_message(channel.id, it->second.to_debug_string(), config.token, config.cert_location); } else if (words[1] == "role" && words.size() == 4) { std::string role_name = words[3]; auto it = guilds.find(words[2]); if (it == guilds.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised guild."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised guild.", config.token, config.cert_location); return; } @@ -618,14 +618,14 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: return role_name == r->name; }); if (it2 == it->second.roles.end()) { - DiscordAPI::send_message(channel.id, ":question: Unrecognised role."); + DiscordAPI::send_message(channel.id, ":question: Unrecognised role.", config.token, config.cert_location); return; } - DiscordAPI::send_message(channel.id, (*it2)->to_debug_string()); + DiscordAPI::send_message(channel.id, (*it2)->to_debug_string(), config.token, config.cert_location); } else { - DiscordAPI::send_message(channel.id, ":question: Unknown parameters."); + DiscordAPI::send_message(channel.id, ":question: Unknown parameters.", config.token, config.cert_location); } } else if (CommandHelper::get_command(channel.guild_id, words[0], custom_command)) { @@ -635,13 +635,13 @@ void GatewayHandler::on_event_message_create(json data, client &c, websocketpp:: } if (custom_command.script.length() == 0) { - DiscordAPI::send_message(channel.id, ":warning: Script has 0 length."); + DiscordAPI::send_message(channel.id, ":warning: Script has 0 length.", config.token, config.cert_location); return; } auto it = v8_instances.find(channel.guild_id); if (it == v8_instances.end()) { - DiscordAPI::send_message(channel.id, ":warning: No V8 instance exists for this server - it's our fault not yours!"); + DiscordAPI::send_message(channel.id, ":warning: No V8 instance exists for this server - it's our fault not yours!", config.token, config.cert_location); return; } diff --git a/TriviaBot/bot/GatewayHandler.hpp b/TriviaBot/bot/GatewayHandler.hpp index 4146428..3be7ca3 100644 --- a/TriviaBot/bot/GatewayHandler.hpp +++ b/TriviaBot/bot/GatewayHandler.hpp @@ -37,17 +37,19 @@ using json = nlohmann::json; *****************************************************************************************************************************/ class TriviaGame; -class APIHelper; +class BotConfig; class GatewayHandler { public: - GatewayHandler(); + GatewayHandler(BotConfig &c); void handle_data(std::string data, client &c, websocketpp::connection_hdl &hdl); void delete_game(std::string channel_id); private: + BotConfig &config; + int last_seq; int heartbeat_interval; diff --git a/TriviaBot/bot/TriviaBot.cpp b/TriviaBot/bot/TriviaBot.cpp index 7090e45..5e57aca 100644 --- a/TriviaBot/bot/TriviaBot.cpp +++ b/TriviaBot/bot/TriviaBot.cpp @@ -8,10 +8,15 @@ #include "ClientConnection.hpp" #include "Logger.hpp" #include "DiscordAPI.hpp" - -std::string bot_token; +#include "BotConfig.hpp" int main(int argc, char *argv[]) { + BotConfig config; + if (config.is_new_config) { + Logger::write("Since the config.json file is newly generated, the program will exit now to allow you to edit it.", Logger::LogLevel::Info); + return 0; + } + curl_global_init(CURL_GLOBAL_DEFAULT); v8::V8::InitializeICUDefaultLocation(argv[0]); @@ -22,16 +27,8 @@ int main(int argc, char *argv[]) { Logger::write("Initialised V8 and curl", Logger::LogLevel::Debug); - if (argc == 2) { - bot_token = argv[1]; - } - else { - std::cout << "Please enter your bot token: " << std::endl; - std::cin >> bot_token; - } - std::string args = "/?v=5&encoding=json"; - std::string url = DiscordAPI::get_gateway().value("url", "wss://gateway.discord.gg"); + std::string url = DiscordAPI::get_gateway(config.cert_location).value("url", "wss://gateway.discord.gg"); bool retry = true; int exit_code = 0; @@ -39,7 +36,7 @@ int main(int argc, char *argv[]) { retry = false; try { - ClientConnection conn; + ClientConnection conn(config); conn.start(url + args); } catch (const std::exception &e) { @@ -65,5 +62,6 @@ int main(int argc, char *argv[]) { Logger::write("Cleaned up", Logger::LogLevel::Info); + std::getchar(); return exit_code; } diff --git a/TriviaBot/bot/TriviaGame.cpp b/TriviaBot/bot/TriviaGame.cpp index a9914ca..b440b14 100644 --- a/TriviaBot/bot/TriviaGame.cpp +++ b/TriviaBot/bot/TriviaGame.cpp @@ -13,8 +13,9 @@ #include "DiscordAPI.hpp" #include "data_structures/User.hpp" #include "Logger.hpp" +#include "BotConfig.hpp" -TriviaGame::TriviaGame(GatewayHandler *gh, std::string channel_id, int total_questions, int delay) : interval(delay) { +TriviaGame::TriviaGame(BotConfig &c, GatewayHandler *gh, std::string channel_id, int total_questions, int delay) : interval(delay), config(c) { this->gh = gh; this->channel_id = channel_id; @@ -26,7 +27,7 @@ TriviaGame::~TriviaGame() { current_thread.reset(); if (scores.size() == 0) { - DiscordAPI::send_message(channel_id, ":red_circle: Game cancelled!"); + DiscordAPI::send_message(channel_id, ":red_circle: Game cancelled!", config.token, config.cert_location); return; } @@ -50,7 +51,7 @@ TriviaGame::~TriviaGame() { average_time.pop_back(); average_time.pop_back(); average_time.pop_back(); message += ":small_blue_diamond: <@!" + p.first + ">: " + std::to_string(p.second) + " (Avg: " + average_time + " seconds)\n"; } - DiscordAPI::send_message(channel_id, message); + DiscordAPI::send_message(channel_id, message, config.token, config.cert_location); sqlite3 *db; int rc; std::string sql; @@ -213,7 +214,8 @@ void TriviaGame::question() { sqlite3_close(db); questions_asked++; - DiscordAPI::send_message(channel_id, ":question: **(" + std::to_string(questions_asked) + "/" + std::to_string(total_questions) + ")** " + current_question); + DiscordAPI::send_message(channel_id, ":question: **(" + std::to_string(questions_asked) + "/" + std::to_string(total_questions) + ")** " + current_question, + config.token, config.cert_location); question_start = boost::posix_time::microsec_clock::universal_time(); give_hint(0, ""); @@ -280,11 +282,11 @@ void TriviaGame::give_hint(int hints_given, std::string hint) { hints_given++; // now equal to the amount of [hide_char]s that need to be present in each word if (print) { - DiscordAPI::send_message(channel_id, ":small_orange_diamond: Hint: **`" + hint + "`**"); + DiscordAPI::send_message(channel_id, ":small_orange_diamond: Hint: **`" + hint + "`**", config.token, config.cert_location); } } boost::this_thread::sleep(interval); - DiscordAPI::send_message(channel_id, ":exclamation: Question failed. Answer: ** `" + *current_answers.begin() + "` **"); + DiscordAPI::send_message(channel_id, ":exclamation: Question failed. Answer: ** `" + *current_answers.begin() + "` **", config.token, config.cert_location); } void TriviaGame::handle_answer(std::string answer, DiscordObjects::User sender) { @@ -299,7 +301,7 @@ void TriviaGame::handle_answer(std::string answer, DiscordObjects::User sender) // remove the last three 0s time_taken.pop_back(); time_taken.pop_back(); time_taken.pop_back(); - DiscordAPI::send_message(channel_id, ":heavy_check_mark: <@!" + sender.id + "> You got it! (" + time_taken + " seconds)"); + DiscordAPI::send_message(channel_id, ":heavy_check_mark: <@!" + sender.id + "> You got it! (" + time_taken + " seconds)", config.token, config.cert_location); increase_score(sender.id); update_average_time(sender.id, diff.total_milliseconds()); diff --git a/TriviaBot/bot/TriviaGame.hpp b/TriviaBot/bot/TriviaGame.hpp index 89b326f..477c7f1 100644 --- a/TriviaBot/bot/TriviaGame.hpp +++ b/TriviaBot/bot/TriviaGame.hpp @@ -11,14 +11,14 @@ #include class GatewayHandler; +class BotConfig; namespace DiscordObjects { class User; } - class TriviaGame { public: - TriviaGame(GatewayHandler *gh, std::string channel_id, int total_questions, int delay); + TriviaGame(BotConfig &c, GatewayHandler *gh, std::string channel_id, int total_questions, int delay); ~TriviaGame(); void start(); @@ -26,6 +26,8 @@ public: void handle_answer(std::string answer, DiscordObjects::User sender); private: + BotConfig &config; + int questions_asked; int total_questions; boost::posix_time::seconds interval; diff --git a/TriviaBot/bot/http/HTTPHelper.cpp b/TriviaBot/bot/http/HTTP.cpp similarity index 83% rename from TriviaBot/bot/http/HTTPHelper.cpp rename to TriviaBot/bot/http/HTTP.cpp index d1e98ee..fa28ec4 100644 --- a/TriviaBot/bot/http/HTTPHelper.cpp +++ b/TriviaBot/bot/http/HTTP.cpp @@ -1,20 +1,18 @@ -#include "HTTPHelper.hpp" +#include "HTTP.hpp" #include "../Logger.hpp" - -extern std::string bot_token; +#include "../BotConfig.hpp" /* * Warning: (Awful) C Code */ - namespace HTTP { size_t write_callback(void *contents, size_t size, size_t nmemb, void *read_buffer) { static_cast(read_buffer)->append(static_cast(contents), size * nmemb); return size * nmemb; } - std::string post_request(std::string url, std::string content_type, std::string data, long *response_code) { + std::string post_request(std::string url, std::string content_type, std::string data, long *response_code, std::string token, std::string ca_location) { CURL *curl; CURLcode res; std::string read_buffer; @@ -25,11 +23,11 @@ namespace HTTP { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // Now with real HTTPS! - curl_easy_setopt(curl, CURLOPT_CAINFO, "bot/http/DiscordCA.crt"); + curl_easy_setopt(curl, CURLOPT_CAINFO, ca_location.c_str()); std::string header_arr[3]; header_arr[0] = "Content-Type: " + content_type; - header_arr[1] = "Authorization: Bot " + bot_token; + header_arr[1] = "Authorization: Bot " + token; header_arr[2] = "User-Agent: DiscordBot(http://github.com/jackb-p/triviadiscord, 1.0)"; for (std::string h : header_arr) { @@ -59,7 +57,7 @@ namespace HTTP { return read_buffer; } - std::string get_request(std::string url, long *response_code) { + std::string get_request(std::string url, long *response_code, std::string token, std::string ca_location) { CURL *curl; CURLcode res; std::string read_buffer; @@ -70,10 +68,10 @@ namespace HTTP { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // Now with real HTTPS! - curl_easy_setopt(curl, CURLOPT_CAINFO, "bot/http/DiscordCA.crt"); + curl_easy_setopt(curl, CURLOPT_CAINFO, ca_location.c_str()); std::string header_arr[2]; - header_arr[0] = "Authorization: Bot " + bot_token; + header_arr[0] = "Authorization: Bot " + token; header_arr[1] = "User-Agent: DiscordBot (http://github.com/jackb-p/triviadiscord, 1.0)"; for (std::string h : header_arr) { diff --git a/TriviaBot/bot/http/HTTP.hpp b/TriviaBot/bot/http/HTTP.hpp new file mode 100644 index 0000000..1f84f7d --- /dev/null +++ b/TriviaBot/bot/http/HTTP.hpp @@ -0,0 +1,15 @@ +#ifndef BOT_HTTP_HTTP +#define BOT_HTTP_HTTP + +#include + +#include + +class BotConfig; + +namespace HTTP { + std::string post_request(std::string url, std::string content_type, std::string data, long *response_code, std::string token, std::string ca_location); + std::string get_request(std::string url, long *response_code, std::string token, std::string ca_location); +} + +#endif \ No newline at end of file diff --git a/TriviaBot/bot/http/HTTPHelper.hpp b/TriviaBot/bot/http/HTTPHelper.hpp deleted file mode 100644 index 1acc725..0000000 --- a/TriviaBot/bot/http/HTTPHelper.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef BOT_HTTP_HTTPHELPER -#define BOT_HTTP_HTTPHELPER - -#include - -#include - -namespace HTTP { - std::string post_request(std::string url, std::string content_type, std::string data, long *response_code); - std::string get_request(std::string url, long *response_code); -} - -#endif \ No newline at end of file diff --git a/TriviaBot/bot/js/V8Instance.cpp b/TriviaBot/bot/js/V8Instance.cpp index 6ca2cf4..6769c31 100644 --- a/TriviaBot/bot/js/V8Instance.cpp +++ b/TriviaBot/bot/js/V8Instance.cpp @@ -6,9 +6,12 @@ #include "V8Instance.hpp" #include "../DiscordAPI.hpp" #include "../Logger.hpp" +#include "../BotConfig.hpp" -V8Instance::V8Instance(std::string guild_id, std::map *guilds, std::map *channels, - std::map *users, std::map *roles) { +using namespace v8; + +V8Instance::V8Instance(BotConfig &c, std::string guild_id, std::map *guilds, std::map *channels, + std::map *users, std::map *roles) : config(c) { rng = std::mt19937(std::random_device()()); this->guild_id = guild_id; @@ -25,6 +28,7 @@ void V8Instance::create() { create_params.array_buffer_allocator = ArrayBuffer::Allocator::NewDefaultAllocator(); isolate = Isolate::New(create_params); + isolate->Enter(); Logger::write("[v8] Created isolate", Logger::LogLevel::Debug); Isolate::Scope isolate_scope(isolate); @@ -696,7 +700,7 @@ void V8Instance::exec_js(std::string js, DiscordObjects::Channel *channel, Disco std::string err_msg = *error; Logger::write("[v8] Compilation error: " + err_msg, Logger::LogLevel::Debug); - DiscordAPI::send_message(channel->id, ":warning: **Compilation error:** `" + err_msg + "`"); + DiscordAPI::send_message(channel->id, ":warning: **Compilation error:** `" + err_msg + "`", config.token, config.cert_location); return; } @@ -708,7 +712,7 @@ void V8Instance::exec_js(std::string js, DiscordObjects::Channel *channel, Disco std::string err_msg = *error; Logger::write("[v8] Runtime error: " + err_msg, Logger::LogLevel::Debug); - DiscordAPI::send_message(channel->id, ":warning: **Runtime error:** `" + err_msg + "`"); + DiscordAPI::send_message(channel->id, ":warning: **Runtime error:** `" + err_msg + "`", config.token, config.cert_location); } auto end = std::chrono::steady_clock::now(); @@ -719,7 +723,7 @@ void V8Instance::exec_js(std::string js, DiscordObjects::Channel *channel, Disco current_channel = nullptr; if (print_text != "") { - DiscordAPI::send_message(channel->id, print_text); + DiscordAPI::send_message(channel->id, print_text, config.token, config.cert_location); print_text = ""; } } diff --git a/TriviaBot/bot/js/V8Instance.hpp b/TriviaBot/bot/js/V8Instance.hpp index 00e99b8..423ec53 100644 --- a/TriviaBot/bot/js/V8Instance.hpp +++ b/TriviaBot/bot/js/V8Instance.hpp @@ -14,68 +14,68 @@ #include "../data_structures/GuildMember.hpp" #include "../data_structures/User.hpp" -class APIHelper; - -using namespace v8; +class BotConfig; class V8Instance { public: - V8Instance(std::string guild_id, std::map *guilds, + V8Instance(BotConfig &c, std::string guild_id, std::map *guilds, std::map *channels, std::map *users, std::map *roles); void exec_js(std::string js, DiscordObjects::Channel *channel, DiscordObjects::GuildMember *sender, std::string args = ""); private: - void create(); - Local create_context(); + BotConfig &config; - void initialise(Local context); + void create(); + v8::Local create_context(); + + void initialise(v8::Local context); /* server */ - Global server_template; - Local make_server_template(); - Local wrap_server(DiscordObjects::Guild *guild); - static void js_get_server(Local property, const PropertyCallbackInfo &info); + v8::Global server_template; + v8::Local make_server_template(); + v8::Local wrap_server(DiscordObjects::Guild *guild); + static void js_get_server(v8::Local property, const v8::PropertyCallbackInfo &info); /* user */ - Global user_template; - Local make_user_template(); - Local wrap_user(DiscordObjects::GuildMember *member); - static void js_get_user(Local property, const PropertyCallbackInfo &info); + v8::Global user_template; + v8::Local make_user_template(); + v8::Local wrap_user(DiscordObjects::GuildMember *member); + static void js_get_user(v8::Local property, const v8::PropertyCallbackInfo &info); - Global user_list_template; - Local make_user_list_template(); - Local wrap_user_list(std::vector *user_list); - static void js_get_user_list(uint32_t index, const PropertyCallbackInfo &info); + v8::Global user_list_template; + v8::Local make_user_list_template(); + v8::Local wrap_user_list(std::vector *user_list); + static void js_get_user_list(uint32_t index, const v8::PropertyCallbackInfo &info); /* channel */ - Global channel_template; - Local make_channel_template(); - Local wrap_channel(DiscordObjects::Channel *channel); - static void js_get_channel(Local property, const PropertyCallbackInfo &info); + v8::Global channel_template; + v8::Local make_channel_template(); + v8::Local wrap_channel(DiscordObjects::Channel *channel); + static void js_get_channel(v8::Local property, const v8::PropertyCallbackInfo &info); - Global channel_list_template; - Local make_channel_list_template(); - Local wrap_channel_list(std::vector *channel_list); - static void js_get_channel_list(uint32_t index, const PropertyCallbackInfo &info); + v8::Global channel_list_template; + v8::Local make_channel_list_template(); + v8::Local wrap_channel_list(std::vector *channel_list); + static void js_get_channel_list(uint32_t index, const v8::PropertyCallbackInfo &info); /* role */ - Global role_template; - Local make_role_template(); - Local wrap_role(DiscordObjects::Role *role); - static void js_get_role(Local property, const PropertyCallbackInfo &info); + v8::Global role_template; + v8::Local make_role_template(); + v8::Local wrap_role(DiscordObjects::Role *role); + static void js_get_role(v8::Local property, const v8::PropertyCallbackInfo &info); - Global role_list_template; - Local make_role_list_template(); - Local wrap_role_list(std::vector *role_list); - static void js_get_role_list(uint32_t index, const PropertyCallbackInfo &info); + v8::Global role_list_template; + v8::Local make_role_list_template(); + v8::Local wrap_role_list(std::vector *role_list); + static void js_get_role_list(uint32_t index, const v8::PropertyCallbackInfo &info); /* print function */ - static void js_print(const FunctionCallbackInfo &args); + static void js_print(const v8::FunctionCallbackInfo &args); /* randomness functions */ - static void js_random(const FunctionCallbackInfo &args); - static void js_shuffle(const FunctionCallbackInfo &args); + static void js_random(const v8::FunctionCallbackInfo &args); + static void js_shuffle(const v8::FunctionCallbackInfo &args); std::map *guilds; std::map *channels; @@ -83,9 +83,9 @@ private: std::map *roles; std::string guild_id; - Isolate *isolate; + v8::Isolate *isolate; - Global context_; + v8::Global context_; /* random generating variables */ std::mt19937 rng;