Add gateway functionality
This commit is contained in:
134
TriviaBot/bot/ClientConnection.hpp
Normal file
134
TriviaBot/bot/ClientConnection.hpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include <websocketpp/config/asio_client.hpp>
|
||||
|
||||
#include "json/json.hpp"
|
||||
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "ProtocolHandler.h"
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_tls_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<boost::asio::ssl::context> 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<context_ptr>(
|
||||
&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>(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;
|
||||
};
|
168
TriviaBot/bot/ProtocolHandler.h
Normal file
168
TriviaBot/bot/ProtocolHandler.h
Normal file
@ -0,0 +1,168 @@
|
||||
#include "json/json.hpp"
|
||||
|
||||
#include <websocketpp/client.hpp>
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_tls_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<std::string, json> guilds;
|
||||
std::map<std::string, json> channels;
|
||||
json user_object;
|
||||
};
|
22
TriviaBot/bot/Source.cpp
Normal file
22
TriviaBot/bot/Source.cpp
Normal file
@ -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();
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
}
|
||||
|
44
TriviaBot/bot/http/HTTPHelper.cpp
Normal file
44
TriviaBot/bot/http/HTTPHelper.cpp
Normal file
@ -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<std::ostream*>(userp);
|
||||
std::streamsize len = size * nmemb;
|
||||
if (os.write(static_cast<char*>(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;
|
||||
}
|
14
TriviaBot/bot/http/HTTPHelper.hpp
Normal file
14
TriviaBot/bot/http/HTTPHelper.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <curl/curl.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// 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);
|
||||
};
|
10090
TriviaBot/bot/json/json.hpp
Normal file
10090
TriviaBot/bot/json/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Submodule TriviaBot/bot/simplewebsocket deleted from c284e5a282
Reference in New Issue
Block a user