diff --git a/TriviaBot/bot/APIHelper.cpp b/TriviaBot/bot/APIHelper.cpp index ca7d484..023eabd 100644 --- a/TriviaBot/bot/APIHelper.cpp +++ b/TriviaBot/bot/APIHelper.cpp @@ -4,7 +4,10 @@ #include "APIHelper.hpp" -APIHelper::APIHelper() { +extern std::string bot_token; + +APIHelper::APIHelper() : BASE_URL("https://discordapp.com/api"), CHANNELS_URL(BASE_URL + "/channels"), + TOKEN_PARAM("token=" + bot_token), JSON_CTYPE("application/json") { http = new HTTPHelper(); } @@ -15,5 +18,5 @@ void APIHelper::send_message(std::string channel_id, std::string message) { }; const std::string response = http->post_request(url, JSON_CTYPE, data.dump()); - std::cout << response << std::endl; + // TODO: verify success } \ No newline at end of file diff --git a/TriviaBot/bot/APIHelper.hpp b/TriviaBot/bot/APIHelper.hpp index ac95f15..3e00658 100644 --- a/TriviaBot/bot/APIHelper.hpp +++ b/TriviaBot/bot/APIHelper.hpp @@ -16,11 +16,11 @@ public: void send_message(std::string channel_id, std::string message); private: - const std::string BASE_URL = "https://discordapp.com/api"; - const std::string CHANNELS_URL = BASE_URL + "/channels"; - const std::string TOKEN = "MTk5NjU3MDk1MjU4MTc3NTM5.ClyBNQ.15qTa-XBKRtGNMMYeXCrU50GhWE"; - const std::string TOKEN_PARAM = "token=" + TOKEN; - const std::string JSON_CTYPE = "application/json"; + const std::string BASE_URL; + const std::string CHANNELS_URL; + const std::string TOKEN; + const std::string TOKEN_PARAM; + const std::string JSON_CTYPE; HTTPHelper *http; }; diff --git a/TriviaBot/bot/GatewayHandler.cpp b/TriviaBot/bot/GatewayHandler.cpp index 3dbab89..4c7193e 100644 --- a/TriviaBot/bot/GatewayHandler.cpp +++ b/TriviaBot/bot/GatewayHandler.cpp @@ -5,6 +5,8 @@ #include "APIHelper.hpp" #include "data_structures/User.hpp" +extern std::string bot_token; + GatewayHandler::GatewayHandler() { last_seq = 0; @@ -26,8 +28,6 @@ void GatewayHandler::handle_data(std::string data, client &c, websocketpp::conne case 11: c.get_alog().write(websocketpp::log::alevel::app, "Heartbeat acknowledged."); break; - default: - std::cout << data << std::endl; } } @@ -53,7 +53,7 @@ void GatewayHandler::heartbeat(websocketpp::lib::error_code const & ec, client * void GatewayHandler::on_hello(json decoded, client &c, websocketpp::connection_hdl &hdl) { heartbeat_interval = decoded["d"]["heartbeat_interval"]; - c.get_alog().write(websocketpp::log::alevel::app, "Heartbeat interval: " + std::to_string((float)heartbeat_interval / 1000) + " seconds"); + c.get_alog().write(websocketpp::log::alevel::app, "Heartbeat interval: " + std::to_string(heartbeat_interval / 1000.0f) + " seconds"); c.set_timer(heartbeat_interval, websocketpp::lib::bind( &GatewayHandler::heartbeat, @@ -71,14 +71,10 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio std::string event_name = decoded["t"]; json data = decoded["d"]; - c.get_alog().write(websocketpp::log::alevel::app, "Received event: " + event_name + " (new seq value: " + std::to_string(last_seq) + ")"); - if (event_name == "READY") { user_object.load_from_json(data["user"]); c.get_alog().write(websocketpp::log::alevel::app, "Sign-on confirmed. (@" + user_object.username + "#" + user_object.discriminator + ")"); - - c.get_alog().write(websocketpp::log::alevel::app, data.dump(4)); } else if (event_name == "GUILD_CREATE") { std::string guild_id = data["id"]; @@ -92,8 +88,6 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio // add ptr to said channel list to guild's channel list guilds[guild_id]->channels.push_back(std::shared_ptr(channels[channel_id])); } - - c.get_alog().write(websocketpp::log::alevel::app, data.dump(4)); } else if (event_name == "TYPING_START") {} else if (event_name == "MESSAGE_CREATE") { @@ -102,27 +96,49 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio DiscordObjects::User sender(data["author"]); - c.get_alog().write(websocketpp::log::alevel::app, "Message received: " + message + " $" + channel->name + " ^" + channel->id); - std::vector words; boost::split(words, message, boost::is_any_of(" ")); - if (games.find(channel->id) != games.end()) { // message received in channel with ongoing game - games[channel->id]->handle_answer(message, sender); - } else if (words[0] == "`trivia" || words[0] == "`t") { + if (words[0] == "`trivia" || words[0] == "`t") { int questions = 10; - if (words.size() == 2) { - try { - questions = std::stoi(words[1]); - } catch (std::invalid_argument e) { - ah->send_message(channel->id, ":exclamation: Invalid arguments!"); - } - } else if (words.size() > 2) { + int delay = 8; + + if (words.size() > 3) { ah->send_message(channel->id, ":exclamation: Invalid arguments!"); + 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"; + + ah->send_message(channel->id, help); + return; + } + else if (words[1] == "stop" || words[1] == "s") { + if (games.find(channel->id) != games.end()) { + delete_game(channel->id); + return; + } + } + else { + try { + questions = std::stoi(words[1]); + if (words.size() == 3) { + delay = std::stoi(words[2]); + } + } + catch (std::invalid_argument e) { + ah->send_message(channel->id, ":exclamation: Invalid arguments!"); + return; + } + } } - games[channel->id] = std::make_unique(this, ah, channel->id, questions); + games[channel->id] = std::make_unique(this, ah, channel->id, questions, delay); games[channel->id]->start(); - } + } else if (words[0] == "`channels") { std::string m = "Channel List:\n"; for (auto ch : channels) { @@ -130,24 +146,26 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio + guilds[ch.second->guild_id]->name + " (" + ch.second->guild_id + ")\n"; } ah->send_message(channel->id, m); - } else if (words[0] == "`guilds") { + } + else if (words[0] == "`guilds") { std::string m = "Guild List:\n"; for (auto &gu : guilds) { m += "> " + gu.second->name + " (" + gu.second->id + ") Channels: " + std::to_string(gu.second->channels.size()) + "\n"; } ah->send_message(channel->id, m); } - c.get_alog().write(websocketpp::log::alevel::app, data.dump(2)); + else if (games.find(channel->id) != games.end()) { // message received in channel with ongoing game + games[channel->id]->handle_answer(message, sender); + } } - //c.get_alog().write(websocketpp::log::alevel::app, decoded.dump(2)); } void GatewayHandler::identify(client &c, websocketpp::connection_hdl &hdl) { json identify = { { "op", 2 }, - { "d",{ - { "token", TOKEN }, - { "properties",{ + { "d", { + { "token", bot_token }, + { "properties", { { "$browser", "Microsoft Windows 10" }, { "$device", "TriviaBot-0.0" }, { "$referrer", "" }, @@ -155,18 +173,19 @@ void GatewayHandler::identify(client &c, websocketpp::connection_hdl &hdl) { } }, { "compress", false }, { "large_threshold", 250 }, - { "shard",{ 0, 1 } } + { "shard", { 0, 1 } } } } }; c.send(hdl, identify.dump(), websocketpp::frame::opcode::text); - c.get_alog().write(websocketpp::log::alevel::app, "Sent identify payload."); + c.get_alog().write(websocketpp::log::alevel::app, "Sent identify payload. Token: " + bot_token); } void GatewayHandler::delete_game(std::string channel_id) { auto it = games.find(channel_id); if (it != games.end()) { + it->second->interrupt(); // remove from map games.erase(it); } else { diff --git a/TriviaBot/bot/GatewayHandler.hpp b/TriviaBot/bot/GatewayHandler.hpp index 0f1067b..12a845d 100644 --- a/TriviaBot/bot/GatewayHandler.hpp +++ b/TriviaBot/bot/GatewayHandler.hpp @@ -57,7 +57,6 @@ private: int heartbeat_interval; const int protocol_version = 5; - const std::string TOKEN = "MTk5NjU3MDk1MjU4MTc3NTM5.ClyBNQ.15qTa-XBKRtGNMMYeXCrU50GhWE"; // bot's user obj DiscordObjects::User user_object; diff --git a/TriviaBot/bot/TriviaBot.cpp b/TriviaBot/bot/TriviaBot.cpp index 03207a6..548ad33 100644 --- a/TriviaBot/bot/TriviaBot.cpp +++ b/TriviaBot/bot/TriviaBot.cpp @@ -2,23 +2,34 @@ #include "ClientConnection.hpp" -int main() { +std::string bot_token; + +int main(int argc, char *argv[]) { curl_global_init(CURL_GLOBAL_DEFAULT); + if (argc == 2) { + bot_token = argv[1]; + } + else { + std::cout << "Please enter your bot token: " << std::endl; + std::cin >> bot_token; + } + + // todo: get this using API std::string uri = "wss://gateway.discord.gg/?v=5&encoding=json"; try { - ClientConnection endpoint; - endpoint.start(uri); + ClientConnection conn; + conn.start(uri); } catch (const std::exception & e) { - std::cout << e.what() << std::endl; + std::cerr << e.what() << std::endl; } catch (websocketpp::lib::error_code e) { - std::cout << e.message() << std::endl; + std::cerr << e.message() << std::endl; } catch (...) { - std::cout << "other exception" << std::endl; + std::cerr << "other exception" << std::endl; } std::getchar(); diff --git a/TriviaBot/bot/TriviaGame.cpp b/TriviaBot/bot/TriviaGame.cpp index cf4561a..6a712a8 100644 --- a/TriviaBot/bot/TriviaGame.cpp +++ b/TriviaBot/bot/TriviaGame.cpp @@ -13,7 +13,7 @@ #include "APIHelper.hpp" #include "data_structures/User.hpp" -TriviaGame::TriviaGame(GatewayHandler *gh, APIHelper *ah, std::string channel_id, int total_questions) { +TriviaGame::TriviaGame(GatewayHandler *gh, APIHelper *ah, std::string channel_id, int total_questions, int delay) : interval(delay) { this->gh = gh; this->ah = ah; this->channel_id = channel_id; @@ -23,6 +23,11 @@ TriviaGame::TriviaGame(GatewayHandler *gh, APIHelper *ah, std::string channel_id } TriviaGame::~TriviaGame() { + if (scores.size() == 0) { + ah->send_message(channel_id, ":red_circle: Game cancelled!"); + return; + } + std::string message = ":red_circle: **(" + std::to_string(questions_asked) + "/" + std::to_string(total_questions) + ")** Game over! **Scores:**\n"; @@ -33,7 +38,7 @@ TriviaGame::~TriviaGame() { } // sort by score, highest->lowest - std::sort(pairs.begin(), pairs.end(), [=](std::pair& a, std::pair& b) { + std::sort(pairs.begin(), pairs.end(), [=](std::pair &a, std::pair &b) { return a.second > b.second; }); @@ -83,7 +88,7 @@ TriviaGame::~TriviaGame() { rc = sqlite3_step(stmt); if (rc == SQLITE_ROW) { - std::string id = reinterpret_cast(sqlite3_column_text(stmt, 0)); + std::string id = reinterpret_cast(sqlite3_column_text(stmt, 0)); int total_score = sqlite3_column_int(stmt, 1); int average_time = sqlite3_column_int(stmt, 2); @@ -131,7 +136,6 @@ TriviaGame::~TriviaGame() { } if (update_sql != "") { - std::cout << update_sql << std::endl; rc = sqlite3_prepare_v2(db, update_sql.c_str(), -1, &stmt, 0); if (rc != SQLITE_OK) { std::cerr << "SQL error." << std::endl; @@ -159,14 +163,14 @@ TriviaGame::~TriviaGame() { sqlite3_close(db); } -void TriviaGame::end_game() { - gh->delete_game(channel_id); -} - void TriviaGame::start() { question(); } +void TriviaGame::interrupt() { + current_thread->interrupt(); +} + void TriviaGame::question() { sqlite3 *db; int rc; char *sql; @@ -188,10 +192,10 @@ void TriviaGame::question() { rc = sqlite3_step(stmt); if (rc == SQLITE_ROW) { // result received - std::string id = reinterpret_cast(sqlite3_column_text(stmt, 0)); // converts id to string for us - std::string category = reinterpret_cast(sqlite3_column_text(stmt, 1)); - std::string question = reinterpret_cast(sqlite3_column_text(stmt, 2)); - std::string answer = reinterpret_cast(sqlite3_column_text(stmt, 3)); + std::string id = reinterpret_cast(sqlite3_column_text(stmt, 0)); // converts id to string for us + std::string category = reinterpret_cast(sqlite3_column_text(stmt, 1)); + std::string question = reinterpret_cast(sqlite3_column_text(stmt, 2)); + std::string answer = reinterpret_cast(sqlite3_column_text(stmt, 3)); current_question = "#" + id + " [" + category + "] **" + question + "**"; boost::split(current_answers, boost::algorithm::to_lower_copy(answer), boost::is_any_of("*")); @@ -212,7 +216,7 @@ void TriviaGame::question() { } void TriviaGame::give_hint(int hints_given, std::string hint) { - boost::this_thread::sleep(boost::posix_time::seconds(10)); + boost::this_thread::sleep(interval); std::string answer = *current_answers.begin(); @@ -225,8 +229,7 @@ void TriviaGame::give_hint(int hints_given, std::string hint) { hint = boost::regex_replace(hint, regexp, std::string(1, hide_char)); print = true; - } - else { + } else { std::stringstream hint_stream(hint); std::random_device rd; @@ -281,13 +284,13 @@ void TriviaGame::give_hint(int hints_given, std::string hint) { } void TriviaGame::question_failed() { - boost::this_thread::sleep(boost::posix_time::seconds(10)); + boost::this_thread::sleep(interval); ah->send_message(channel_id, ":exclamation: Question failed. Answer: ** `" + *current_answers.begin() + "` **"); - if (questions_asked < 10) { + if (questions_asked < total_questions) { question(); } else { - end_game(); + gh->delete_game(channel_id); } } @@ -307,15 +310,11 @@ void TriviaGame::handle_answer(std::string answer, DiscordObjects::User sender) increase_score(sender.id); update_average_time(sender.id, diff.total_milliseconds()); - if (questions_asked < 10) { + if (questions_asked < total_questions) { question(); } else { - end_game(); + gh->delete_game(channel_id); } - } else if (answer == "`s" || answer == "`stop") { - current_thread->interrupt(); - - end_game(); } } diff --git a/TriviaBot/bot/TriviaGame.hpp b/TriviaBot/bot/TriviaGame.hpp index 04c1514..846159d 100644 --- a/TriviaBot/bot/TriviaGame.hpp +++ b/TriviaBot/bot/TriviaGame.hpp @@ -19,17 +19,18 @@ namespace DiscordObjects { class TriviaGame { public: - TriviaGame(GatewayHandler *gh, APIHelper *ah, std::string channel_id, int total_questions); + TriviaGame(GatewayHandler *gh, APIHelper *ah, std::string channel_id, int total_questions, int delay); ~TriviaGame(); void start(); + void interrupt(); void handle_answer(std::string answer, DiscordObjects::User sender); private: int questions_asked; int total_questions; + boost::posix_time::seconds interval; - void end_game(); void question(); void give_hint(int hints_given, std::string hint); void question_failed(); diff --git a/TriviaBot/bot/data_structures/Guild.hpp b/TriviaBot/bot/data_structures/Guild.hpp index fe2ace7..933d082 100644 --- a/TriviaBot/bot/data_structures/Guild.hpp +++ b/TriviaBot/bot/data_structures/Guild.hpp @@ -83,8 +83,6 @@ namespace DiscordObjects { inline void Guild::load_from_json(json data) { Guild(); - std::cout << data.dump(4) << std::endl; - id = data.value("id", "null"); name = data.value("name", "null");