From d49c502869bd1850dc94186b503c182d0c44c495 Mon Sep 17 00:00:00 2001 From: jackb-p Date: Wed, 3 Aug 2016 21:52:14 +0100 Subject: [PATCH 01/15] Update gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fc45dfb..e155f43 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ # Data files /TriviaBot/data_management/questions -/TriviaBot/bot/db/trivia.db \ No newline at end of file +/TriviaBot/bot/db/trivia.db + +# Compiled sqlite file +sqlite3.obj \ No newline at end of file From 005dad899bc63c1f84e6bf9754e801c905bf85a9 Mon Sep 17 00:00:00 2001 From: jackb-p Date: Wed, 3 Aug 2016 22:04:05 +0100 Subject: [PATCH 02/15] Basic JS implementation --- TriviaBot/bot/GatewayHandler.cpp | 23 ++++--- TriviaBot/bot/GatewayHandler.hpp | 5 +- TriviaBot/bot/TriviaBot.cpp | 12 ++++ TriviaBot/bot/TriviaGame.cpp | 2 +- TriviaBot/bot/TriviaGame.hpp | 4 +- TriviaBot/bot/js/V8Instance.cpp | 101 +++++++++++++++++++++++++++++++ TriviaBot/bot/js/V8Instance.hpp | 31 ++++++++++ 7 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 TriviaBot/bot/js/V8Instance.cpp create mode 100644 TriviaBot/bot/js/V8Instance.hpp diff --git a/TriviaBot/bot/GatewayHandler.cpp b/TriviaBot/bot/GatewayHandler.cpp index f15ab29..7e3af06 100644 --- a/TriviaBot/bot/GatewayHandler.cpp +++ b/TriviaBot/bot/GatewayHandler.cpp @@ -10,7 +10,7 @@ extern std::string bot_token; GatewayHandler::GatewayHandler() { last_seq = 0; - ah = new APIHelper(); + ah = std::make_shared(); } void GatewayHandler::handle_data(std::string data, client &c, websocketpp::connection_hdl &hdl) { @@ -68,14 +68,7 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio } else if (event_name == "GUILD_CREATE") { std::string guild_id = data["id"]; - try { - guilds[guild_id] = std::make_unique(data); - } - catch (std::domain_error err) { - // this doesn't even work - c.get_alog().write(websocketpp::log::elevel::rerror, "Domain error"); - } - + guilds[guild_id] = std::make_unique(data); c.get_alog().write(websocketpp::log::alevel::app, "Loaded guild: " + guilds[guild_id]->name); @@ -87,6 +80,11 @@ 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])); } + + if (v8_instances.count(guild_id) == 0) { + v8_instances[guild_id] = std::make_unique(ah); + c.get_alog().write(websocketpp::log::alevel::app, "Created v8 instance for guild " + guild_id); + } } else if (event_name == "TYPING_START") {} else if (event_name == "MESSAGE_CREATE") { @@ -156,6 +154,13 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio else if (words[0] == "`info") { ah->send_message(channel->id, ":information_source: trivia-bot by Jack. "); } + else if (words[0] == "`js") { + std::string js = message.erase(0, 3); + auto it = v8_instances.find(channel->guild_id); + if (it != v8_instances.end()) { + it->second->exec_js(js, channel->id); + } + } else if (games.find(channel->id) != games.end()) { // message received in channel with ongoing game games[channel->id]->handle_answer(message, sender); } diff --git a/TriviaBot/bot/GatewayHandler.hpp b/TriviaBot/bot/GatewayHandler.hpp index 4b60448..775a1a6 100644 --- a/TriviaBot/bot/GatewayHandler.hpp +++ b/TriviaBot/bot/GatewayHandler.hpp @@ -9,6 +9,7 @@ #include "json/json.hpp" #include "TriviaGame.hpp" +#include "js/V8Instance.hpp" #include "data_structures/User.hpp" #include "data_structures/Guild.hpp" #include "data_structures/Channel.hpp" @@ -68,10 +69,12 @@ private: // std::map> games; + // + std::map> v8_instances; std::unique_ptr heartbeat_thread; - APIHelper *ah; + std::shared_ptr ah; }; #endif \ No newline at end of file diff --git a/TriviaBot/bot/TriviaBot.cpp b/TriviaBot/bot/TriviaBot.cpp index 548ad33..aeee6ca 100644 --- a/TriviaBot/bot/TriviaBot.cpp +++ b/TriviaBot/bot/TriviaBot.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "ClientConnection.hpp" @@ -7,6 +9,12 @@ std::string bot_token; int main(int argc, char *argv[]) { curl_global_init(CURL_GLOBAL_DEFAULT); + v8::V8::InitializeICUDefaultLocation(argv[0]); + v8::V8::InitializeExternalStartupData(argv[0]); + v8::Platform* platform = v8::platform::CreateDefaultPlatform(); + v8::V8::InitializePlatform(platform); + v8::V8::Initialize(); + if (argc == 2) { bot_token = argv[1]; } @@ -34,6 +42,10 @@ int main(int argc, char *argv[]) { std::getchar(); + v8::V8::Dispose(); + v8::V8::ShutdownPlatform(); + delete platform; + curl_global_cleanup(); return 0; diff --git a/TriviaBot/bot/TriviaGame.cpp b/TriviaBot/bot/TriviaGame.cpp index a2385f1..94a5631 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, int delay) : interval(delay) { +TriviaGame::TriviaGame(GatewayHandler *gh, std::shared_ptr ah, std::string channel_id, int total_questions, int delay) : interval(delay) { this->gh = gh; this->ah = ah; this->channel_id = channel_id; diff --git a/TriviaBot/bot/TriviaGame.hpp b/TriviaBot/bot/TriviaGame.hpp index fb393db..4031c1d 100644 --- a/TriviaBot/bot/TriviaGame.hpp +++ b/TriviaBot/bot/TriviaGame.hpp @@ -19,7 +19,7 @@ namespace DiscordObjects { class TriviaGame { public: - TriviaGame(GatewayHandler *gh, APIHelper *ah, std::string channel_id, int total_questions, int delay); + TriviaGame(GatewayHandler *gh, std::shared_ptr ah, std::string channel_id, int total_questions, int delay); ~TriviaGame(); void start(); @@ -38,7 +38,7 @@ private: std::string channel_id; GatewayHandler *gh; - APIHelper *ah; + std::shared_ptr ah; const char hide_char = '#'; diff --git a/TriviaBot/bot/js/V8Instance.cpp b/TriviaBot/bot/js/V8Instance.cpp new file mode 100644 index 0000000..434fd8d --- /dev/null +++ b/TriviaBot/bot/js/V8Instance.cpp @@ -0,0 +1,101 @@ +#include +#include + +#include "V8Instance.hpp" +#include "../APIHelper.hpp" + +using namespace v8; + +V8Instance::V8Instance(std::shared_ptr ah) { + this->ah = ah; + create(); +} + +V8Instance::~V8Instance() { + clean_up(); +} + +void V8Instance::create() { + Isolate::CreateParams create_params; + create_params.array_buffer_allocator = ArrayBuffer::Allocator::NewDefaultAllocator(); + + isolate = Isolate::New(create_params); + isolate->Enter(); + std::cout << "Created isolate." << std::endl; + + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + + // set global context + Local context = create_context(); + context->Enter(); + Context::Scope context_scope(context); + std::cout << "Created context and context scope." << std::endl; +} + +v8::Local V8Instance::create_context() { + Local global = ObjectTemplate::New(isolate); + // bind print() function + Local self = External::New(isolate, (void *) this); + global->Set(String::NewFromUtf8(isolate, "print", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, V8Instance::js_print, self)); + std::cout << "Created global, assigned print function." << std::endl; + + return Context::New(isolate, NULL, global); +} + +void V8Instance::clean_up() { + std::cout << "Cleaning up." << std::endl; + isolate->Exit(); + isolate->Dispose(); + delete array_buffer_allocator; +} + +void V8Instance::reload() { + clean_up(); + create(); +} + +void V8Instance::exec_js(std::string js, std::string channel_id) { + std::cout << "Isolate nullptr? " << (isolate == nullptr) << std::endl; + + HandleScope handle_scope(isolate); + Local context(isolate->GetCurrentContext()); + + std::cout << "Executing js: " << js << std::endl; + + Local source = String::NewFromUtf8(isolate, js.c_str(), NewStringType::kNormal).ToLocalChecked(); + std::cout << "String coverted" << std::endl; + + // compile + std::cout << "Context empty? " << context.IsEmpty() << std::endl; + + TryCatch try_catch(isolate); + Local