forked from OpenGamers/abaddon
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Fetch dependencies
|
- name: Fetch dependencies
|
||||||
uses: lukka/run-vcpkg@main
|
uses: lukka/run-vcpkg@main
|
||||||
with:
|
with:
|
||||||
vcpkgArguments: gtkmm nlohmann-json cpr zlib sqlite3 glibmm openssl ixwebsocket
|
vcpkgArguments: gtkmm nlohmann-json zlib sqlite3 glibmm openssl ixwebsocket curl
|
||||||
vcpkgDirectory: ${{ github.workspace }}/ci/vcpkg/
|
vcpkgDirectory: ${{ github.workspace }}/ci/vcpkg/
|
||||||
vcpkgTriplet: x64-windows
|
vcpkgTriplet: x64-windows
|
||||||
|
|
||||||
@@ -71,7 +71,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
brew install gtkmm3
|
brew install gtkmm3
|
||||||
brew install nlohmann-json
|
brew install nlohmann-json
|
||||||
brew install cpr
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: lukka/run-cmake@main
|
uses: lukka/run-cmake@main
|
||||||
@@ -110,15 +109,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir deps
|
mkdir deps
|
||||||
cd deps
|
cd deps
|
||||||
git clone https://github.com/whoshuu/cpr
|
|
||||||
cd cpr
|
|
||||||
git checkout 9ff9cef6c794ec3d52d94a62ca791e2f2babca45
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
cd ../..
|
|
||||||
git clone https://github.com/nlohmann/json
|
git clone https://github.com/nlohmann/json
|
||||||
cd json
|
cd json
|
||||||
git checkout db78ac1d7716f56fc9f1b030b715f872f93964e4
|
git checkout db78ac1d7716f56fc9f1b030b715f872f93964e4
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ set(USE_OPEN_SSL TRUE)
|
|||||||
|
|
||||||
find_package(nlohmann_json REQUIRED)
|
find_package(nlohmann_json REQUIRED)
|
||||||
find_package(CURL)
|
find_package(CURL)
|
||||||
find_package(cpr REQUIRED)
|
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(SQLite3 REQUIRED)
|
find_package(SQLite3 REQUIRED)
|
||||||
find_package(gtkmm REQUIRED)
|
find_package(gtkmm REQUIRED)
|
||||||
@@ -51,9 +50,9 @@ file(GLOB ABADDON_SOURCES
|
|||||||
|
|
||||||
add_executable(abaddon ${ABADDON_SOURCES})
|
add_executable(abaddon ${ABADDON_SOURCES})
|
||||||
target_include_directories(abaddon PUBLIC ${GTKMM_INCLUDE_DIRS})
|
target_include_directories(abaddon PUBLIC ${GTKMM_INCLUDE_DIRS})
|
||||||
target_include_directories(abaddon PUBLIC ${CPR_INCLUDE_DIRS})
|
|
||||||
target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS})
|
target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS})
|
||||||
target_include_directories(abaddon PUBLIC ${SQLite3_INCLUDE_DIRS})
|
target_include_directories(abaddon PUBLIC ${SQLite3_INCLUDE_DIRS})
|
||||||
|
target_include_directories(abaddon PUBLIC ${NLOHMANN_JSON_INCLUDE_DIRS})
|
||||||
|
|
||||||
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
|
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
|
||||||
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
|
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
|
||||||
@@ -87,6 +86,5 @@ endif()
|
|||||||
target_link_libraries(abaddon ${SQLite3_LIBRARIES})
|
target_link_libraries(abaddon ${SQLite3_LIBRARIES})
|
||||||
target_link_libraries(abaddon ${GTKMM_LIBRARIES})
|
target_link_libraries(abaddon ${GTKMM_LIBRARIES})
|
||||||
target_link_libraries(abaddon ${CURL_LIBRARIES})
|
target_link_libraries(abaddon ${CURL_LIBRARIES})
|
||||||
target_link_libraries(abaddon ${CPR_LIBRARY})
|
|
||||||
target_link_libraries(abaddon ${ZLIB_LIBRARY})
|
target_link_libraries(abaddon ${ZLIB_LIBRARY})
|
||||||
target_link_libraries(abaddon ${NLOHMANN_JSON_LIBRARIES})
|
target_link_libraries(abaddon ${NLOHMANN_JSON_LIBRARIES})
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -13,7 +13,7 @@
|
|||||||
### Building:
|
### Building:
|
||||||
#### Windows:
|
#### Windows:
|
||||||
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
|
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
|
||||||
2. `vcpkg install gtkmm:x64-windows nlohmann-json:x64-windows ixwebsocket:x64-windows cpr:x64-windows zlib:x64-windows simpleini:x64-windows sqlite3:x64-windows openssl:x64-windows`
|
2. `vcpkg install gtkmm:x64-windows nlohmann-json:x64-windows ixwebsocket:x64-windows zlib:x64-windows simpleini:x64-windows sqlite3:x64-windows openssl:x64-windows curl:x64-windows`
|
||||||
3. `mkdir build && cd build`
|
3. `mkdir build && cd build`
|
||||||
4. `cmake -G"Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=c:\path\to\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_TARGET_TRIPLET=x64-windows ..`
|
4. `cmake -G"Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=c:\path\to\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_TARGET_TRIPLET=x64-windows ..`
|
||||||
5. Build with Visual Studio
|
5. Build with Visual Studio
|
||||||
@@ -22,13 +22,13 @@ Or, do steps 1 and 2, and open CMakeLists.txt in Visual Studio if `vcpkg integra
|
|||||||
|
|
||||||
#### Mac:
|
#### Mac:
|
||||||
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
|
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
|
||||||
2. `brew install gtkmm3 nlohmann-json cpr`
|
2. `brew install gtkmm3 nlohmann-json`
|
||||||
3. `mkdir build && cd build`
|
3. `mkdir build && cd build`
|
||||||
4. `cmake ..`
|
4. `cmake ..`
|
||||||
5. `make`
|
5. `make`
|
||||||
|
|
||||||
#### Linux:
|
#### Linux:
|
||||||
1. Install dependencies: `libgtkmm-3.0-dev`, `libcurl4-gnutls-dev`, [cpr](https://github.com/whoshuu/cpr), and [nlohmann-json](https://github.com/nlohmann/json)
|
1. Install dependencies: `libgtkmm-3.0-dev`, `libcurl4-gnutls-dev`, and [nlohmann-json](https://github.com/nlohmann/json)
|
||||||
2. `git clone https://github.com/uowuo/abaddon && cd abaddon`
|
2. `git clone https://github.com/uowuo/abaddon && cd abaddon`
|
||||||
3. `mkdir build && cd build`
|
3. `mkdir build && cd build`
|
||||||
4. `cmake ..`
|
4. `cmake ..`
|
||||||
@@ -36,8 +36,8 @@ Or, do steps 1 and 2, and open CMakeLists.txt in Visual Studio if `vcpkg integra
|
|||||||
|
|
||||||
### Downloads (from CI):
|
### Downloads (from CI):
|
||||||
- Windows: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-windows-RelWithDebInfo.zip)
|
- Windows: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-windows-RelWithDebInfo.zip)
|
||||||
- MacOS: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-macos-RelWithDebInfo.zip) unsigned, unpackaged, requires gtkmm3 and [cpr](https://github.com/whoshuu/cpr/) (e.g. from homebrew)
|
- MacOS: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-macos-RelWithDebInfo.zip) unsigned, unpackaged, requires gtkmm3 (e.g. from homebrew)
|
||||||
- Linux: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-linux-MinSizeRel.zip) unpackaged (for now), requires gtkmm3 and [cpr](https://github.com/whoshuu/cpr/). built on Ubuntu 18.04 + gcc9
|
- Linux: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-linux-MinSizeRel.zip) unpackaged (for now), requires gtkmm3. built on Ubuntu 18.04 + gcc9
|
||||||
|
|
||||||
Make sure you start from the directory where `css` and `res` are
|
Make sure you start from the directory where `css` and `res` are
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Make sure you start from the directory where `css` and `res` are
|
|||||||
* [gtkmm](https://www.gtkmm.org/en/)
|
* [gtkmm](https://www.gtkmm.org/en/)
|
||||||
* [JSON for Modern C++](https://github.com/nlohmann/json)
|
* [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||||
* [IXWebSocket](https://github.com/machinezone/IXWebSocket)
|
* [IXWebSocket](https://github.com/machinezone/IXWebSocket)
|
||||||
* [C++ Requests: Curl for People](https://github.com/whoshuu/cpr/)
|
* [libcurl](https://curl.se/)
|
||||||
* [zlib](https://zlib.net/)
|
* [zlib](https://zlib.net/)
|
||||||
* [simpleini](https://github.com/brofield/simpleini)
|
* [simpleini](https://github.com/brofield/simpleini)
|
||||||
* [SQLite3](https://www.sqlite.org/index.html)
|
* [SQLite3](https://www.sqlite.org/index.html)
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
find_path(CPR_INCLUDE_DIR
|
|
||||||
NAMES cpr/cpr.h)
|
|
||||||
|
|
||||||
find_library(CPR_LIBRARY
|
|
||||||
NAMES cpr
|
|
||||||
HINTS ${CPR_LIBRARY_ROOT})
|
|
||||||
|
|
||||||
set(CPR_LIBRARIES ${CPR_LIBRARY})
|
|
||||||
set(CPR_INCLUDE_DIRS ${CPR_INCLUDE_DIR})
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(cpr
|
|
||||||
FOUND_VAR CPR_FOUND
|
|
||||||
REQUIRED_VARS
|
|
||||||
CPR_LIBRARY
|
|
||||||
CPR_INCLUDE_DIR
|
|
||||||
VERSION_VAR CPR_VERSION)
|
|
||||||
@@ -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) {
|
void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback) {
|
||||||
sigc::signal<void, std::optional<InviteData>> signal;
|
sigc::signal<void, std::optional<InviteData>> signal;
|
||||||
signal.connect(callback);
|
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 (!CheckCode(r)) {
|
||||||
if (r.status_code == 404)
|
if (r.status_code == 404)
|
||||||
callback(std::nullopt);
|
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) {
|
void DiscordClient::FetchMessagesInChannel(Snowflake id, std::function<void(const std::vector<Snowflake> &)> cb) {
|
||||||
std::string path = "/channels/" + std::to_string(id) + "/messages?limit=50";
|
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;
|
if (!CheckCode(r)) return;
|
||||||
|
|
||||||
std::vector<Message> msgs;
|
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) {
|
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);
|
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;
|
if (!CheckCode(r)) return;
|
||||||
|
|
||||||
std::vector<Message> msgs;
|
std::vector<Message> msgs;
|
||||||
@@ -453,7 +453,7 @@ void DiscordClient::SetGuildName(Snowflake id, const Glib::ustring &name, sigc::
|
|||||||
obj.Name = name;
|
obj.Name = name;
|
||||||
sigc::signal<void, bool> signal;
|
sigc::signal<void, bool> signal;
|
||||||
signal.connect(callback);
|
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;
|
const auto success = r.status_code == 200;
|
||||||
signal.emit(success);
|
signal.emit(success);
|
||||||
});
|
});
|
||||||
@@ -468,7 +468,7 @@ void DiscordClient::SetGuildIcon(Snowflake id, const std::string &data, sigc::sl
|
|||||||
obj.IconData = data;
|
obj.IconData = data;
|
||||||
sigc::signal<void, bool> signal;
|
sigc::signal<void, bool> signal;
|
||||||
signal.connect(callback);
|
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;
|
const auto success = r.status_code == 200;
|
||||||
signal.emit(success);
|
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) {
|
void DiscordClient::UnbanUser(Snowflake guild_id, Snowflake user_id, sigc::slot<void(bool success)> callback) {
|
||||||
sigc::signal<void, bool> signal;
|
sigc::signal<void, bool> signal;
|
||||||
signal.connect(callback);
|
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);
|
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) {
|
void DiscordClient::DeleteInvite(const std::string &code, sigc::slot<void(bool success)> callback) {
|
||||||
sigc::signal<void, bool> signal;
|
sigc::signal<void, bool> signal;
|
||||||
signal.connect(callback);
|
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));
|
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) {
|
void DiscordClient::FetchGuildBan(Snowflake guild_id, Snowflake user_id, sigc::slot<void(BanData)> callback) {
|
||||||
sigc::signal<void, BanData> signal;
|
sigc::signal<void, BanData> signal;
|
||||||
signal.connect(callback);
|
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;
|
if (!CheckCode(response)) return;
|
||||||
auto ban = nlohmann::json::parse(response.text).get<BanData>();
|
auto ban = nlohmann::json::parse(response.text).get<BanData>();
|
||||||
m_store.SetBan(guild_id, ban.User.ID, ban);
|
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) {
|
void DiscordClient::FetchGuildBans(Snowflake guild_id, sigc::slot<void(std::vector<BanData>)> callback) {
|
||||||
sigc::signal<void, std::vector<BanData>> signal;
|
sigc::signal<void, std::vector<BanData>> signal;
|
||||||
signal.connect(callback);
|
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;
|
if (!CheckCode(response)) return;
|
||||||
auto bans = nlohmann::json::parse(response.text).get<std::vector<BanData>>();
|
auto bans = nlohmann::json::parse(response.text).get<std::vector<BanData>>();
|
||||||
m_store.BeginTransaction();
|
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) {
|
void DiscordClient::FetchGuildInvites(Snowflake guild_id, sigc::slot<void(std::vector<InviteData>)> callback) {
|
||||||
sigc::signal<void, std::vector<InviteData>> signal;
|
sigc::signal<void, std::vector<InviteData>> signal;
|
||||||
signal.connect(callback);
|
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?
|
// store?
|
||||||
if (!CheckCode(response)) return;
|
if (!CheckCode(response)) return;
|
||||||
auto invites = nlohmann::json::parse(response.text).get<std::vector<InviteData>>();
|
auto invites = nlohmann::json::parse(response.text).get<std::vector<InviteData>>();
|
||||||
@@ -1232,9 +1232,9 @@ void DiscordClient::HandleSocketOpen() {
|
|||||||
void DiscordClient::HandleSocketClose(uint16_t code) {
|
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) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "websocket.hpp"
|
#include "websocket.hpp"
|
||||||
#include "http.hpp"
|
#include "httpclient.hpp"
|
||||||
#include "objects.hpp"
|
#include "objects.hpp"
|
||||||
#include "store.hpp"
|
#include "store.hpp"
|
||||||
#include <sigc++/sigc++.h>
|
#include <sigc++/sigc++.h>
|
||||||
@@ -175,7 +175,7 @@ private:
|
|||||||
void HandleSocketOpen();
|
void HandleSocketOpen();
|
||||||
void HandleSocketClose(uint16_t code);
|
void HandleSocketClose(uint16_t code);
|
||||||
|
|
||||||
bool CheckCode(const cpr::Response &r);
|
bool CheckCode(const http::response_type &r);
|
||||||
|
|
||||||
void StoreMessageData(Message &msg);
|
void StoreMessageData(Message &msg);
|
||||||
|
|
||||||
|
|||||||
156
discord/http.cpp
156
discord/http.cpp
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
136
discord/httpclient.cpp
Normal file
136
discord/httpclient.cpp
Normal file
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
37
discord/httpclient.hpp
Normal file
37
discord/httpclient.hpp
Normal file
@@ -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;
|
||||||
|
};
|
||||||
@@ -51,10 +51,10 @@ void Cache::GetFileFromURL(std::string url, callback_type cb) {
|
|||||||
if (m_canceled) return;
|
if (m_canceled) return;
|
||||||
m_semaphore->wait();
|
m_semaphore->wait();
|
||||||
if (m_canceled) return;
|
if (m_canceled) return;
|
||||||
const auto &r = cpr::Get(cpr::Url { url });
|
http::request req(http::REQUEST_GET, url);
|
||||||
m_semaphore->notify();
|
m_semaphore->notify();
|
||||||
if (m_canceled) return;
|
if (m_canceled) return;
|
||||||
OnResponse(r);
|
OnResponse(req.execute());
|
||||||
});
|
});
|
||||||
m_futures.push_back(std::move(future));
|
m_futures.push_back(std::move(future));
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ void Cache::CleanupFutures() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cache::OnResponse(const cpr::Response &r) {
|
void Cache::OnResponse(const http::response_type &r) {
|
||||||
CleanupFutures(); // see above comment
|
CleanupFutures(); // see above comment
|
||||||
if (r.error || r.status_code > 300) return;
|
if (r.error || r.status_code > 300) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cpr/cpr.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <future>
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
#include "http.hpp"
|
||||||
// todo throttle requests and keep track of active requests to stop redundant requests
|
|
||||||
|
|
||||||
class Cache {
|
class Cache {
|
||||||
public:
|
public:
|
||||||
@@ -23,7 +22,7 @@ private:
|
|||||||
std::string GetCachedName(std::string str);
|
std::string GetCachedName(std::string str);
|
||||||
void CleanupFutures();
|
void CleanupFutures();
|
||||||
void RespondFromPath(std::filesystem::path path, callback_type cb);
|
void RespondFromPath(std::filesystem::path path, callback_type cb);
|
||||||
void OnResponse(const cpr::Response &r);
|
void OnResponse(const http::response_type &r);
|
||||||
|
|
||||||
std::unique_ptr<Semaphore> m_semaphore;
|
std::unique_ptr<Semaphore> m_semaphore;
|
||||||
|
|
||||||
|
|||||||
121
http.cpp
Normal file
121
http.cpp
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#include "http.hpp"
|
||||||
|
|
||||||
|
namespace http {
|
||||||
|
request::request(EMethod method, const std::string &url)
|
||||||
|
: m_url(url) {
|
||||||
|
switch (method) {
|
||||||
|
case REQUEST_GET:
|
||||||
|
m_method = "GET";
|
||||||
|
break;
|
||||||
|
case REQUEST_POST:
|
||||||
|
m_method = "POST";
|
||||||
|
break;
|
||||||
|
case REQUEST_PATCH:
|
||||||
|
m_method = "PATCH";
|
||||||
|
break;
|
||||||
|
case REQUEST_PUT:
|
||||||
|
m_method = "PUT";
|
||||||
|
break;
|
||||||
|
case REQUEST_DELETE:
|
||||||
|
m_method = "DELETE";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_method = "GET";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
request::~request() {
|
||||||
|
if (m_curl != nullptr)
|
||||||
|
curl_easy_cleanup(m_curl);
|
||||||
|
|
||||||
|
if (m_header_list != nullptr)
|
||||||
|
curl_slist_free_all(m_header_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void request::set_verify_ssl(bool verify) {
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, verify ? 1L : 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void request::set_proxy(const std::string &proxy) {
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_PROXY, proxy.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void request::set_header(const std::string &name, const std::string &value) {
|
||||||
|
m_header_list = curl_slist_append(m_header_list, (name + ": " + value).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void request::set_body(const std::string &data) {
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_COPYPOSTFIELDS, data.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void request::set_user_agent(const std::string &data) {
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, data.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
response request::execute() {
|
||||||
|
if (m_curl == nullptr) {
|
||||||
|
auto response = detail::make_response(m_url, EStatusCode::ClientErrorCURLInit);
|
||||||
|
response.error_string = "curl pointer is null";
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::check_init();
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method);
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, detail::curl_write_data_callback);
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &str);
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_ERRORBUFFER, m_error_buf);
|
||||||
|
if (m_header_list != nullptr)
|
||||||
|
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_header_list);
|
||||||
|
|
||||||
|
CURLcode result = curl_easy_perform(m_curl);
|
||||||
|
if (result != CURLE_OK) {
|
||||||
|
auto response = detail::make_response(m_url, EStatusCode::ClientErrorCURLPerform);
|
||||||
|
response.error_string = curl_easy_strerror(result);
|
||||||
|
response.error_string += " " + std::string(m_error_buf);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
int response_code = 0;
|
||||||
|
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||||
|
|
||||||
|
auto response = detail::make_response(m_url, response_code);
|
||||||
|
response.text = str;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void request::prepare() {
|
||||||
|
m_curl = curl_easy_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
size_t curl_write_data_callback(void *ptr, size_t size, size_t nmemb, std::string *outstr) {
|
||||||
|
auto new_length = size * nmemb;
|
||||||
|
outstr->append(reinterpret_cast<char *>(ptr), new_length);
|
||||||
|
return new_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
response make_response(const std::string &url, int code) {
|
||||||
|
response r;
|
||||||
|
r.url = url;
|
||||||
|
r.status_code = static_cast<EStatusCode>(code);
|
||||||
|
if (code < http::EStatusCode::ClientErrorMax)
|
||||||
|
r.error = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_init() {
|
||||||
|
static bool initialized = false;
|
||||||
|
if (!initialized) {
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace http
|
||||||
129
http.hpp
Normal file
129
http.hpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
// i regret not using snake case for everything oh well
|
||||||
|
|
||||||
|
namespace http {
|
||||||
|
enum EStatusCode : int {
|
||||||
|
Continue = 100,
|
||||||
|
SwitchingProtocols = 101,
|
||||||
|
Processing = 102,
|
||||||
|
EarlyHints = 103,
|
||||||
|
|
||||||
|
OK = 200,
|
||||||
|
Created = 201,
|
||||||
|
Accepted = 202,
|
||||||
|
NonAuthoritativeInformation = 203,
|
||||||
|
NoContent = 204,
|
||||||
|
ResetContent = 205,
|
||||||
|
PartialContent = 206,
|
||||||
|
MultiStatus = 207,
|
||||||
|
AlreadyReported = 208,
|
||||||
|
IMUsed = 226,
|
||||||
|
|
||||||
|
MultipleChoices = 300,
|
||||||
|
MovedPermanently = 301,
|
||||||
|
Found = 302,
|
||||||
|
SeeOther = 303,
|
||||||
|
NotModified = 304,
|
||||||
|
UseProxy = 305,
|
||||||
|
SwitchProxy = 306,
|
||||||
|
TemporaryRedirect = 307,
|
||||||
|
PermanentRedirect = 308,
|
||||||
|
|
||||||
|
BadRequest = 400,
|
||||||
|
Unauthorized = 401,
|
||||||
|
PaymentRequired = 402,
|
||||||
|
Forbidden = 403,
|
||||||
|
NotFound = 404,
|
||||||
|
MethodNotAllowed = 405,
|
||||||
|
NotAcceptable = 406,
|
||||||
|
ProxyAuthorizationRequired = 407,
|
||||||
|
RequestTimeout = 408,
|
||||||
|
Conflict = 409,
|
||||||
|
Gone = 410,
|
||||||
|
LengthRequired = 411,
|
||||||
|
PreconditionFailed = 412,
|
||||||
|
PayloadTooLarge = 413,
|
||||||
|
URITooLong = 414,
|
||||||
|
UnsupportedMediaType = 415,
|
||||||
|
RangeNotSatisfiable = 416,
|
||||||
|
ExpectationFailed = 417,
|
||||||
|
ImATeapot = 418,
|
||||||
|
MisdirectedRequest = 421,
|
||||||
|
UnprocessableEntity = 422,
|
||||||
|
Locked = 423,
|
||||||
|
FailedDependency = 424,
|
||||||
|
TooEarly = 425,
|
||||||
|
UpgradeRequired = 426,
|
||||||
|
PreconditionRequired = 428,
|
||||||
|
TooManyRequests = 429,
|
||||||
|
RequestHeaderFieldsTooLarge = 431,
|
||||||
|
UnavailableForLegalReasons = 451,
|
||||||
|
|
||||||
|
InternalServerError = 500,
|
||||||
|
NotImplemented = 501,
|
||||||
|
BadGateway = 502,
|
||||||
|
ServiceUnavailable = 503,
|
||||||
|
GatewayTimeout = 504,
|
||||||
|
HTTPVersionNotSupported = 505,
|
||||||
|
VariantAlsoNegotiates = 506,
|
||||||
|
InsufficientStorage = 507,
|
||||||
|
LoopDetected = 508,
|
||||||
|
NotExtended = 510,
|
||||||
|
NetworkAuthenticationRequired = 511,
|
||||||
|
|
||||||
|
ClientError = 1,
|
||||||
|
ClientErrorCURLInit,
|
||||||
|
ClientErrorCURLPerform,
|
||||||
|
ClientErrorMax = 99,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EMethod {
|
||||||
|
REQUEST_GET,
|
||||||
|
REQUEST_POST,
|
||||||
|
REQUEST_PATCH,
|
||||||
|
REQUEST_PUT,
|
||||||
|
REQUEST_DELETE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response {
|
||||||
|
EStatusCode status_code;
|
||||||
|
std::string text;
|
||||||
|
std::string url;
|
||||||
|
bool error = false;
|
||||||
|
std::string error_string;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct request {
|
||||||
|
request(EMethod method, const std::string &url);
|
||||||
|
~request();
|
||||||
|
|
||||||
|
void set_verify_ssl(bool verify);
|
||||||
|
void set_proxy(const std::string &proxy);
|
||||||
|
void set_header(const std::string &name, const std::string &value);
|
||||||
|
void set_body(const std::string &data);
|
||||||
|
void set_user_agent(const std::string &data);
|
||||||
|
|
||||||
|
response execute();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void prepare();
|
||||||
|
|
||||||
|
CURL *m_curl;
|
||||||
|
std::string m_url;
|
||||||
|
const char *m_method;
|
||||||
|
curl_slist *m_header_list = nullptr;
|
||||||
|
char m_error_buf[CURL_ERROR_SIZE] = { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
using response_type = response;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
size_t curl_write_data_callback(void *ptr, size_t size, size_t nmemb, std::string *outstr);
|
||||||
|
|
||||||
|
response make_response(const std::string &url, int code);
|
||||||
|
void check_init();
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace http
|
||||||
Reference in New Issue
Block a user