diff options
Diffstat (limited to 'discord')
-rw-r--r-- | discord/discord.cpp | 24 | ||||
-rw-r--r-- | discord/discord.hpp | 4 | ||||
-rw-r--r-- | discord/http.cpp | 156 | ||||
-rw-r--r-- | discord/http.hpp | 37 | ||||
-rw-r--r-- | discord/httpclient.cpp | 136 | ||||
-rw-r--r-- | discord/httpclient.hpp | 37 |
6 files changed, 187 insertions, 207 deletions
diff --git a/discord/discord.cpp b/discord/discord.cpp index 5d20553..531651f 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -101,7 +101,7 @@ std::set<Snowflake> DiscordClient::GetMessagesForChannel(Snowflake id) const { void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback) { sigc::signal<void, std::optional<InviteData>> signal; signal.connect(callback); - m_http.MakeGET("/invites/" + code + "?with_counts=true", [this, callback](cpr::Response r) { + m_http.MakeGET("/invites/" + code + "?with_counts=true", [this, callback](http::response_type r) { if (!CheckCode(r)) { if (r.status_code == 404) callback(std::nullopt); @@ -114,7 +114,7 @@ void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional< void DiscordClient::FetchMessagesInChannel(Snowflake id, std::function<void(const std::vector<Snowflake> &)> cb) { std::string path = "/channels/" + std::to_string(id) + "/messages?limit=50"; - m_http.MakeGET(path, [this, id, cb](cpr::Response r) { + m_http.MakeGET(path, [this, id, cb](const http::response_type &r) { if (!CheckCode(r)) return; std::vector<Message> msgs; @@ -137,7 +137,7 @@ void DiscordClient::FetchMessagesInChannel(Snowflake id, std::function<void(cons void DiscordClient::FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, std::function<void(const std::vector<Snowflake> &)> cb) { std::string path = "/channels/" + std::to_string(channel_id) + "/messages?limit=50&before=" + std::to_string(before_id); - m_http.MakeGET(path, [this, channel_id, cb](cpr::Response r) { + m_http.MakeGET(path, [this, channel_id, cb](http::response_type r) { if (!CheckCode(r)) return; std::vector<Message> msgs; @@ -453,7 +453,7 @@ void DiscordClient::SetGuildName(Snowflake id, const Glib::ustring &name, sigc:: obj.Name = name; sigc::signal<void, bool> signal; signal.connect(callback); - m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, signal](const cpr::Response &r) { + m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, signal](const http::response_type &r) { const auto success = r.status_code == 200; signal.emit(success); }); @@ -468,7 +468,7 @@ void DiscordClient::SetGuildIcon(Snowflake id, const std::string &data, sigc::sl obj.IconData = data; sigc::signal<void, bool> signal; signal.connect(callback); - m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, signal](const cpr::Response &r) { + m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, signal](const http::response_type &r) { const auto success = r.status_code == 200; signal.emit(success); }); @@ -481,7 +481,7 @@ void DiscordClient::UnbanUser(Snowflake guild_id, Snowflake user_id) { void DiscordClient::UnbanUser(Snowflake guild_id, Snowflake user_id, sigc::slot<void(bool success)> callback) { sigc::signal<void, bool> signal; signal.connect(callback); - m_http.MakeDELETE("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), [this, callback](const cpr::Response &response) { + m_http.MakeDELETE("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), [this, callback](const http::response_type &response) { callback(response.status_code == 204); }); } @@ -493,7 +493,7 @@ void DiscordClient::DeleteInvite(const std::string &code) { void DiscordClient::DeleteInvite(const std::string &code, sigc::slot<void(bool success)> callback) { sigc::signal<void, bool> signal; signal.connect(callback); - m_http.MakeDELETE("/invites/" + code, [this, callback](const cpr::Response &response) { + m_http.MakeDELETE("/invites/" + code, [this, callback](const http::response_type &response) { callback(CheckCode(response)); }); } @@ -505,7 +505,7 @@ std::vector<BanData> DiscordClient::GetBansInGuild(Snowflake guild_id) { void DiscordClient::FetchGuildBan(Snowflake guild_id, Snowflake user_id, sigc::slot<void(BanData)> callback) { sigc::signal<void, BanData> signal; signal.connect(callback); - m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), [this, callback, guild_id](const cpr::Response &response) { + m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), [this, callback, guild_id](const http::response_type &response) { if (!CheckCode(response)) return; auto ban = nlohmann::json::parse(response.text).get<BanData>(); m_store.SetBan(guild_id, ban.User.ID, ban); @@ -517,7 +517,7 @@ void DiscordClient::FetchGuildBan(Snowflake guild_id, Snowflake user_id, sigc::s void DiscordClient::FetchGuildBans(Snowflake guild_id, sigc::slot<void(std::vector<BanData>)> callback) { sigc::signal<void, std::vector<BanData>> signal; signal.connect(callback); - m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/bans", [this, callback, guild_id](const cpr::Response &response) { + m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/bans", [this, callback, guild_id](const http::response_type &response) { if (!CheckCode(response)) return; auto bans = nlohmann::json::parse(response.text).get<std::vector<BanData>>(); m_store.BeginTransaction(); @@ -533,7 +533,7 @@ void DiscordClient::FetchGuildBans(Snowflake guild_id, sigc::slot<void(std::vect void DiscordClient::FetchGuildInvites(Snowflake guild_id, sigc::slot<void(std::vector<InviteData>)> callback) { sigc::signal<void, std::vector<InviteData>> signal; signal.connect(callback); - m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/invites", [this, callback, guild_id](const cpr::Response &response) { + m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/invites", [this, callback, guild_id](const http::response_type &response) { // store? if (!CheckCode(response)) return; auto invites = nlohmann::json::parse(response.text).get<std::vector<InviteData>>(); @@ -1232,9 +1232,9 @@ void DiscordClient::HandleSocketOpen() { void DiscordClient::HandleSocketClose(uint16_t code) { } -bool DiscordClient::CheckCode(const cpr::Response &r) { +bool DiscordClient::CheckCode(const http::response_type &r) { if (r.status_code >= 300 || r.error) { - fprintf(stderr, "api request to %s failed with status code %d\n", r.url.c_str(), r.status_code); + fprintf(stderr, "api request to %s failed with status code %d: %s\n", r.url.c_str(), r.status_code, r.error_string.c_str()); return false; } diff --git a/discord/discord.hpp b/discord/discord.hpp index 11315f9..a6f5d99 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -1,6 +1,6 @@ #pragma once #include "websocket.hpp" -#include "http.hpp" +#include "httpclient.hpp" #include "objects.hpp" #include "store.hpp" #include <sigc++/sigc++.h> @@ -175,7 +175,7 @@ private: void HandleSocketOpen(); void HandleSocketClose(uint16_t code); - bool CheckCode(const cpr::Response &r); + bool CheckCode(const http::response_type &r); void StoreMessageData(Message &msg); diff --git a/discord/http.cpp b/discord/http.cpp deleted file mode 100644 index a435aef..0000000 --- a/discord/http.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "http.hpp" - -//#define USE_LOCAL_PROXY -HTTPClient::HTTPClient(std::string api_base) - : m_api_base(api_base) { - m_dispatcher.connect(sigc::mem_fun(*this, &HTTPClient::RunCallbacks)); -} - -void HTTPClient::SetUserAgent(std::string agent) { - m_agent = agent; -} - -void HTTPClient::SetAuth(std::string auth) { - m_authorization = auth; -} - -void HTTPClient::MakeDELETE(std::string path, std::function<void(cpr::Response r)> cb) { - printf("DELETE %s\n", path.c_str()); - auto url = cpr::Url { m_api_base + path }; - auto headers = cpr::Header { - { "Authorization", m_authorization }, - }; - auto ua = cpr::UserAgent {m_agent != "" ? m_agent : "Abaddon" }; - -#ifdef USE_LOCAL_PROXY - m_futures.push_back(cpr::DeleteCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, ua, - cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } }, - cpr::VerifySsl { false })); -#else - m_futures.push_back(cpr::DeleteCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, ua)); -#endif -} - -void HTTPClient::MakePATCH(std::string path, std::string payload, std::function<void(cpr::Response r)> cb) { - printf("PATCH %s\n", path.c_str()); - auto url = cpr::Url { m_api_base + path }; - auto headers = cpr::Header { - { "Authorization", m_authorization }, - { "Content-Type", "application/json" }, - }; - auto ua = cpr::UserAgent { m_agent != "" ? m_agent : "Abaddon" }; - - auto body = cpr::Body { payload }; -#ifdef USE_LOCAL_PROXY - m_futures.push_back(cpr::PatchCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, body, ua, - cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } }, - cpr::VerifySsl { false })); -#else - m_futures.push_back(cpr::PatchCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, body, ua)); -#endif -} - -void HTTPClient::MakePOST(std::string path, std::string payload, std::function<void(cpr::Response r)> cb) { - printf("POST %s\n", path.c_str()); - auto url = cpr::Url { m_api_base + path }; - auto headers = cpr::Header { - { "Authorization", m_authorization }, - { "Content-Type", "application/json" }, - }; - auto ua = cpr::UserAgent { m_agent != "" ? m_agent : "Abaddon" }; - - auto body = cpr::Body { payload }; -#ifdef USE_LOCAL_PROXY - m_futures.push_back(cpr::PostCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, body, ua, - cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } }, - cpr::VerifySsl { false })); -#else - m_futures.push_back(cpr::PostCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, body, ua)); -#endif -} - -void HTTPClient::MakePUT(std::string path, std::string payload, std::function<void(cpr::Response r)> cb) { - printf("PUT %s\n", path.c_str()); - auto url = cpr::Url { m_api_base + path }; - auto headers = cpr::Header { - { "Authorization", m_authorization }, - { "Content-Type", "application/json" }, - }; - auto ua = cpr::UserAgent { m_agent != "" ? m_agent : "Abaddon" }; - - auto body = cpr::Body { payload }; -#ifdef USE_LOCAL_PROXY - m_futures.push_back(cpr::PutCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, body, ua, - cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } }, - cpr::VerifySsl { false })); -#else - m_futures.push_back(cpr::PutCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, body, ua)); -#endif -} - -void HTTPClient::MakeGET(std::string path, std::function<void(cpr::Response r)> cb) { - printf("GET %s\n", path.c_str()); - auto url = cpr::Url { m_api_base + path }; - auto headers = cpr::Header { - { "Authorization", m_authorization }, - { "Content-Type", "application/json" }, - }; - auto ua = cpr::UserAgent { m_agent != "" ? m_agent : "Abaddon" }; - - auto x = cpr::UserAgent {}; -#ifdef USE_LOCAL_PROXY - m_futures.push_back(cpr::GetCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, ua, - cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } }, - cpr::VerifySsl { false })); -#else - m_futures.push_back(cpr::GetCallback( - std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb), - url, headers, ua)); -#endif -} - -void HTTPClient::CleanupFutures() { - for (auto it = m_futures.begin(); it != m_futures.end();) { - if (it->wait_for(std::chrono::seconds(0)) == std::future_status::ready) - it = m_futures.erase(it); - else - it++; - } -} - -void HTTPClient::RunCallbacks() { - m_mutex.lock(); - m_queue.front()(); - m_queue.pop(); - m_mutex.unlock(); -} - -void HTTPClient::OnResponse(cpr::Response r, std::function<void(cpr::Response r)> cb) { - CleanupFutures(); - try { - m_mutex.lock(); - m_queue.push([this, r, cb] { cb(r); }); - m_dispatcher.emit(); - m_mutex.unlock(); - } catch (std::exception &e) { - fprintf(stderr, "error handling response (%s, code %d): %s\n", r.url.c_str(), r.status_code, e.what()); - } -} diff --git a/discord/http.hpp b/discord/http.hpp deleted file mode 100644 index b664c86..0000000 --- a/discord/http.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include <cpr/cpr.h> -#include <functional> -#include <future> -#include <string> -#include <unordered_map> -#include <memory> -#include <mutex> -#include <queue> -#include <glibmm.h> - -class HTTPClient { -public: - HTTPClient(std::string api_base); - - void SetUserAgent(std::string agent); - void SetAuth(std::string auth); - void MakeDELETE(std::string path, std::function<void(cpr::Response r)> cb); - void MakeGET(std::string path, std::function<void(cpr::Response r)> cb); - void MakePATCH(std::string path, std::string payload, std::function<void(cpr::Response r)> cb); - void MakePOST(std::string path, std::string payload, std::function<void(cpr::Response r)> cb); - void MakePUT(std::string path, std::string payload, std::function<void(cpr::Response r)> cb); - -private: - void OnResponse(cpr::Response r, std::function<void(cpr::Response r)> cb); - void CleanupFutures(); - - mutable std::mutex m_mutex; - Glib::Dispatcher m_dispatcher; - std::queue<std::function<void()>> m_queue; - void RunCallbacks(); - - std::vector<std::future<void>> m_futures; - std::string m_api_base; - std::string m_authorization; - std::string m_agent; -}; diff --git a/discord/httpclient.cpp b/discord/httpclient.cpp new file mode 100644 index 0000000..dc94566 --- /dev/null +++ b/discord/httpclient.cpp @@ -0,0 +1,136 @@ +#include "httpclient.hpp" +#include "httpclient.hpp" + +//#define USE_LOCAL_PROXY +HTTPClient::HTTPClient(std::string api_base) + : m_api_base(api_base) { + m_dispatcher.connect(sigc::mem_fun(*this, &HTTPClient::RunCallbacks)); +} + +void HTTPClient::SetUserAgent(std::string agent) { + m_agent = agent; +} + +void HTTPClient::SetAuth(std::string auth) { + m_authorization = auth; +} + +void HTTPClient::MakeDELETE(const std::string &path, std::function<void(http::response_type r)> cb) { + printf("DELETE %s\n", path.c_str()); + m_futures.push_back(std::async(std::launch::async, [this, path, cb] { + http::request req(http::REQUEST_DELETE, m_api_base + path); + req.set_header("Authorization", m_authorization); + req.set_user_agent(m_agent != "" ? m_agent : "Abaddon"); +#ifdef USE_LOCAL_PROXY + req.set_proxy("http://127.0.0.1:8888"); + req.set_verify_ssl(false); +#endif + + auto res = req.execute(); + + OnResponse(res, cb); + })); +} + +void HTTPClient::MakePATCH(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb) { + printf("PATCH %s\n", path.c_str()); + m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] { + http::request req(http::REQUEST_PATCH, m_api_base + path); + req.set_header("Authorization", m_authorization); + req.set_header("Content-Type", "application/json"); + req.set_user_agent(m_agent != "" ? m_agent : "Abaddon"); + req.set_body(payload); +#ifdef USE_LOCAL_PROXY + req.set_proxy("http://127.0.0.1:8888"); + req.set_verify_ssl(false); +#endif + + auto res = req.execute(); + + OnResponse(res, cb); + })); +} + +void HTTPClient::MakePOST(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb) { + printf("POST %s\n", path.c_str()); + m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] { + http::request req(http::REQUEST_POST, m_api_base + path); + req.set_header("Authorization", m_authorization); + req.set_header("Content-Type", "application/json"); + req.set_user_agent(m_agent != "" ? m_agent : "Abaddon"); + req.set_body(payload); +#ifdef USE_LOCAL_PROXY + req.set_proxy("http://127.0.0.1:8888"); + req.set_verify_ssl(false); +#endif + + auto res = req.execute(); + + OnResponse(res, cb); + })); +} + +void HTTPClient::MakePUT(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb) { + printf("PUT %s\n", path.c_str()); + m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] { + http::request req(http::REQUEST_PUT, m_api_base + path); + req.set_header("Authorization", m_authorization); + req.set_header("Content-Type", "application/json"); + req.set_user_agent(m_agent != "" ? m_agent : "Abaddon"); + req.set_body(payload); +#ifdef USE_LOCAL_PROXY + req.set_proxy("http://127.0.0.1:8888"); + req.set_verify_ssl(false); +#endif + + auto res = req.execute(); + + OnResponse(res, cb); + })); +} + +void HTTPClient::MakeGET(const std::string &path, std::function<void(http::response_type r)> cb) { + printf("GET %s\n", path.c_str()); + m_futures.push_back(std::async(std::launch::async, [this, path, cb] { + http::request req(http::REQUEST_GET, m_api_base + path); + req.set_header("Authorization", m_authorization); + req.set_header("Content-Type", "application/json"); + req.set_user_agent(m_agent != "" ? m_agent : "Abaddon"); +#ifdef USE_LOCAL_PROXY + req.set_proxy("http://127.0.0.1:8888"); + req.set_verify_ssl(false); +#endif + + auto res = req.execute(); + + OnResponse(res, cb); + })); +} + +void HTTPClient::CleanupFutures() { + for (auto it = m_futures.begin(); it != m_futures.end();) { + if (it->wait_for(std::chrono::seconds(0)) == std::future_status::ready) + it = m_futures.erase(it); + else + it++; + } +} + +void HTTPClient::RunCallbacks() { + m_mutex.lock(); + m_queue.front()(); + m_queue.pop(); + m_mutex.unlock(); +} + +void HTTPClient::OnResponse(const http::response_type &r, std::function<void(http::response_type r)> cb) { + CleanupFutures(); + try { + m_mutex.lock(); + m_queue.push([this, r, cb] { cb(r); }); + m_dispatcher.emit(); + m_mutex.unlock(); + } catch (const std::exception &e) { + fprintf(stderr, "error handling response (%s, code %d): %s\n", r.url.c_str(), r.status_code, e.what()); + } +} diff --git a/discord/httpclient.hpp b/discord/httpclient.hpp new file mode 100644 index 0000000..8038334 --- /dev/null +++ b/discord/httpclient.hpp @@ -0,0 +1,37 @@ +#pragma once +#include <functional> +#include <future> +#include <string> +#include <unordered_map> +#include <memory> +#include <mutex> +#include <queue> +#include <glibmm.h> +#include "../http.hpp" + +class HTTPClient { +public: + HTTPClient(std::string api_base); + + void SetUserAgent(std::string agent); + void SetAuth(std::string auth); + void MakeDELETE(const std::string &path, std::function<void(http::response_type r)> cb); + void MakeGET(const std::string &path, std::function<void(http::response_type r)> cb); + void MakePATCH(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb); + void MakePOST(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb); + void MakePUT(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb); + +private: + void OnResponse(const http::response_type &r, std::function<void(http::response_type r)> cb); + void CleanupFutures(); + + mutable std::mutex m_mutex; + Glib::Dispatcher m_dispatcher; + std::queue<std::function<void()>> m_queue; + void RunCallbacks(); + + std::vector<std::future<void>> m_futures; + std::string m_api_base; + std::string m_authorization; + std::string m_agent; +}; |