diff --git a/TriviaBot/TriviaBot.vcxproj b/TriviaBot/TriviaBot.vcxproj
index 68e3f0c..1228b4a 100644
--- a/TriviaBot/TriviaBot.vcxproj
+++ b/TriviaBot/TriviaBot.vcxproj
@@ -69,16 +69,18 @@
- C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\curl\include;$(IncludePath)
- C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3\x64;$(LibraryPath)
+ C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\curl\include;$(IncludePath)
+ C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0\libs;$(LibraryPath)
+ C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\beast\include;$(SourcePath)
C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\curl\include;$(IncludePath)
C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3\x64;$(LibraryPath)
- C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3\x86;$(LibraryPath)
+ C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3\x86;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0\libs;$(LibraryPath)
C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\curl\include;$(IncludePath)
+ C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\beast\include;$(SourcePath)
C:\Users\Jack\Documents\Visual Studio 2015\Projects\TriviaBot\lib\sqlite3\x86;$(LibraryPath)
@@ -89,11 +91,14 @@
Level3
Disabled
true
- _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;CURL_STATICLIB;%(PreprocessorDefinitions)
+ C:\boost_1_61_0;C:\OpenSSL-Win64\include;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\liboauth\include;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\curl\include;C:\buildcurl\third-party\libcurl\include;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\websocketpp;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\beast\include;%(AdditionalIncludeDirectories)
+ -D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)
- sqlite3.lib;%(AdditionalDependencies)
+ libcurl.lib;sqlite3.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies)
/SUBSYSTEM:CONSOLE %(AdditionalOptions)
+ C:\buildcurl\third-party\libcurl\lib\dll-release-x64;C:\OpenSSL-Win32\lib;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0\stage\lib;%(AdditionalLibraryDirectories)
@@ -101,11 +106,14 @@
Level4
Disabled
true
- _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;CURL_STATICLIB;%(PreprocessorDefinitions)
+ C:\boost_1_61_0;C:\OpenSSL-Win64\include;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\liboauth\include;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\curl\include;C:\buildcurl\third-party\libcurl\include;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\websocketpp;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\sqlite3;%(AdditionalIncludeDirectories)
+ -D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)
- sqlite3.lib;%(AdditionalDependencies)
+ libcurl.lib;sqlite3.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies)
/SUBSYSTEM:CONSOLE %(AdditionalOptions)
+ C:\buildcurl\third-party\libcurl\lib\dll-release-x64;C:\OpenSSL-Win64\lib;C:\boost_1_61_0\lib64-msvc-14.0;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\sqlite3\x64;%(AdditionalLibraryDirectories)
@@ -116,12 +124,14 @@
true
true
_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0;C:\OpenSSL-Win32\include;%(AdditionalIncludeDirectories)
true
true
- sqlite3.lib;%(AdditionalDependencies)
+ sqlite3.lib;libeay32.lib;%(AdditionalDependencies)
/SUBSYSTEM:CONSOLE %(AdditionalOptions)
+ C:\OpenSSL-Win32\lib;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0\libs;%(AdditionalLibraryDirectories)
@@ -132,27 +142,37 @@
true
true
_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0;C:\OpenSSL-Win32\include;%(AdditionalIncludeDirectories)
true
true
- sqlite3.lib;%(AdditionalDependencies)
+ sqlite3.lib;libeay32.lib;%(AdditionalDependencies)
/SUBSYSTEM:CONSOLE %(AdditionalOptions)
+ C:\OpenSSL-Win32\lib;C:\Users\Jack\Documents\GitHubVisualStudio\TriviaDiscord\lib\boost_1_61_0\libs;%(AdditionalLibraryDirectories)
-
+
+
+
+ -D_SCL_SECURE_NO_WARNINGS
+ %(AdditionalOptions)
+ -D_SCL_SECURE_NO_WARNINGS
+ %(AdditionalOptions)
+
+
+ -D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)
+
-
-
-
-
-
+
+
+
diff --git a/TriviaBot/TriviaBot.vcxproj.filters b/TriviaBot/TriviaBot.vcxproj.filters
index 7e75dc2..243aedd 100644
--- a/TriviaBot/TriviaBot.vcxproj.filters
+++ b/TriviaBot/TriviaBot.vcxproj.filters
@@ -21,19 +21,13 @@
Header Files
-
+
Header Files
-
+
Header Files
-
- Header Files
-
-
- Header Files
-
-
+
Header Files
@@ -44,5 +38,14 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
\ No newline at end of file
diff --git a/TriviaBot/bot/ClientConnection.hpp b/TriviaBot/bot/ClientConnection.hpp
new file mode 100644
index 0000000..4983b95
--- /dev/null
+++ b/TriviaBot/bot/ClientConnection.hpp
@@ -0,0 +1,134 @@
+#include
+
+#include "json/json.hpp"
+
+#include
+
+#include
+
+#include "ProtocolHandler.h"
+
+typedef websocketpp::client client;
+
+using websocketpp::lib::bind;
+
+// pull out the type of messages sent by our config
+typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr;
+typedef websocketpp::lib::shared_ptr context_ptr;
+typedef client::connection_ptr connection_ptr;
+
+class ClientConnection {
+public:
+ typedef ClientConnection type;
+
+ ClientConnection() {
+ m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
+
+ m_endpoint.set_access_channels(websocketpp::log::alevel::app | websocketpp::log::alevel::connect);
+ m_endpoint.set_error_channels(websocketpp::log::elevel::all);
+
+ // Initialize ASIO
+ m_endpoint.init_asio();
+
+ // Register our handlers
+ m_endpoint.set_socket_init_handler(bind(
+ &type::on_socket_init,
+ this,
+ websocketpp::lib::placeholders::_1
+ ));
+ m_endpoint.set_tls_init_handler(bind(
+ &type::on_tls_init,
+ this,
+ websocketpp::lib::placeholders::_1
+ ));
+ m_endpoint.set_message_handler(bind(
+ &type::on_message,
+ this,
+ websocketpp::lib::placeholders::_1,
+ websocketpp::lib::placeholders::_2
+ ));
+ m_endpoint.set_open_handler(bind(
+ &type::on_open,
+ this,
+ websocketpp::lib::placeholders::_1
+ ));
+ m_endpoint.set_close_handler(bind(
+ &type::on_close,
+ this,
+ websocketpp::lib::placeholders::_1
+ ));
+ m_endpoint.set_fail_handler(bind(
+ &type::on_fail,
+ this,
+ websocketpp::lib::placeholders::_1
+ ));
+ }
+
+ void start(std::string uri) {
+ websocketpp::lib::error_code ec;
+ client::connection_ptr con = m_endpoint.get_connection(uri, ec);
+
+ if (ec) {
+ m_endpoint.get_alog().write(websocketpp::log::alevel::app, ec.message());
+ return;
+ }
+
+ m_endpoint.connect(con);
+
+ m_endpoint.run();
+ }
+
+ void on_socket_init(websocketpp::connection_hdl) {
+ m_endpoint.get_alog().write(websocketpp::log::alevel::app,
+ "Socket intialised.");
+ }
+
+ context_ptr on_tls_init(websocketpp::connection_hdl) {
+ context_ptr ctx = std::make_shared(boost::asio::ssl::context::sslv23);
+
+ try {
+ ctx->set_options(boost::asio::ssl::context::default_workarounds |
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::no_sslv3 |
+ boost::asio::ssl::context::single_dh_use);
+ }
+ catch (std::exception& e) {
+ std::cout << "Error in context pointer: " << e.what() << std::endl;
+ }
+ return ctx;
+ }
+
+ void on_fail(websocketpp::connection_hdl hdl) {
+ client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);
+
+ m_endpoint.get_elog().write(websocketpp::log::elevel::warn,
+ "Fail handler: \n" +
+ std::to_string(con->get_state()) + "\n" +
+ std::to_string(con->get_local_close_code()) + "\n" +
+ con->get_local_close_reason() + "\n" +
+ std::to_string(con->get_remote_close_code()) + "\n" +
+ con->get_remote_close_reason() + "\n" +
+ std::to_string(con->get_ec().value()) + " - " + con->get_ec().message() + "\n");
+ }
+
+ void on_open(websocketpp::connection_hdl &hdl) {
+ //ProtocolHandler::handle_data();
+ //pHandler.handle_data("jjj", m_endpoint, hdl);
+ }
+
+ void on_message(websocketpp::connection_hdl &hdl, message_ptr message) {
+ if (message->get_opcode() != websocketpp::frame::opcode::text) {
+ std::cout << "<< " << websocketpp::utility::to_hex(message->get_payload()) << std::endl;
+ return;
+ }
+
+ pHandler.handle_data(message->get_payload(), m_endpoint, hdl);
+ }
+
+ void on_close(websocketpp::connection_hdl) {
+ std::cout << "Closed." << std::endl;
+ }
+private:
+ client m_endpoint;
+ ProtocolHandler pHandler;
+};
\ No newline at end of file
diff --git a/TriviaBot/bot/ProtocolHandler.h b/TriviaBot/bot/ProtocolHandler.h
new file mode 100644
index 0000000..e5435d7
--- /dev/null
+++ b/TriviaBot/bot/ProtocolHandler.h
@@ -0,0 +1,168 @@
+#include "json/json.hpp"
+
+#include
+#include
+
+typedef websocketpp::client client;
+using json = nlohmann::json;
+
+/************ Opcodes **************************************************************************************************
+* Code | Name | Description *
+* --------------------------------------------------------------------------------------------------------------------------*
+* 0 | Dispatch | dispatches an event *
+* 1 | Heartbeat | used for ping checking *
+* 2 | Identify | used for client handshake *
+* 3 | Status Update | used to update the client status *
+* 4 | Voice State Update | used to join/move/leave voice channels *
+* 5 | Voice Server Ping | used for voice ping checking *
+* 6 | Resume | used to resume a closed connection *
+* 7 | Reconnect | used to tell clients to reconnect to the gateway *
+* 8 | Request Guild Members | used to request guild members *
+* 9 | Invalid Session | used to notify client they have an invalid session id *
+* 10 | Hello | sent immediately after connecting, contains heartbeat and server debug information *
+* 11 | Heartback ACK | sent immediately following a client heartbeat that was received *
+*****************************************************************************************************************************/
+
+class ProtocolHandler {
+public:
+ ProtocolHandler() {
+ last_seq = 0;
+ }
+
+ void 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:
+ c.get_alog().write(websocketpp::log::alevel::app, "Heartbeat acknowledged.");
+ break;
+ default:
+ std::cout << data << std::endl;
+ }
+ }
+
+ void heartbeat(websocketpp::lib::error_code const & ec, client *c, websocketpp::connection_hdl *hdl) {
+ json heartbeat = {
+ { "op", 1 },
+ { "d", last_seq }
+ };
+
+ c->send(*hdl, heartbeat.dump(), websocketpp::frame::opcode::text);
+
+ c->set_timer(heartbeat_interval, websocketpp::lib::bind(
+ &ProtocolHandler::heartbeat,
+ this,
+ websocketpp::lib::placeholders::_1,
+ c,
+ hdl
+ ));
+
+ c->get_alog().write(websocketpp::log::alevel::app, "Sent heartbeat. (seq: " + std::to_string(last_seq) + ")");
+ }
+
+ void 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.set_timer(heartbeat_interval, websocketpp::lib::bind(
+ &ProtocolHandler::heartbeat,
+ this,
+ websocketpp::lib::placeholders::_1,
+ &c,
+ &hdl
+ ));
+
+ identify(c, hdl);
+ }
+
+ void on_dispatch(json decoded, client &c, websocketpp::connection_hdl &hdl) {
+ last_seq = decoded["s"];
+ 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 = data["user"];
+
+ std::string username = user_object["username"];
+ std::string discriminator = user_object["discriminator"];
+ c.get_alog().write(websocketpp::log::alevel::app, "Sign-on confirmed. (@" + username + "#" + discriminator + ")");
+
+ c.get_alog().write(websocketpp::log::alevel::app, data.dump(4));
+ }
+ else if (event_name == "GUILD_CREATE") {
+ std::string guild_name = data["name"];
+ std::string guild_id = data["id"];
+
+ guilds[guild_id] = data;
+
+ for (json &element : data["channels"]) {
+ if (element["type"] == "text"){
+ channels[element["id"]] = element;
+ }
+ }
+
+ c.get_alog().write(websocketpp::log::alevel::app, "Guild joined: " + guild_name);
+ }
+ else if (event_name == "TYPING_START") {}
+ else if (event_name == "MESSAGE_CREATE") {
+ std::string message = data["content"];
+ json channel = channels[data["channel_id"]];
+ std::string channel_name = channel["name"];
+ std::string channel_id = data["channel_id"];
+
+ c.get_alog().write(websocketpp::log::alevel::app, "Message received: " + message + " $" + channel_name + " ^" + channel_id);
+
+ if (message == "`trivia" || message == "`t") {
+
+ }
+ }
+ //c.get_alog().write(websocketpp::log::alevel::app, decoded.dump(2));
+ }
+
+ json create_message(json user, std::string channel_id) {
+
+ }
+
+ void identify(client &c, websocketpp::connection_hdl &hdl) {
+ json identify = {
+ { "op", 2 },
+ { "d", {
+ { "token", bot_token },
+ { "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);
+ c.get_alog().write(websocketpp::log::alevel::app, "Sent identify payload.");
+ }
+
+private:
+ int last_seq;
+ int heartbeat_interval;
+
+ const int protocol_version = 5;
+ const std::string bot_token = "MTk5NjU3MDk1MjU4MTc3NTM5.ClyBNQ.15qTa-XBKRtGNMMYeXCrU50GhWE";
+
+ std::map guilds;
+ std::map channels;
+ json user_object;
+};
\ No newline at end of file
diff --git a/TriviaBot/bot/Source.cpp b/TriviaBot/bot/Source.cpp
new file mode 100644
index 0000000..d182226
--- /dev/null
+++ b/TriviaBot/bot/Source.cpp
@@ -0,0 +1,22 @@
+#include "ClientConnection.hpp"
+
+int main(int argc, char* argv[]) {
+ std::string uri = "wss://gateway.discord.gg/?v=5&encoding=json";
+ //std::string uri = "wss://echo.websocket.org/";
+
+ try {
+ ClientConnection endpoint;
+ endpoint.start(uri);
+ }
+ catch (const std::exception & e) {
+ std::cout << e.what() << std::endl;
+ }
+ catch (websocketpp::lib::error_code e) {
+ std::cout << e.message() << std::endl;
+ }
+ catch (...) {
+ std::cout << "other exception" << std::endl;
+ }
+
+ std::getchar();
+}
\ No newline at end of file
diff --git a/TriviaBot/bot/TriviaBot.cpp b/TriviaBot/bot/TriviaBot.cpp
index f4eea67..e69de29 100644
--- a/TriviaBot/bot/TriviaBot.cpp
+++ b/TriviaBot/bot/TriviaBot.cpp
@@ -1,4 +0,0 @@
-#include
-
-int main() {
-}
diff --git a/TriviaBot/bot/http/HTTPHelper.cpp b/TriviaBot/bot/http/HTTPHelper.cpp
new file mode 100644
index 0000000..4eccb9c
--- /dev/null
+++ b/TriviaBot/bot/http/HTTPHelper.cpp
@@ -0,0 +1,44 @@
+#include "HTTPHelper.hpp"
+
+size_t HTTPHelper::data_write(void* buf, size_t size, size_t nmemb, void* userp) {
+ if (userp) {
+ std::ostream& os = *static_cast(userp);
+ std::streamsize len = size * nmemb;
+ if (os.write(static_cast(buf), len)) {
+ return len;
+ }
+ }
+
+ return 0;
+}
+
+CURLcode HTTPHelper::curl_read(const std::string& url, std::ostream& os, long timeout = 30) {
+ CURLcode code(CURLE_FAILED_INIT);
+ CURL* curl = curl_easy_init();
+
+ if (curl) {
+ if (CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &data_write))
+ && CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L))
+ && CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L))
+ && CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FILE, &os))
+ && CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout))
+ && CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_URL, url.c_str()))) {
+ code = curl_easy_perform(curl);
+ }
+ curl_easy_cleanup(curl);
+ }
+ return code;
+}
+
+std::string HTTPHelper::read_url(std::string url) {
+ std::ostringstream oss;
+ std::string html = "ERROR";
+ if (CURLE_OK == curl_read("http://www.google.co.uk/", oss)) {
+ html = oss.str();
+ }
+ else {
+ std::cout << "CURL error" << std::endl;
+ }
+
+ return html;
+}
\ No newline at end of file
diff --git a/TriviaBot/bot/http/HTTPHelper.hpp b/TriviaBot/bot/http/HTTPHelper.hpp
new file mode 100644
index 0000000..6556765
--- /dev/null
+++ b/TriviaBot/bot/http/HTTPHelper.hpp
@@ -0,0 +1,14 @@
+#include
+#include
+#include
+#include
+
+// callback function writes data to a std::ostream
+class HTTPHelper {
+public:
+ static std::string read_url(std::string url);
+
+private:
+ static size_t data_write(void* buf, size_t size, size_t nmemb, void* userp);
+ static CURLcode curl_read(const std::string& url, std::ostream& os, long timeout);
+};
\ No newline at end of file
diff --git a/TriviaBot/bot/json/json.hpp b/TriviaBot/bot/json/json.hpp
new file mode 100644
index 0000000..ba7d821
--- /dev/null
+++ b/TriviaBot/bot/json/json.hpp
@@ -0,0 +1,10090 @@
+/*
+ __ _____ _____ _____
+ __| | __| | | | JSON for Modern C++
+| | |__ | | | | | | version 2.0.1
+|_____|_____|_____|_|___| https://github.com/nlohmann/json
+
+Licensed under the MIT License .
+Copyright (c) 2013-2016 Niels Lohmann .
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef NLOHMANN_JSON_HPP
+#define NLOHMANN_JSON_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include