mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-11-24 18:17:18 +01:00
Update WIP discord and some vendors.
CPR has features disabled and PCRE is fully disabled until updated to new code.
This commit is contained in:
27
vendor/CMakeLists.txt
vendored
27
vendor/CMakeLists.txt
vendored
@@ -8,6 +8,8 @@ add_subdirectory(TinyDir)
|
||||
add_subdirectory(SAJSON)
|
||||
add_subdirectory(CPR)
|
||||
add_subdirectory(UTF8)
|
||||
add_subdirectory(JSON)
|
||||
add_subdirectory(Inja)
|
||||
add_subdirectory(PUGIXML)
|
||||
add_subdirectory(CivetWeb)
|
||||
if (ENABLE_BUILTIN_MYSQL_C)
|
||||
@@ -70,4 +72,29 @@ set(BUILD_STATIC ON CACHE INTERNAL "" FORCE)
|
||||
if (WIN32 OR MINGW)
|
||||
set(ZMQ_HAVE_IPC OFF CACHE INTERNAL "" FORCE)
|
||||
endif()
|
||||
set(ENABLE_CURVE OFF CACHE INTERNAL "" FORCE)
|
||||
set(WITH_LIBSODIUM OFF CACHE INTERNAL "" FORCE)
|
||||
add_subdirectory(ZMQ)
|
||||
if(ENABLE_DISCORD)
|
||||
set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE)
|
||||
set(BUILD_VOICE_SUPPORT OFF CACHE INTERNAL "" FORCE)
|
||||
set(DPP_INSTALL OFF CACHE INTERNAL "" FORCE)
|
||||
set(DPP_BUILD_TEST OFF CACHE INTERNAL "" FORCE)
|
||||
set(DPP_NO_VCPKG ON CACHE INTERNAL "" FORCE)
|
||||
set(DPP_CORO OFF CACHE INTERNAL "" FORCE)
|
||||
set(DPP_USE_EXTERNAL_JSON ON CACHE INTERNAL "" FORCE)
|
||||
if (WIN32 OR MINGW)
|
||||
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "" FORCE)
|
||||
endif()
|
||||
add_subdirectory(DPP)
|
||||
target_link_libraries(dpp PRIVATE nlohmann_json)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE)
|
||||
# We don't care about DPP warnings
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
||||
target_compile_options(dpp PRIVATE -w)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(dpp PRIVATE -w)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(dpp PRIVATE /w)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
60
vendor/CPR/CMakeLists.txt
vendored
60
vendor/CPR/CMakeLists.txt
vendored
@@ -1,52 +1,84 @@
|
||||
# Create the CPR library
|
||||
add_library(CPR STATIC
|
||||
# Source files
|
||||
cpr/auth.cpp
|
||||
cpr/bearer.cpp
|
||||
cpr/cookies.cpp
|
||||
cpr/cprtypes.cpp
|
||||
cpr/curl_container.cpp
|
||||
cpr/curlholder.cpp
|
||||
cpr/error.cpp
|
||||
cpr/file.cpp
|
||||
cpr/interceptor.cpp
|
||||
cpr/multipart.cpp
|
||||
cpr/multiperform.cpp
|
||||
cpr/parameters.cpp
|
||||
cpr/payload.cpp
|
||||
cpr/proxies.cpp
|
||||
cpr/proxyauth.cpp
|
||||
cpr/redirect.cpp
|
||||
cpr/response.cpp
|
||||
cpr/session.cpp
|
||||
cpr/ssl_ctx.cpp
|
||||
cpr/threadpool.cpp
|
||||
cpr/timeout.cpp
|
||||
cpr/unix_socket.cpp
|
||||
cpr/util.cpp
|
||||
cpr/response.cpp
|
||||
# Header files
|
||||
include/cpr/api.h
|
||||
include/cpr/auth.h
|
||||
cpr/accept_encoding.cpp
|
||||
cpr/async.cpp
|
||||
cpr/auth.cpp
|
||||
cpr/bearer.cpp
|
||||
cpr/callback.cpp
|
||||
cpr/cert_info.cpp
|
||||
cpr/cookies.cpp
|
||||
cpr/cprtypes.cpp
|
||||
cpr/curl_container.cpp
|
||||
cpr/curlholder.cpp
|
||||
cpr/curlmultiholder.cpp
|
||||
# Header Files
|
||||
include/cpr/bearer.h
|
||||
include/cpr/body.h
|
||||
include/cpr/buffer.h
|
||||
include/cpr/callback.h
|
||||
include/cpr/cert_info.h
|
||||
include/cpr/connect_timeout.h
|
||||
include/cpr/cookies.h
|
||||
include/cpr/cpr.h
|
||||
include/cpr/cprtypes.h
|
||||
include/cpr/curl_container.h
|
||||
include/cpr/curlholder.h
|
||||
include/cpr/curlholder.h
|
||||
include/cpr/digest.h
|
||||
include/cpr/curlmultiholder.h
|
||||
include/cpr/error.h
|
||||
include/cpr/file.h
|
||||
include/cpr/filesystem.h
|
||||
include/cpr/http_version.h
|
||||
include/cpr/interceptor.h
|
||||
include/cpr/interface.h
|
||||
include/cpr/limit_rate.h
|
||||
include/cpr/local_port.h
|
||||
include/cpr/local_port_range.h
|
||||
include/cpr/low_speed.h
|
||||
include/cpr/multipart.h
|
||||
include/cpr/ntlm.h
|
||||
include/cpr/multiperform.h
|
||||
include/cpr/parameters.h
|
||||
include/cpr/payload.h
|
||||
include/cpr/proxies.h
|
||||
include/cpr/proxyauth.h
|
||||
include/cpr/range.h
|
||||
include/cpr/redirect.h
|
||||
include/cpr/reserve_size.h
|
||||
include/cpr/resolve.h
|
||||
include/cpr/response.h
|
||||
include/cpr/session.h
|
||||
include/cpr/singleton.h
|
||||
include/cpr/ssl_ctx.h
|
||||
include/cpr/ssl_options.h
|
||||
include/cpr/status_codes.h
|
||||
include/cpr/threadpool.h
|
||||
include/cpr/timeout.h
|
||||
include/cpr/unix_socket.h
|
||||
include/cpr/user_agent.h
|
||||
include/cpr/util.h
|
||||
include/cpr/verbose.h
|
||||
include/cpr/accept_encoding.h
|
||||
include/cpr/api.h
|
||||
include/cpr/async.h
|
||||
include/cpr/async_wrapper.h
|
||||
include/cpr/auth.h
|
||||
)
|
||||
# Library includes
|
||||
target_include_directories(CPR PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cpr)
|
||||
@@ -55,7 +87,7 @@ target_include_directories(CPR PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(CPR PRIVATE -Wno-deprecated-declarations)
|
||||
endif()
|
||||
# Find CURK
|
||||
# Find CURL
|
||||
find_package(CURL REQUIRED)
|
||||
if (CURL_FOUND)
|
||||
set(SSL_ENABLED ON CACHE INTERNAL "" FORCE)
|
||||
|
||||
37
vendor/CPR/cpr/accept_encoding.cpp
vendored
Normal file
37
vendor/CPR/cpr/accept_encoding.cpp
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "cpr/accept_encoding.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
AcceptEncoding::AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods) {
|
||||
methods_.clear();
|
||||
std::transform(methods.begin(), methods.end(), std::inserter(methods_, methods_.begin()), [&](cpr::AcceptEncodingMethods method) { return cpr::AcceptEncodingMethodsStringMap.at(method); });
|
||||
}
|
||||
|
||||
AcceptEncoding::AcceptEncoding(const std::initializer_list<std::string>& string_methods) : methods_{string_methods} {}
|
||||
|
||||
bool AcceptEncoding::empty() const noexcept {
|
||||
return methods_.empty();
|
||||
}
|
||||
|
||||
const std::string AcceptEncoding::getString() const {
|
||||
return std::accumulate(std::next(methods_.begin()), methods_.end(), *methods_.begin(), [](std::string a, std::string b) { return std::move(a) + ", " + std::move(b); });
|
||||
}
|
||||
|
||||
[[nodiscard]] bool AcceptEncoding::disabled() const {
|
||||
if (methods_.find(cpr::AcceptEncodingMethodsStringMap.at(AcceptEncodingMethods::disabled)) != methods_.end()) {
|
||||
if (methods_.size() != 1) {
|
||||
throw std::invalid_argument("AcceptEncoding does not accept any other values if 'disabled' is present. You set the following encodings: " + getString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
8
vendor/CPR/cpr/async.cpp
vendored
Normal file
8
vendor/CPR/cpr/async.cpp
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "cpr/async.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
CPR_SINGLETON_IMPL(GlobalThreadPool)
|
||||
|
||||
} // namespace cpr
|
||||
9
vendor/CPR/cpr/auth.cpp
vendored
9
vendor/CPR/cpr/auth.cpp
vendored
@@ -1,7 +1,16 @@
|
||||
#include "cpr/auth.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
Authentication::~Authentication() noexcept {
|
||||
util::secureStringClear(auth_string_);
|
||||
}
|
||||
|
||||
const char* Authentication::GetAuthString() const noexcept {
|
||||
return auth_string_.c_str();
|
||||
}
|
||||
|
||||
AuthMode Authentication::GetAuthMode() const noexcept {
|
||||
return auth_mode_;
|
||||
}
|
||||
} // namespace cpr
|
||||
|
||||
5
vendor/CPR/cpr/bearer.cpp
vendored
5
vendor/CPR/cpr/bearer.cpp
vendored
@@ -1,9 +1,14 @@
|
||||
#include "cpr/bearer.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
// Only supported with libcurl >= 7.61.0.
|
||||
// As an alternative use SetHeader and add the token manually.
|
||||
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||||
Bearer::~Bearer() noexcept {
|
||||
util::secureStringClear(token_string_);
|
||||
}
|
||||
|
||||
const char* Bearer::GetToken() const noexcept {
|
||||
return token_string_.c_str();
|
||||
}
|
||||
|
||||
14
vendor/CPR/cpr/callback.cpp
vendored
Normal file
14
vendor/CPR/cpr/callback.cpp
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <cpr/callback.h>
|
||||
#include <curl/curl.h>
|
||||
#include <functional>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
void CancellationCallback::SetProgressCallback(ProgressCallback& u_cb) {
|
||||
user_cb.emplace(std::reference_wrapper{u_cb});
|
||||
}
|
||||
bool CancellationCallback::operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const {
|
||||
const bool cont_operation{!cancellation_state->load()};
|
||||
return user_cb ? (cont_operation && (*user_cb)(dltotal, dlnow, ultotal, ulnow)) : cont_operation;
|
||||
}
|
||||
} // namespace cpr
|
||||
43
vendor/CPR/cpr/cert_info.cpp
vendored
Normal file
43
vendor/CPR/cpr/cert_info.cpp
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "cpr/cert_info.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
std::string& CertInfo::operator[](const size_t& pos) {
|
||||
return cert_info_[pos];
|
||||
}
|
||||
|
||||
CertInfo::iterator CertInfo::begin() {
|
||||
return cert_info_.begin();
|
||||
}
|
||||
CertInfo::iterator CertInfo::end() {
|
||||
return cert_info_.end();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::begin() const {
|
||||
return cert_info_.begin();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::end() const {
|
||||
return cert_info_.end();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::cbegin() const {
|
||||
return cert_info_.cbegin();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::cend() const {
|
||||
return cert_info_.cend();
|
||||
}
|
||||
|
||||
void CertInfo::emplace_back(const std::string& str) {
|
||||
cert_info_.emplace_back(str);
|
||||
}
|
||||
|
||||
void CertInfo::push_back(const std::string& str) {
|
||||
cert_info_.push_back(str);
|
||||
}
|
||||
|
||||
void CertInfo::pop_back() {
|
||||
cert_info_.pop_back();
|
||||
}
|
||||
} // namespace cpr
|
||||
83
vendor/CPR/cpr/cookies.cpp
vendored
83
vendor/CPR/cpr/cookies.cpp
vendored
@@ -1,51 +1,106 @@
|
||||
#include "cpr/cookies.h"
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
namespace cpr {
|
||||
std::string Cookies::GetEncoded(const CurlHolder& holder) const {
|
||||
const std::string Cookie::GetDomain() const {
|
||||
return domain_;
|
||||
}
|
||||
|
||||
bool Cookie::IsIncludingSubdomains() const {
|
||||
return includeSubdomains_;
|
||||
}
|
||||
|
||||
const std::string Cookie::GetPath() const {
|
||||
return path_;
|
||||
}
|
||||
|
||||
bool Cookie::IsHttpsOnly() const {
|
||||
return httpsOnly_;
|
||||
}
|
||||
|
||||
const std::chrono::system_clock::time_point Cookie::GetExpires() const {
|
||||
return expires_;
|
||||
}
|
||||
|
||||
const std::string Cookie::GetExpiresString() const {
|
||||
std::stringstream ss;
|
||||
std::tm tm{};
|
||||
const std::time_t tt = std::chrono::system_clock::to_time_t(expires_);
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&tm, &tt);
|
||||
#else
|
||||
gmtime_r(&tt, &tm);
|
||||
#endif
|
||||
ss << std::put_time(&tm, "%a, %d %b %Y %H:%M:%S GMT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
const std::string Cookie::GetName() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string Cookie::GetValue() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
const std::string Cookies::GetEncoded(const CurlHolder& holder) const {
|
||||
std::stringstream stream;
|
||||
for (const std::pair<const std::string, std::string>& item : map_) {
|
||||
for (const cpr::Cookie& item : cookies_) {
|
||||
// Depending on if encoding is set to "true", we will URL-encode cookies
|
||||
stream << (encode ? holder.urlEncode(item.first) : item.first) << "=";
|
||||
stream << (encode ? holder.urlEncode(item.GetName()) : item.GetName()) << "=";
|
||||
|
||||
// special case version 1 cookies, which can be distinguished by
|
||||
// beginning and trailing quotes
|
||||
if (!item.second.empty() && item.second.front() == '"' && item.second.back() == '"') {
|
||||
stream << item.second;
|
||||
if (!item.GetValue().empty() && item.GetValue().front() == '"' && item.GetValue().back() == '"') {
|
||||
stream << item.GetValue();
|
||||
} else {
|
||||
// Depending on if encoding is set to "true", we will URL-encode cookies
|
||||
stream << (encode ? holder.urlEncode(item.second) : item.second);
|
||||
stream << (encode ? holder.urlEncode(item.GetValue()) : item.GetValue());
|
||||
}
|
||||
stream << "; ";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string& Cookies::operator[](const std::string& key) {
|
||||
return map_[key];
|
||||
cpr::Cookie& Cookies::operator[](size_t pos) {
|
||||
return cookies_[pos];
|
||||
}
|
||||
|
||||
Cookies::iterator Cookies::begin() {
|
||||
return map_.begin();
|
||||
return cookies_.begin();
|
||||
}
|
||||
|
||||
Cookies::iterator Cookies::end() {
|
||||
return map_.end();
|
||||
return cookies_.end();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::begin() const {
|
||||
return map_.begin();
|
||||
return cookies_.begin();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::end() const {
|
||||
return map_.end();
|
||||
return cookies_.end();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::cbegin() const {
|
||||
return map_.cbegin();
|
||||
return cookies_.cbegin();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::cend() const {
|
||||
return map_.cend();
|
||||
return cookies_.cend();
|
||||
}
|
||||
|
||||
void Cookies::emplace_back(const Cookie& str) {
|
||||
cookies_.emplace_back(str);
|
||||
}
|
||||
|
||||
void Cookies::push_back(const Cookie& str) {
|
||||
cookies_.push_back(str);
|
||||
}
|
||||
|
||||
void Cookies::pop_back() {
|
||||
cookies_.pop_back();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
4
vendor/CPR/cpr/cprtypes.cpp
vendored
4
vendor/CPR/cpr/cprtypes.cpp
vendored
@@ -5,8 +5,6 @@
|
||||
|
||||
namespace cpr {
|
||||
bool CaseInsensitiveCompare::operator()(const std::string& a, const std::string& b) const noexcept {
|
||||
return std::lexicographical_compare(
|
||||
a.begin(), a.end(), b.begin(), b.end(),
|
||||
[](unsigned char ac, unsigned char bc) { return std::tolower(ac) < std::tolower(bc); });
|
||||
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char ac, unsigned char bc) { return std::tolower(ac) < std::tolower(bc); });
|
||||
}
|
||||
} // namespace cpr
|
||||
|
||||
17
vendor/CPR/cpr/curl_container.cpp
vendored
17
vendor/CPR/cpr/curl_container.cpp
vendored
@@ -1,16 +1,15 @@
|
||||
#include "cpr/curl_container.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace cpr {
|
||||
template <class T>
|
||||
CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList)
|
||||
: containerList_(containerList) {}
|
||||
CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList) : containerList_(containerList) {}
|
||||
|
||||
template <class T>
|
||||
void CurlContainer<T>::Add(const std::initializer_list<T>& containerList) {
|
||||
for (const T& element : containerList) {
|
||||
containerList_.push_back(std::move(element));
|
||||
}
|
||||
std::transform(containerList.begin(), containerList.end(), std::back_inserter(containerList_), [](const T& elem) { return std::move(elem); });
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -26,15 +25,15 @@ const std::string CurlContainer<Parameter>::GetContent(const CurlHolder& holder)
|
||||
content += "&";
|
||||
}
|
||||
|
||||
std::string escapedKey = encode ? holder.urlEncode(parameter.key) : parameter.key;
|
||||
const std::string escapedKey = encode ? holder.urlEncode(parameter.key) : parameter.key;
|
||||
if (parameter.value.empty()) {
|
||||
content += escapedKey;
|
||||
} else {
|
||||
std::string escapedValue = encode ? holder.urlEncode(parameter.value) : parameter.value;
|
||||
const std::string escapedValue = encode ? holder.urlEncode(parameter.value) : parameter.value;
|
||||
content += escapedKey + "=";
|
||||
content += escapedValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -46,7 +45,7 @@ const std::string CurlContainer<Pair>::GetContent(const CurlHolder& holder) cons
|
||||
if (!content.empty()) {
|
||||
content += "&";
|
||||
}
|
||||
std::string escaped = encode ? holder.urlEncode(element.value) : element.value;
|
||||
const std::string escaped = encode ? holder.urlEncode(element.value) : element.value;
|
||||
content += element.key + "=" + escaped;
|
||||
}
|
||||
|
||||
|
||||
16
vendor/CPR/cpr/curlholder.cpp
vendored
16
vendor/CPR/cpr/curlholder.cpp
vendored
@@ -2,10 +2,6 @@
|
||||
#include <cassert>
|
||||
|
||||
namespace cpr {
|
||||
// It does not make sense to make a std::mutex const.
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::mutex CurlHolder::curl_easy_init_mutex_{};
|
||||
|
||||
CurlHolder::CurlHolder() {
|
||||
/**
|
||||
* Allow multithreaded access to CPR by locking curl_easy_init().
|
||||
@@ -14,22 +10,24 @@ CurlHolder::CurlHolder() {
|
||||
* https://curl.haxx.se/libcurl/c/curl_easy_init.html
|
||||
* https://curl.haxx.se/libcurl/c/threadsafe.html
|
||||
**/
|
||||
curl_easy_init_mutex_.lock();
|
||||
curl_easy_init_mutex_().lock();
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-prefer-member-initializer) since we need it to happen inside the lock
|
||||
handle = curl_easy_init();
|
||||
curl_easy_init_mutex_.unlock();
|
||||
curl_easy_init_mutex_().unlock();
|
||||
|
||||
assert(handle);
|
||||
} // namespace cpr
|
||||
|
||||
CurlHolder::~CurlHolder() {
|
||||
curl_slist_free_all(chunk);
|
||||
curl_formfree(formpost);
|
||||
curl_slist_free_all(resolveCurlList);
|
||||
curl_mime_free(multipart);
|
||||
curl_easy_cleanup(handle);
|
||||
}
|
||||
|
||||
std::string CurlHolder::urlEncode(const std::string& s) const {
|
||||
assert(handle);
|
||||
char* output = curl_easy_escape(handle, s.c_str(), s.length());
|
||||
char* output = curl_easy_escape(handle, s.c_str(), static_cast<int>(s.length()));
|
||||
if (output) {
|
||||
std::string result = output;
|
||||
curl_free(output);
|
||||
@@ -40,7 +38,7 @@ std::string CurlHolder::urlEncode(const std::string& s) const {
|
||||
|
||||
std::string CurlHolder::urlDecode(const std::string& s) const {
|
||||
assert(handle);
|
||||
char* output = curl_easy_unescape(handle, s.c_str(), s.length(), nullptr);
|
||||
char* output = curl_easy_unescape(handle, s.c_str(), static_cast<int>(s.length()), nullptr);
|
||||
if (output) {
|
||||
std::string result = output;
|
||||
curl_free(output);
|
||||
|
||||
15
vendor/CPR/cpr/curlmultiholder.cpp
vendored
Normal file
15
vendor/CPR/cpr/curlmultiholder.cpp
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "cpr/curlmultiholder.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
CurlMultiHolder::CurlMultiHolder() : handle{curl_multi_init()} {
|
||||
assert(handle);
|
||||
}
|
||||
|
||||
CurlMultiHolder::~CurlMultiHolder() {
|
||||
curl_multi_cleanup(handle);
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
2
vendor/CPR/cpr/error.cpp
vendored
2
vendor/CPR/cpr/error.cpp
vendored
@@ -59,7 +59,7 @@ ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) {
|
||||
case CURLE_SSL_ISSUER_ERROR:
|
||||
return ErrorCode::SSL_CACERT_ERROR;
|
||||
case CURLE_TOO_MANY_REDIRECTS:
|
||||
return ErrorCode::OK;
|
||||
return ErrorCode::TOO_MANY_REDIRECTS;
|
||||
default:
|
||||
return ErrorCode::INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
60
vendor/CPR/cpr/file.cpp
vendored
Normal file
60
vendor/CPR/cpr/file.cpp
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "cpr/file.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
Files::Files(const std::initializer_list<std::string>& p_filepaths) {
|
||||
for (const std::string& filepath : p_filepaths) {
|
||||
files.emplace_back(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
Files::iterator Files::begin() {
|
||||
return files.begin();
|
||||
}
|
||||
|
||||
Files::iterator Files::end() {
|
||||
return files.end();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::begin() const {
|
||||
return files.begin();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::end() const {
|
||||
return files.end();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::cbegin() const {
|
||||
return files.cbegin();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::cend() const {
|
||||
return files.cend();
|
||||
}
|
||||
|
||||
void Files::emplace_back(const File& file) {
|
||||
files.emplace_back(file);
|
||||
}
|
||||
|
||||
void Files::push_back(const File& file) {
|
||||
files.push_back(file);
|
||||
}
|
||||
|
||||
void Files::pop_back() {
|
||||
files.pop_back();
|
||||
}
|
||||
|
||||
Files& Files::operator=(const Files& other) {
|
||||
if (&other != this) {
|
||||
files = other.files;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Files& Files::operator=(Files&& old) noexcept {
|
||||
if (&old != this) {
|
||||
files = std::move(old.files);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
} // namespace cpr
|
||||
53
vendor/CPR/cpr/interceptor.cpp
vendored
Normal file
53
vendor/CPR/cpr/interceptor.cpp
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "cpr/interceptor.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
Response Interceptor::proceed(Session& session) {
|
||||
return session.proceed();
|
||||
}
|
||||
|
||||
Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod) {
|
||||
switch (httpMethod) {
|
||||
case ProceedHttpMethod::DELETE_REQUEST:
|
||||
return session.Delete();
|
||||
case ProceedHttpMethod::GET_REQUEST:
|
||||
return session.Get();
|
||||
case ProceedHttpMethod::HEAD_REQUEST:
|
||||
return session.Head();
|
||||
case ProceedHttpMethod::OPTIONS_REQUEST:
|
||||
return session.Options();
|
||||
case ProceedHttpMethod::PATCH_REQUEST:
|
||||
return session.Patch();
|
||||
case ProceedHttpMethod::POST_REQUEST:
|
||||
return session.Post();
|
||||
case ProceedHttpMethod::PUT_REQUEST:
|
||||
return session.Put();
|
||||
default:
|
||||
throw std::invalid_argument{"Can't proceed the session with the provided http method!"};
|
||||
}
|
||||
}
|
||||
|
||||
Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod, std::ofstream& file) {
|
||||
if (httpMethod == ProceedHttpMethod::DOWNLOAD_FILE_REQUEST) {
|
||||
return session.Download(file);
|
||||
}
|
||||
throw std::invalid_argument{"std::ofstream argument is only valid for ProceedHttpMethod::DOWNLOAD_FILE!"};
|
||||
}
|
||||
|
||||
Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write) {
|
||||
if (httpMethod == ProceedHttpMethod::DOWNLOAD_CALLBACK_REQUEST) {
|
||||
return session.Download(write);
|
||||
}
|
||||
throw std::invalid_argument{"WriteCallback argument is only valid for ProceedHttpMethod::DOWNLOAD_CALLBACK!"};
|
||||
}
|
||||
|
||||
std::vector<Response> InterceptorMulti::proceed(MultiPerform& multi) {
|
||||
return multi.proceed();
|
||||
}
|
||||
|
||||
void InterceptorMulti::PrepareDownloadSession(MultiPerform& multi, size_t sessions_index, const WriteCallback& write) {
|
||||
multi.PrepareDownloadSessions(sessions_index, write);
|
||||
}
|
||||
} // namespace cpr
|
||||
2
vendor/CPR/cpr/multipart.cpp
vendored
2
vendor/CPR/cpr/multipart.cpp
vendored
@@ -2,4 +2,6 @@
|
||||
|
||||
namespace cpr {
|
||||
Multipart::Multipart(const std::initializer_list<Part>& p_parts) : parts{p_parts} {}
|
||||
Multipart::Multipart(const std::vector<Part>& p_parts) : parts{p_parts} {}
|
||||
Multipart::Multipart(const std::vector<Part>&& p_parts) : parts{p_parts} {}
|
||||
} // namespace cpr
|
||||
|
||||
323
vendor/CPR/cpr/multiperform.cpp
vendored
Normal file
323
vendor/CPR/cpr/multiperform.cpp
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
#include "cpr/multiperform.h"
|
||||
|
||||
#include "cpr/interceptor.h"
|
||||
#include "cpr/response.h"
|
||||
#include "cpr/session.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
MultiPerform::MultiPerform() : multicurl_(new CurlMultiHolder()) {}
|
||||
|
||||
MultiPerform::~MultiPerform() {
|
||||
// Unlock all sessions
|
||||
for (const std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
pair.first->isUsedInMultiPerform = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::AddSession(std::shared_ptr<Session>& session, HttpMethod method) {
|
||||
// Check if this multiperform is download only
|
||||
if (((method != HttpMethod::DOWNLOAD_REQUEST && is_download_multi_perform) && method != HttpMethod::UNDEFINED) || (method == HttpMethod::DOWNLOAD_REQUEST && !is_download_multi_perform && !sessions_.empty())) {
|
||||
// Currently it is not possible to mix download and non-download methods, as download needs additional parameters
|
||||
throw std::invalid_argument("Failed to add session: Cannot mix download and non-download methods!");
|
||||
}
|
||||
|
||||
// Set download only if neccessary
|
||||
if (method == HttpMethod::DOWNLOAD_REQUEST) {
|
||||
is_download_multi_perform = true;
|
||||
}
|
||||
|
||||
// Add easy handle to multi handle
|
||||
const CURLMcode error_code = curl_multi_add_handle(multicurl_->handle, session->curl_->handle);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_add_handle() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Lock session to the multihandle
|
||||
session->isUsedInMultiPerform = true;
|
||||
|
||||
// Add session to sessions_
|
||||
sessions_.emplace_back(session, method);
|
||||
}
|
||||
|
||||
void MultiPerform::RemoveSession(const std::shared_ptr<Session>& session) {
|
||||
// Remove easy handle from multihandle
|
||||
const CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, session->curl_->handle);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_remove_handle() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Unock session
|
||||
session->isUsedInMultiPerform = false;
|
||||
|
||||
// Remove session from sessions_
|
||||
auto it = std::find_if(sessions_.begin(), sessions_.end(), [&session](const std::pair<std::shared_ptr<Session>, HttpMethod>& pair) { return session->curl_->handle == pair.first->curl_->handle; });
|
||||
if (it == sessions_.end()) {
|
||||
throw std::invalid_argument("Failed to find session!");
|
||||
}
|
||||
sessions_.erase(it);
|
||||
|
||||
// Reset download only if empty
|
||||
if (sessions_.empty()) {
|
||||
is_download_multi_perform = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::shared_ptr<Session>, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() {
|
||||
return sessions_;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::shared_ptr<Session>, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() const {
|
||||
return sessions_;
|
||||
}
|
||||
|
||||
void MultiPerform::DoMultiPerform() {
|
||||
// Do multi perform until every handle has finished
|
||||
int still_running{0};
|
||||
do {
|
||||
CURLMcode error_code = curl_multi_perform(multicurl_->handle, &still_running);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_perform() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (still_running) {
|
||||
const int timeout_ms{250};
|
||||
error_code = curl_multi_poll(multicurl_->handle, nullptr, 0, timeout_ms, nullptr);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_poll() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (still_running);
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::ReadMultiInfo(std::function<Response(Session&, CURLcode)>&& complete_function) {
|
||||
// Get infos and create Response objects
|
||||
std::vector<Response> responses;
|
||||
struct CURLMsg* info{nullptr};
|
||||
do {
|
||||
int msgq = 0;
|
||||
|
||||
// Read info from multihandle
|
||||
info = curl_multi_info_read(multicurl_->handle, &msgq);
|
||||
|
||||
if (info) {
|
||||
// Find current session
|
||||
auto it = std::find_if(sessions_.begin(), sessions_.end(), [&info](const std::pair<std::shared_ptr<Session>, HttpMethod>& pair) { return pair.first->curl_->handle == info->easy_handle; });
|
||||
if (it == sessions_.end()) {
|
||||
std::cerr << "Failed to find current session!" << std::endl;
|
||||
break;
|
||||
}
|
||||
const std::shared_ptr<Session> current_session = (*it).first;
|
||||
|
||||
// Add response object
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-union-access)
|
||||
responses.push_back(complete_function(*current_session, info->data.result));
|
||||
}
|
||||
} while (info);
|
||||
|
||||
// Sort response objects to match order of added sessions
|
||||
std::vector<Response> sorted_responses;
|
||||
for (const std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
Session& current_session = *(pair.first);
|
||||
auto it = std::find_if(responses.begin(), responses.end(), [¤t_session](const Response& response) { return current_session.curl_->handle == response.curl_->handle; });
|
||||
const Response current_response = *it;
|
||||
// Erase response from original vector to increase future search speed
|
||||
responses.erase(it);
|
||||
sorted_responses.push_back(current_response);
|
||||
}
|
||||
|
||||
return sorted_responses;
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::MakeRequest() {
|
||||
if (!interceptors_.empty()) {
|
||||
return intercept();
|
||||
}
|
||||
|
||||
DoMultiPerform();
|
||||
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.Complete(curl_error); });
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::MakeDownloadRequest() {
|
||||
if (!interceptors_.empty()) {
|
||||
return intercept();
|
||||
}
|
||||
|
||||
DoMultiPerform();
|
||||
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.CompleteDownload(curl_error); });
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareSessions() {
|
||||
for (const std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
switch (pair.second) {
|
||||
case HttpMethod::GET_REQUEST:
|
||||
pair.first->PrepareGet();
|
||||
break;
|
||||
case HttpMethod::POST_REQUEST:
|
||||
pair.first->PreparePost();
|
||||
break;
|
||||
case HttpMethod::PUT_REQUEST:
|
||||
pair.first->PreparePut();
|
||||
break;
|
||||
case HttpMethod::DELETE_REQUEST:
|
||||
pair.first->PrepareDelete();
|
||||
break;
|
||||
case HttpMethod::PATCH_REQUEST:
|
||||
pair.first->PreparePatch();
|
||||
break;
|
||||
case HttpMethod::HEAD_REQUEST:
|
||||
pair.first->PrepareHead();
|
||||
break;
|
||||
case HttpMethod::OPTIONS_REQUEST:
|
||||
pair.first->PrepareOptions();
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PrepareSessions failed: Undefined HttpMethod or download without arguments!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareDownloadSession(size_t sessions_index, const WriteCallback& write) {
|
||||
const std::pair<std::shared_ptr<Session>, HttpMethod>& pair = sessions_[sessions_index];
|
||||
switch (pair.second) {
|
||||
case HttpMethod::DOWNLOAD_REQUEST:
|
||||
pair.first->PrepareDownload(write);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareDownloadSession(size_t sessions_index, std::ofstream& file) {
|
||||
const std::pair<std::shared_ptr<Session>, HttpMethod>& pair = sessions_[sessions_index];
|
||||
switch (pair.second) {
|
||||
case HttpMethod::DOWNLOAD_REQUEST:
|
||||
pair.first->PrepareDownload(file);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::SetHttpMethod(HttpMethod method) {
|
||||
for (std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
pair.second = method;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareGet() {
|
||||
SetHttpMethod(HttpMethod::GET_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareDelete() {
|
||||
SetHttpMethod(HttpMethod::DELETE_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PreparePut() {
|
||||
SetHttpMethod(HttpMethod::PUT_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PreparePatch() {
|
||||
SetHttpMethod(HttpMethod::PATCH_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareHead() {
|
||||
SetHttpMethod(HttpMethod::HEAD_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareOptions() {
|
||||
SetHttpMethod(HttpMethod::OPTIONS_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PreparePost() {
|
||||
SetHttpMethod(HttpMethod::POST_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Get() {
|
||||
PrepareGet();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Delete() {
|
||||
PrepareDelete();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Put() {
|
||||
PreparePut();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Head() {
|
||||
PrepareHead();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Options() {
|
||||
PrepareOptions();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Patch() {
|
||||
PreparePatch();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Post() {
|
||||
PreparePost();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Perform() {
|
||||
PrepareSessions();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::proceed() {
|
||||
// Check if this multiperform mixes download and non download requests
|
||||
if (!sessions_.empty()) {
|
||||
const bool new_is_download_multi_perform = sessions_.front().second == HttpMethod::DOWNLOAD_REQUEST;
|
||||
|
||||
for (const std::pair<std::shared_ptr<Session>, HttpMethod>& s : sessions_) {
|
||||
const HttpMethod method = s.second;
|
||||
if ((new_is_download_multi_perform && method != HttpMethod::DOWNLOAD_REQUEST) || (!new_is_download_multi_perform && method == HttpMethod::DOWNLOAD_REQUEST)) {
|
||||
throw std::invalid_argument("Failed to proceed with session: Cannot mix download and non-download methods!");
|
||||
}
|
||||
}
|
||||
is_download_multi_perform = new_is_download_multi_perform;
|
||||
}
|
||||
|
||||
PrepareSessions();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::intercept() {
|
||||
// At least one interceptor exists -> Execute its intercept function
|
||||
const std::shared_ptr<InterceptorMulti> interceptor = interceptors_.front();
|
||||
interceptors_.pop();
|
||||
return interceptor->intercept(*this);
|
||||
}
|
||||
|
||||
void MultiPerform::AddInterceptor(const std::shared_ptr<InterceptorMulti>& pinterceptor) {
|
||||
interceptors_.push(pinterceptor);
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
6
vendor/CPR/cpr/parameters.cpp
vendored
6
vendor/CPR/cpr/parameters.cpp
vendored
@@ -1,10 +1,4 @@
|
||||
#include "cpr/parameters.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
Parameters::Parameters(const std::initializer_list<Parameter>& parameters) : CurlContainer<Parameter>(parameters) {}
|
||||
} // namespace cpr
|
||||
|
||||
6
vendor/CPR/cpr/payload.cpp
vendored
6
vendor/CPR/cpr/payload.cpp
vendored
@@ -1,10 +1,4 @@
|
||||
#include "cpr/payload.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
Payload::Payload(const std::initializer_list<Pair>& pairs) : CurlContainer<Pair>(pairs) {}
|
||||
} // namespace cpr
|
||||
|
||||
4
vendor/CPR/cpr/proxies.cpp
vendored
4
vendor/CPR/cpr/proxies.cpp
vendored
@@ -7,8 +7,8 @@
|
||||
|
||||
namespace cpr {
|
||||
|
||||
Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts)
|
||||
: hosts_{hosts} {}
|
||||
Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts) : hosts_{hosts} {}
|
||||
Proxies::Proxies(const std::map<std::string, std::string>& hosts) : hosts_{hosts} {}
|
||||
|
||||
bool Proxies::has(const std::string& protocol) const {
|
||||
return hosts_.count(protocol) > 0;
|
||||
|
||||
22
vendor/CPR/cpr/proxyauth.cpp
vendored
22
vendor/CPR/cpr/proxyauth.cpp
vendored
@@ -1,16 +1,30 @@
|
||||
#include "cpr/proxyauth.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
const char* EncodedAuthentication::GetAuthString() const noexcept {
|
||||
return auth_string_.c_str();
|
||||
EncodedAuthentication::~EncodedAuthentication() noexcept {
|
||||
util::secureStringClear(username);
|
||||
util::secureStringClear(password);
|
||||
}
|
||||
|
||||
const std::string& EncodedAuthentication::GetUsername() const {
|
||||
return username;
|
||||
}
|
||||
|
||||
const std::string& EncodedAuthentication::GetPassword() const {
|
||||
return password;
|
||||
}
|
||||
|
||||
bool ProxyAuthentication::has(const std::string& protocol) const {
|
||||
return proxyAuth_.count(protocol) > 0;
|
||||
}
|
||||
|
||||
const char* ProxyAuthentication::operator[](const std::string& protocol) {
|
||||
return proxyAuth_[protocol].GetAuthString();
|
||||
const char* ProxyAuthentication::GetUsername(const std::string& protocol) {
|
||||
return proxyAuth_[protocol].username.c_str();
|
||||
}
|
||||
|
||||
const char* ProxyAuthentication::GetPassword(const std::string& protocol) {
|
||||
return proxyAuth_[protocol].password.c_str();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
2
vendor/CPR/cpr/redirect.cpp
vendored
2
vendor/CPR/cpr/redirect.cpp
vendored
@@ -19,7 +19,7 @@ PostRedirectFlags operator~(PostRedirectFlags flag) {
|
||||
|
||||
PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
|
||||
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
||||
uint8_t tmp = static_cast<uint8_t>(lhs);
|
||||
const uint8_t tmp = static_cast<uint8_t>(lhs);
|
||||
lhs = static_cast<PostRedirectFlags>(tmp);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
26
vendor/CPR/cpr/response.cpp
vendored
26
vendor/CPR/cpr/response.cpp
vendored
@@ -1,12 +1,9 @@
|
||||
#include "cpr/response.h"
|
||||
|
||||
namespace cpr {
|
||||
Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
|
||||
std::string&& p_header_string, Cookies&& p_cookies = Cookies{},
|
||||
Error&& p_error = Error{})
|
||||
: curl_(std::move(curl)), text(std::move(p_text)), cookies(std::move(p_cookies)),
|
||||
error(std::move(p_error)) {
|
||||
header = cpr::util::parseHeader(p_header_string, &status_line, &reason);
|
||||
|
||||
Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string, Cookies&& p_cookies = Cookies{}, Error&& p_error = Error{}) : curl_(std::move(curl)), text(std::move(p_text)), cookies(std::move(p_cookies)), error(std::move(p_error)), raw_header(std::move(p_header_string)) {
|
||||
header = cpr::util::parseHeader(raw_header, &status_line, &reason);
|
||||
assert(curl_);
|
||||
assert(curl_->handle);
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code);
|
||||
@@ -14,7 +11,7 @@ Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
|
||||
char* url_string{nullptr};
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string);
|
||||
url = Url(url_string);
|
||||
#if LIBCURL_VERSION_NUM >= 0x073700
|
||||
#if LIBCURL_VERSION_NUM >= 0x073700 // 7.55.0
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_bytes);
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes);
|
||||
#else
|
||||
@@ -27,20 +24,21 @@ Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_REDIRECT_COUNT, &redirect_count);
|
||||
}
|
||||
|
||||
std::vector<std::string> Response::GetCertInfo() {
|
||||
std::vector<CertInfo> Response::GetCertInfos() {
|
||||
assert(curl_);
|
||||
assert(curl_->handle);
|
||||
curl_certinfo* ci{nullptr};
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci);
|
||||
|
||||
std::vector<std::string> info;
|
||||
info.resize(ci->num_of_certs);
|
||||
std::vector<CertInfo> cert_infos;
|
||||
for (int i = 0; i < ci->num_of_certs; i++) {
|
||||
// No way around here.
|
||||
CertInfo cert_info;
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
info[i] = std::string{ci->certinfo[i]->data};
|
||||
for (curl_slist* slist = ci->certinfo[i]; slist; slist = slist->next) {
|
||||
cert_info.emplace_back(std::string{slist->data});
|
||||
}
|
||||
cert_infos.emplace_back(cert_info);
|
||||
}
|
||||
|
||||
return info;
|
||||
return cert_infos;
|
||||
}
|
||||
} // namespace cpr
|
||||
|
||||
1320
vendor/CPR/cpr/session.cpp
vendored
1320
vendor/CPR/cpr/session.cpp
vendored
File diff suppressed because it is too large
Load Diff
70
vendor/CPR/cpr/ssl_ctx.cpp
vendored
Normal file
70
vendor/CPR/cpr/ssl_ctx.cpp
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
#include "cpr/ssl_ctx.h"
|
||||
|
||||
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
|
||||
#ifdef OPENSSL_BACKEND_USED
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
/**
|
||||
* The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL.
|
||||
* If an error is returned from the callback no attempt to establish a connection is made and
|
||||
* the perform operation will return the callback's error code.
|
||||
*
|
||||
* Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html
|
||||
* https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html
|
||||
*/
|
||||
CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) {
|
||||
// Check arguments
|
||||
if (raw_cert_buf == nullptr || sslctx == nullptr) {
|
||||
printf("Invalid callback arguments\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
// Setup pointer
|
||||
X509_STORE* store = nullptr;
|
||||
X509* cert = nullptr;
|
||||
BIO* bio = nullptr;
|
||||
char* cert_buf = static_cast<char*>(raw_cert_buf);
|
||||
|
||||
// Create a memory BIO using the data of cert_buf.
|
||||
// Note: It is assumed, that cert_buf is nul terminated and its length is determined by strlen.
|
||||
bio = BIO_new_mem_buf(cert_buf, -1);
|
||||
|
||||
// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
|
||||
PEM_read_bio_X509(bio, &cert, nullptr, nullptr);
|
||||
if (cert == nullptr) {
|
||||
printf("PEM_read_bio_X509 failed\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
// Get a pointer to the current certificate verification storage
|
||||
store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
|
||||
|
||||
// Add the loaded certificate to the verification storage
|
||||
const int status = X509_STORE_add_cert(store, cert);
|
||||
if (status == 0) {
|
||||
printf("Error adding certificate\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
// Decrement the reference count of the X509 structure cert and frees it up
|
||||
X509_free(cert);
|
||||
|
||||
// Free the entire bio chain
|
||||
BIO_free(bio);
|
||||
|
||||
// The CA certificate was loaded successfully into the verification storage
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif // OPENSSL_BACKEND_USED
|
||||
|
||||
#endif // SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
148
vendor/CPR/cpr/threadpool.cpp
vendored
Normal file
148
vendor/CPR/cpr/threadpool.cpp
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "cpr/threadpool.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
ThreadPool::ThreadPool(size_t min_threads, size_t max_threads, std::chrono::milliseconds max_idle_ms) : min_thread_num(min_threads), max_thread_num(max_threads), max_idle_time(max_idle_ms), status(STOP), cur_thread_num(0), idle_thread_num(0) {}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
int ThreadPool::Start(size_t start_threads) {
|
||||
if (status != STOP) {
|
||||
return -1;
|
||||
}
|
||||
status = RUNNING;
|
||||
if (start_threads < min_thread_num) {
|
||||
start_threads = min_thread_num;
|
||||
}
|
||||
if (start_threads > max_thread_num) {
|
||||
start_threads = max_thread_num;
|
||||
}
|
||||
for (size_t i = 0; i < start_threads; ++i) {
|
||||
CreateThread();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Stop() {
|
||||
if (status == STOP) {
|
||||
return -1;
|
||||
}
|
||||
status = STOP;
|
||||
task_cond.notify_all();
|
||||
for (auto& i : threads) {
|
||||
if (i.thread->joinable()) {
|
||||
i.thread->join();
|
||||
}
|
||||
}
|
||||
threads.clear();
|
||||
cur_thread_num = 0;
|
||||
idle_thread_num = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Pause() {
|
||||
if (status == RUNNING) {
|
||||
status = PAUSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Resume() {
|
||||
if (status == PAUSE) {
|
||||
status = RUNNING;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Wait() {
|
||||
while (true) {
|
||||
if (status == STOP || (tasks.empty() && idle_thread_num == cur_thread_num)) {
|
||||
break;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ThreadPool::CreateThread() {
|
||||
if (cur_thread_num >= max_thread_num) {
|
||||
return false;
|
||||
}
|
||||
std::thread* thread = new std::thread([this] {
|
||||
bool initialRun = true;
|
||||
while (status != STOP) {
|
||||
while (status == PAUSE) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
Task task;
|
||||
{
|
||||
std::unique_lock<std::mutex> locker(task_mutex);
|
||||
task_cond.wait_for(locker, std::chrono::milliseconds(max_idle_time), [this]() { return status == STOP || !tasks.empty(); });
|
||||
if (status == STOP) {
|
||||
return;
|
||||
}
|
||||
if (tasks.empty()) {
|
||||
if (cur_thread_num > min_thread_num) {
|
||||
DelThread(std::this_thread::get_id());
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!initialRun) {
|
||||
--idle_thread_num;
|
||||
}
|
||||
task = std::move(tasks.front());
|
||||
tasks.pop();
|
||||
}
|
||||
if (task) {
|
||||
task();
|
||||
++idle_thread_num;
|
||||
if (initialRun) {
|
||||
initialRun = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AddThread(thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThreadPool::AddThread(std::thread* thread) {
|
||||
thread_mutex.lock();
|
||||
++cur_thread_num;
|
||||
ThreadData data;
|
||||
data.thread = std::shared_ptr<std::thread>(thread);
|
||||
data.id = thread->get_id();
|
||||
data.status = RUNNING;
|
||||
data.start_time = time(nullptr);
|
||||
data.stop_time = 0;
|
||||
threads.emplace_back(data);
|
||||
thread_mutex.unlock();
|
||||
}
|
||||
|
||||
void ThreadPool::DelThread(std::thread::id id) {
|
||||
const time_t now = time(nullptr);
|
||||
thread_mutex.lock();
|
||||
--cur_thread_num;
|
||||
--idle_thread_num;
|
||||
auto iter = threads.begin();
|
||||
while (iter != threads.end()) {
|
||||
if (iter->status == STOP && now > iter->stop_time) {
|
||||
if (iter->thread->joinable()) {
|
||||
iter->thread->join();
|
||||
iter = threads.erase(iter);
|
||||
continue;
|
||||
}
|
||||
} else if (iter->id == id) {
|
||||
iter->status = STOP;
|
||||
iter->stop_time = time(nullptr);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
thread_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
4
vendor/CPR/cpr/timeout.cpp
vendored
4
vendor/CPR/cpr/timeout.cpp
vendored
@@ -14,12 +14,12 @@ long Timeout::Milliseconds() const {
|
||||
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
if (ms.count() > std::numeric_limits<long>::max()) {
|
||||
if (ms.count() > static_cast<std::chrono::milliseconds::rep>(std::numeric_limits<long>::max())) {
|
||||
throw std::overflow_error("cpr::Timeout: timeout value overflow: " + std::to_string(ms.count()) + " ms.");
|
||||
}
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
if (ms.count() < std::numeric_limits<long>::min()) {
|
||||
if (ms.count() < static_cast<std::chrono::milliseconds::rep>(std::numeric_limits<long>::min())) {
|
||||
throw std::underflow_error("cpr::Timeout: timeout value underflow: " + std::to_string(ms.count()) + " ms.");
|
||||
}
|
||||
|
||||
|
||||
126
vendor/CPR/cpr/util.cpp
vendored
126
vendor/CPR/cpr/util.cpp
vendored
@@ -3,23 +3,64 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
namespace util {
|
||||
#if defined(_Win32)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wreserved-macro-identifier") // Not all versions of clang support this flag like the one used on Ubuntu 18.04
|
||||
#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunused-macros"
|
||||
#endif
|
||||
// https://en.cppreference.com/w/c/string/byte/memset
|
||||
// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp, cppcoreguidelines-macro-usage)
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
namespace cpr::util {
|
||||
|
||||
enum class CurlHTTPCookieField : size_t {
|
||||
Domain = 0,
|
||||
IncludeSubdomains,
|
||||
Path,
|
||||
HttpsOnly,
|
||||
Expires,
|
||||
Name,
|
||||
Value,
|
||||
};
|
||||
|
||||
Cookies parseCookies(curl_slist* raw_cookies) {
|
||||
const int CURL_HTTP_COOKIE_SIZE = static_cast<int>(CurlHTTPCookieField::Value) + 1;
|
||||
Cookies cookies;
|
||||
for (curl_slist* nc = raw_cookies; nc; nc = nc->next) {
|
||||
std::vector<std::string> tokens = cpr::util::split(nc->data, '\t');
|
||||
std::string value = tokens.back();
|
||||
tokens.pop_back();
|
||||
cookies[tokens.back()] = value;
|
||||
while (tokens.size() < CURL_HTTP_COOKIE_SIZE) {
|
||||
tokens.emplace_back("");
|
||||
}
|
||||
const std::time_t expires = static_cast<time_t>(std::stoul(tokens.at(static_cast<size_t>(CurlHTTPCookieField::Expires))));
|
||||
cookies.emplace_back(Cookie{
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Name)),
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Value)),
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Domain)),
|
||||
isTrue(tokens.at(static_cast<size_t>(CurlHTTPCookieField::IncludeSubdomains))),
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Path)),
|
||||
isTrue(tokens.at(static_cast<size_t>(CurlHTTPCookieField::HttpsOnly))),
|
||||
std::chrono::system_clock::from_time_t(expires),
|
||||
});
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
@@ -36,7 +77,6 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
|
||||
}
|
||||
|
||||
for (std::string& line : lines) {
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
|
||||
if (line.substr(0, 5) == "HTTP/") {
|
||||
// set the status_line if it was given
|
||||
if ((status_line != nullptr) || (reason != nullptr)) {
|
||||
@@ -47,7 +87,7 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
|
||||
|
||||
// set the reason if it was given
|
||||
if (reason != nullptr) {
|
||||
size_t pos1 = line.find_first_of("\t ");
|
||||
const size_t pos1 = line.find_first_of("\t ");
|
||||
size_t pos2 = std::string::npos;
|
||||
if (pos1 != std::string::npos) {
|
||||
pos2 = line.find_first_of("\t ", pos1 + 1);
|
||||
@@ -62,7 +102,7 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
|
||||
}
|
||||
|
||||
if (line.length() > 0) {
|
||||
size_t found = line.find(':');
|
||||
const size_t found = line.find(':');
|
||||
if (found != std::string::npos) {
|
||||
std::string value = line.substr(found + 1);
|
||||
value.erase(0, value.find_first_not_of("\t "));
|
||||
@@ -105,7 +145,7 @@ size_t writeFunction(char* ptr, size_t size, size_t nmemb, std::string* data) {
|
||||
|
||||
size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file) {
|
||||
size *= nmemb;
|
||||
file->write(ptr, size);
|
||||
file->write(ptr, static_cast<std::streamsize>(size));
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -114,19 +154,8 @@ size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallba
|
||||
return (*write)({ptr, size}) ? size : 0;
|
||||
}
|
||||
|
||||
#if LIBCURL_VERSION_NUM < 0x072000
|
||||
int progressUserFunction(const ProgressCallback* progress, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow) {
|
||||
#else
|
||||
int progressUserFunction(const ProgressCallback* progress, curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow) {
|
||||
#endif
|
||||
return (*progress)(dltotal, dlnow, ultotal, ulnow) ? 0 : 1;
|
||||
}
|
||||
|
||||
int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size,
|
||||
const DebugCallback* debug) {
|
||||
(*debug)(DebugCallback::InfoType(type), std::string(data, size));
|
||||
int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size, const DebugCallback* debug) {
|
||||
(*debug)(static_cast<DebugCallback::InfoType>(type), std::string(data, size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -141,7 +170,7 @@ int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t s
|
||||
* std::string result = holder.urlEncode(input);
|
||||
**/
|
||||
std::string urlEncode(const std::string& s) {
|
||||
CurlHolder holder; // Create a temporary new holder for URL encoding
|
||||
const CurlHolder holder; // Create a temporary new holder for URL encoding
|
||||
return holder.urlEncode(s);
|
||||
}
|
||||
|
||||
@@ -156,9 +185,54 @@ std::string urlEncode(const std::string& s) {
|
||||
* std::string result = holder.urlDecode(input);
|
||||
**/
|
||||
std::string urlDecode(const std::string& s) {
|
||||
CurlHolder holder; // Create a temporary new holder for URL decoding
|
||||
const CurlHolder holder; // Create a temporary new holder for URL decoding
|
||||
return holder.urlDecode(s);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace cpr
|
||||
#if defined(__STDC_LIB_EXT1__)
|
||||
void secureStringClear(std::string& s) {
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
memset_s(&s.front(), s.length(), 0, s.length());
|
||||
s.clear();
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
void secureStringClear(std::string& s) {
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
SecureZeroMemory(&s.front(), s.length());
|
||||
s.clear();
|
||||
}
|
||||
#else
|
||||
#if defined(__clang__)
|
||||
#pragma clang optimize off // clang
|
||||
#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#pragma GCC push_options // g++
|
||||
#pragma GCC optimize("O0") // g++
|
||||
#endif
|
||||
void secureStringClear(std::string& s) {
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
// NOLINTNEXTLINE (readability-container-data-pointer)
|
||||
char* ptr = &(s[0]);
|
||||
memset(ptr, '\0', s.length());
|
||||
s.clear();
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang optimize on // clang
|
||||
#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#pragma GCC pop_options // g++
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool isTrue(const std::string& s) {
|
||||
std::string temp_string{s};
|
||||
std::transform(temp_string.begin(), temp_string.end(), temp_string.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
return temp_string == "true";
|
||||
}
|
||||
|
||||
} // namespace cpr::util
|
||||
|
||||
41
vendor/CPR/include/cpr/accept_encoding.h
vendored
Normal file
41
vendor/CPR/include/cpr/accept_encoding.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef CPR_ACCEPT_ENCODING_H
|
||||
#define CPR_ACCEPT_ENCODING_H
|
||||
|
||||
#include <curl/curlver.h>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
enum class AcceptEncodingMethods {
|
||||
identity,
|
||||
deflate,
|
||||
zlib,
|
||||
gzip,
|
||||
disabled,
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cert-err58-cpp)
|
||||
static const std::map<AcceptEncodingMethods, std::string> AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}};
|
||||
|
||||
class AcceptEncoding {
|
||||
public:
|
||||
AcceptEncoding() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods);
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
AcceptEncoding(const std::initializer_list<std::string>& methods);
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept;
|
||||
[[nodiscard]] const std::string getString() const;
|
||||
[[nodiscard]] bool disabled() const;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> methods_;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
270
vendor/CPR/include/cpr/api.h
vendored
270
vendor/CPR/include/cpr/api.h
vendored
@@ -7,27 +7,108 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "cpr/async.h"
|
||||
#include "cpr/async_wrapper.h"
|
||||
#include "cpr/auth.h"
|
||||
#include "cpr/bearer.h"
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/digest.h"
|
||||
#include "cpr/multipart.h"
|
||||
#include "cpr/ntlm.h"
|
||||
#include "cpr/multiperform.h"
|
||||
#include "cpr/payload.h"
|
||||
#include "cpr/response.h"
|
||||
#include "cpr/session.h"
|
||||
#include <utility>
|
||||
#include <cpr/filesystem.h>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
using AsyncResponse = std::future<Response>;
|
||||
using AsyncResponse = AsyncWrapper<Response>;
|
||||
|
||||
namespace priv {
|
||||
|
||||
template <bool processed_header, typename CurrentType>
|
||||
void set_option_internal(Session& session, CurrentType&& current_option) {
|
||||
session.SetOption(std::forward<CurrentType>(current_option));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void set_option_internal<true, Header>(Session& session, Header&& current_option) {
|
||||
// Header option was already provided -> Update previous header
|
||||
session.UpdateHeader(std::forward<Header>(current_option));
|
||||
}
|
||||
|
||||
template <bool processed_header, typename CurrentType, typename... Ts>
|
||||
void set_option_internal(Session& session, CurrentType&& current_option, Ts&&... ts) {
|
||||
set_option_internal<processed_header, CurrentType>(session, std::forward<CurrentType>(current_option));
|
||||
|
||||
if (std::is_same<CurrentType, Header>::value) {
|
||||
set_option_internal<true, Ts...>(session, std::forward<Ts>(ts)...);
|
||||
} else {
|
||||
set_option_internal<processed_header, Ts...>(session, std::forward<Ts>(ts)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void set_option(Session& session, Ts&&... ts) {
|
||||
std::initializer_list<int> ignore = { (session.SetOption(std::forward<Ts>(ts)), 0)... };
|
||||
(void)ignore;
|
||||
set_option_internal<false, Ts...>(session, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
// Idea: https://stackoverflow.com/a/19060157
|
||||
template <typename Tuple, std::size_t... I>
|
||||
void apply_set_option_internal(Session& session, Tuple&& t, std::index_sequence<I...>) {
|
||||
set_option(session, std::get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
// Idea: https://stackoverflow.com/a/19060157
|
||||
template <typename Tuple>
|
||||
void apply_set_option(Session& session, Tuple&& t) {
|
||||
using Indices = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
|
||||
apply_set_option_internal(session, std::forward<Tuple>(t), Indices());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setup_multiperform_internal(MultiPerform& multiperform, T&& t) {
|
||||
std::shared_ptr<Session> session = std::make_shared<Session>();
|
||||
apply_set_option(*session, t);
|
||||
multiperform.AddSession(session);
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
void setup_multiperform_internal(MultiPerform& multiperform, T&& t, Ts&&... ts) {
|
||||
std::shared_ptr<Session> session = std::make_shared<Session>();
|
||||
apply_set_option(*session, t);
|
||||
multiperform.AddSession(session);
|
||||
setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void setup_multiperform(MultiPerform& multiperform, Ts&&... ts) {
|
||||
setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
using session_action_t = cpr::Response (cpr::Session::*)();
|
||||
|
||||
template <session_action_t SessionAction, typename T>
|
||||
void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& parameters) {
|
||||
std::shared_ptr<std::atomic_bool> cancellation_state = std::make_shared<std::atomic_bool>(false);
|
||||
|
||||
std::function<Response(T)> execFn{[cancellation_state](T params) {
|
||||
if (cancellation_state->load()) {
|
||||
return Response{};
|
||||
}
|
||||
cpr::Session s{};
|
||||
s.SetCancellationParam(cancellation_state);
|
||||
apply_set_option(s, std::forward<T>(params));
|
||||
return std::invoke(SessionAction, s);
|
||||
}};
|
||||
responses.emplace_back(GlobalThreadPool::GetInstance()->Submit(std::move(execFn), std::forward<T>(parameters)), std::move(cancellation_state));
|
||||
}
|
||||
|
||||
template <session_action_t SessionAction, typename T, typename... Ts>
|
||||
void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& head, Ts&&... tail) {
|
||||
setup_multiasync<SessionAction>(responses, std::forward<T>(head));
|
||||
if constexpr (sizeof...(Ts) > 0) {
|
||||
setup_multiasync<SessionAction>(responses, std::forward<Ts>(tail)...);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
@@ -43,17 +124,14 @@ Response Get(Ts&&... ts) {
|
||||
// Get async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse GetAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Get callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto GetCallback(Then then, Ts... ts) -> std::future<decltype(then(Get(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto GetCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Post methods
|
||||
@@ -67,17 +145,14 @@ Response Post(Ts&&... ts) {
|
||||
// Post async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse PostAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Post callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto PostCallback(Then then, Ts... ts) -> std::future<decltype(then(Post(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto PostCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Put methods
|
||||
@@ -91,17 +166,14 @@ Response Put(Ts&&... ts) {
|
||||
// Put async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse PutAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Put callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto PutCallback(Then then, Ts... ts) -> std::future<decltype(then(Put(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto PutCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Head methods
|
||||
@@ -115,17 +187,14 @@ Response Head(Ts&&... ts) {
|
||||
// Head async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse HeadAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Head callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto HeadCallback(Then then, Ts... ts) -> std::future<decltype(then(Head(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto HeadCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Delete methods
|
||||
@@ -139,18 +208,14 @@ Response Delete(Ts&&... ts) {
|
||||
// Delete async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse DeleteAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Delete(std::move(ts_inner)...); },
|
||||
std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Delete callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto DeleteCallback(Then then, Ts... ts) -> std::future<decltype(then(Delete(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto DeleteCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Options methods
|
||||
@@ -164,19 +229,14 @@ Response Options(Ts&&... ts) {
|
||||
// Options async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse OptionsAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Options(std::move(ts_inner)...); },
|
||||
std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Options callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto OptionsCallback(Then then, Ts... ts)
|
||||
-> std::future<decltype(then(Options(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto OptionsCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Patch methods
|
||||
@@ -190,17 +250,14 @@ Response Patch(Ts&&... ts) {
|
||||
// Patch async methods
|
||||
template <typename... Ts>
|
||||
AsyncResponse PatchAsync(Ts... ts) {
|
||||
return std::async(
|
||||
std::launch::async, [](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
return cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
|
||||
}
|
||||
|
||||
// Patch callback methods
|
||||
template <typename Then, typename... Ts>
|
||||
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||||
auto PatchCallback(Then then, Ts... ts) -> std::future<decltype(then(Patch(std::move(ts)...)))> {
|
||||
return std::async(
|
||||
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); },
|
||||
std::move(then), std::move(ts)...);
|
||||
auto PatchCallback(Then then, Ts... ts) {
|
||||
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||||
}
|
||||
|
||||
// Download methods
|
||||
@@ -211,6 +268,18 @@ Response Download(std::ofstream& file, Ts&&... ts) {
|
||||
return session.Download(file);
|
||||
}
|
||||
|
||||
// Download async method
|
||||
template <typename... Ts>
|
||||
AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) {
|
||||
return AsyncWrapper{std::async(
|
||||
std::launch::async,
|
||||
[](fs::path local_path_, Ts... ts_) {
|
||||
std::ofstream f(local_path_.c_str());
|
||||
return Download(f, std::move(ts_)...);
|
||||
},
|
||||
std::move(local_path), std::move(ts)...)};
|
||||
}
|
||||
|
||||
// Download with user callback
|
||||
template <typename... Ts>
|
||||
Response Download(const WriteCallback& write, Ts&&... ts) {
|
||||
@@ -219,6 +288,105 @@ Response Download(const WriteCallback& write, Ts&&... ts) {
|
||||
return session.Download(write);
|
||||
}
|
||||
|
||||
// Multi requests
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiGet(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Get();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiDelete(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Delete();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiPut(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Put();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiHead(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Head();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiOptions(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Options();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiPatch(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Patch();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<Response> MultiPost(Ts&&... ts) {
|
||||
MultiPerform multiperform;
|
||||
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||||
return multiperform.Post();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiGetAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Get>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiDeleteAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Delete>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiHeadAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Head>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiOptionsAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Options>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiPatchAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Patch>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiPostAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Post>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
std::vector<AsyncWrapper<Response, true>> MultiPutAsync(Ts&&... ts) {
|
||||
std::vector<AsyncWrapper<Response, true>> ret{};
|
||||
priv::setup_multiasync<&cpr::Session::Put>(ret, std::forward<Ts>(ts)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
|
||||
50
vendor/CPR/include/cpr/async.h
vendored
Normal file
50
vendor/CPR/include/cpr/async.h
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef CPR_ASYNC_H
|
||||
#define CPR_ASYNC_H
|
||||
|
||||
#include "async_wrapper.h"
|
||||
#include "singleton.h"
|
||||
#include "threadpool.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class GlobalThreadPool : public ThreadPool {
|
||||
CPR_SINGLETON_DECL(GlobalThreadPool)
|
||||
protected:
|
||||
GlobalThreadPool() = default;
|
||||
|
||||
public:
|
||||
~GlobalThreadPool() override = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a wrapper for a future, calling future.get() will wait until the task is done and return RetType.
|
||||
* async(fn, args...)
|
||||
* async(std::bind(&Class::mem_fn, &obj))
|
||||
* async(std::mem_fn(&Class::mem_fn, &obj))
|
||||
**/
|
||||
template <class Fn, class... Args>
|
||||
auto async(Fn&& fn, Args&&... args) {
|
||||
return AsyncWrapper{GlobalThreadPool::GetInstance()->Submit(std::forward<Fn>(fn), std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
class async {
|
||||
public:
|
||||
static void startup(size_t min_threads = CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM, size_t max_threads = CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM, std::chrono::milliseconds max_idle_ms = CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME) {
|
||||
GlobalThreadPool* gtp = GlobalThreadPool::GetInstance();
|
||||
if (gtp->IsStarted()) {
|
||||
return;
|
||||
}
|
||||
gtp->SetMinThreadNum(min_threads);
|
||||
gtp->SetMaxThreadNum(max_threads);
|
||||
gtp->SetMaxIdleTime(max_idle_ms);
|
||||
gtp->Start();
|
||||
}
|
||||
|
||||
static void cleanup() {
|
||||
GlobalThreadPool::ExitInstance();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
140
vendor/CPR/include/cpr/async_wrapper.h
vendored
Normal file
140
vendor/CPR/include/cpr/async_wrapper.h
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
#ifndef CPR_ASYNC_WRAPPER_H
|
||||
#define CPR_ASYNC_WRAPPER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
#include "cpr/response.h"
|
||||
|
||||
namespace cpr {
|
||||
enum class [[nodiscard]] CancellationResult { failure, success, invalid_operation };
|
||||
|
||||
/**
|
||||
* A class template intended to wrap results of async operations (instances of std::future<T>)
|
||||
* and also provide extended capablilities relaed to these requests, for example cancellation.
|
||||
*
|
||||
* The RAII semantics are the same as std::future<T> - moveable, not copyable.
|
||||
*/
|
||||
template <typename T, bool isCancellable = false>
|
||||
class AsyncWrapper {
|
||||
private:
|
||||
std::future<T> future;
|
||||
std::shared_ptr<std::atomic_bool> is_cancelled;
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
explicit AsyncWrapper(std::future<T>&& f) : future{std::move(f)} {}
|
||||
AsyncWrapper(std::future<T>&& f, std::shared_ptr<std::atomic_bool>&& cancelledState) : future{std::move(f)}, is_cancelled{std::move(cancelledState)} {}
|
||||
|
||||
// Copy Semantics
|
||||
AsyncWrapper(const AsyncWrapper&) = delete;
|
||||
AsyncWrapper& operator=(const AsyncWrapper&) = delete;
|
||||
|
||||
// Move Semantics
|
||||
AsyncWrapper(AsyncWrapper&&) noexcept = default;
|
||||
AsyncWrapper& operator=(AsyncWrapper&&) noexcept = default;
|
||||
|
||||
// Destructor
|
||||
~AsyncWrapper() {
|
||||
if constexpr (isCancellable) {
|
||||
if(is_cancelled) {
|
||||
is_cancelled->store(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// These methods replicate the behaviour of std::future<T>
|
||||
[[nodiscard]] T get() {
|
||||
if constexpr (isCancellable) {
|
||||
if (IsCancelled()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::get on a cancelled request!"};
|
||||
}
|
||||
}
|
||||
if (!future.valid()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::get when the associated future instance is invalid!"};
|
||||
}
|
||||
return future.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const noexcept {
|
||||
if constexpr (isCancellable) {
|
||||
return !is_cancelled->load() && future.valid();
|
||||
} else {
|
||||
return future.valid();
|
||||
}
|
||||
}
|
||||
|
||||
void wait() const {
|
||||
if constexpr (isCancellable) {
|
||||
if (is_cancelled->load()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::wait when the associated future is invalid or cancelled!"};
|
||||
}
|
||||
}
|
||||
if (!future.valid()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"};
|
||||
}
|
||||
future.wait();
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
|
||||
if constexpr (isCancellable) {
|
||||
if (IsCancelled()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::wait_for when the associated future is cancelled!"};
|
||||
}
|
||||
}
|
||||
if (!future.valid()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"};
|
||||
}
|
||||
return future.wait_for(timeout_duration);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
|
||||
if constexpr (isCancellable) {
|
||||
if (IsCancelled()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is cancelled!"};
|
||||
}
|
||||
}
|
||||
if (!future.valid()) {
|
||||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"};
|
||||
}
|
||||
return future.wait_until(timeout_time);
|
||||
}
|
||||
|
||||
std::shared_future<T> share() noexcept {
|
||||
return future.share();
|
||||
}
|
||||
|
||||
// Cancellation-related methods
|
||||
CancellationResult Cancel() {
|
||||
if constexpr (!isCancellable) {
|
||||
return CancellationResult::invalid_operation;
|
||||
}
|
||||
if (!future.valid() || is_cancelled->load()) {
|
||||
return CancellationResult::invalid_operation;
|
||||
}
|
||||
is_cancelled->store(true);
|
||||
return CancellationResult::success;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsCancelled() const {
|
||||
if constexpr (isCancellable) {
|
||||
return is_cancelled->load();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Deduction guides
|
||||
template <typename T>
|
||||
AsyncWrapper(std::future<T>&&) -> AsyncWrapper<T, false>;
|
||||
|
||||
template <typename T>
|
||||
AsyncWrapper(std::future<T>&&, std::shared_ptr<std::atomic_bool>&&) -> AsyncWrapper<T, true>;
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
|
||||
#endif
|
||||
15
vendor/CPR/include/cpr/auth.h
vendored
15
vendor/CPR/include/cpr/auth.h
vendored
@@ -7,23 +7,24 @@
|
||||
|
||||
namespace cpr {
|
||||
|
||||
enum class AuthMode { BASIC, DIGEST, NTLM };
|
||||
|
||||
class Authentication {
|
||||
public:
|
||||
Authentication(const std::string& username, const std::string& password)
|
||||
: auth_string_{username + ":" + password} {}
|
||||
Authentication(std::string&& username, std::string&& password)
|
||||
: auth_string_{std::move(username) + ":" + std::move(password)} {}
|
||||
Authentication(std::string username, std::string password, AuthMode auth_mode) : auth_string_{std::move(username) + ":" + std::move(password)}, auth_mode_{std::move(auth_mode)} {}
|
||||
Authentication(const Authentication& other) = default;
|
||||
Authentication(Authentication&& old) noexcept = default;
|
||||
virtual ~Authentication() noexcept = default;
|
||||
~Authentication() noexcept;
|
||||
|
||||
Authentication& operator=(Authentication&& old) noexcept = default;
|
||||
Authentication& operator=(const Authentication& other) = default;
|
||||
|
||||
virtual const char* GetAuthString() const noexcept;
|
||||
const char* GetAuthString() const noexcept;
|
||||
AuthMode GetAuthMode() const noexcept;
|
||||
|
||||
protected:
|
||||
private:
|
||||
std::string auth_string_;
|
||||
AuthMode auth_mode_;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
8
vendor/CPR/include/cpr/bearer.h
vendored
8
vendor/CPR/include/cpr/bearer.h
vendored
@@ -1,8 +1,8 @@
|
||||
#ifndef CPR_BEARER_H
|
||||
#define CPR_BEARER_H
|
||||
|
||||
#include <string>
|
||||
#include <curl/curlver.h>
|
||||
#include <string>
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -14,12 +14,10 @@ namespace cpr {
|
||||
class Bearer {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Bearer(const std::string& token) : token_string_{token} {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Bearer(std::string&& token) : token_string_{std::move(token)} {}
|
||||
Bearer(std::string token) : token_string_{std::move(token)} {}
|
||||
Bearer(const Bearer& other) = default;
|
||||
Bearer(Bearer&& old) noexcept = default;
|
||||
virtual ~Bearer() noexcept = default;
|
||||
virtual ~Bearer() noexcept;
|
||||
|
||||
Bearer& operator=(Bearer&& old) noexcept = default;
|
||||
Bearer& operator=(const Bearer& other) = default;
|
||||
|
||||
28
vendor/CPR/include/cpr/body.h
vendored
28
vendor/CPR/include/cpr/body.h
vendored
@@ -1,24 +1,46 @@
|
||||
#ifndef CPR_BODY_H
|
||||
#define CPR_BODY_H
|
||||
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpr/buffer.h"
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/file.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class Body : public StringHolder<Body> {
|
||||
public:
|
||||
Body() : StringHolder<Body>() {}
|
||||
Body() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Body(const std::string& body) : StringHolder<Body>(body) {}
|
||||
Body(std::string body) : StringHolder<Body>(std::move(body)) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Body(std::string&& body) : StringHolder<Body>(std::move(body)) {}
|
||||
Body(std::string_view body) : StringHolder<Body>(body) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Body(const char* body) : StringHolder<Body>(body) {}
|
||||
Body(const char* str, size_t len) : StringHolder<Body>(str, len) {}
|
||||
Body(const std::initializer_list<std::string> args) : StringHolder<Body>(args) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
Body(const Buffer& buffer) : StringHolder<Body>(reinterpret_cast<const char*>(buffer.data), static_cast<size_t>(buffer.datalen)) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
Body(const File& file) {
|
||||
std::ifstream is(file.filepath, std::ifstream::binary);
|
||||
if (!is) {
|
||||
throw std::invalid_argument("Can't open the file for HTTP request body!");
|
||||
}
|
||||
|
||||
is.seekg(0, std::ios::end);
|
||||
const std::streampos length = is.tellg();
|
||||
is.seekg(0, std::ios::beg);
|
||||
std::string buffer;
|
||||
buffer.resize(static_cast<size_t>(length));
|
||||
is.read(buffer.data(), length);
|
||||
str_ = std::move(buffer);
|
||||
}
|
||||
Body(const Body& other) = default;
|
||||
Body(Body&& old) noexcept = default;
|
||||
~Body() override = default;
|
||||
|
||||
33
vendor/CPR/include/cpr/buffer.h
vendored
Normal file
33
vendor/CPR/include/cpr/buffer.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef CPR_BUFFER_H
|
||||
#define CPR_BUFFER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <cpr/filesystem.h>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
struct Buffer {
|
||||
using data_t = const char*;
|
||||
|
||||
template <typename Iterator>
|
||||
Buffer(Iterator begin, Iterator end, fs::path&& p_filename)
|
||||
// Ignored here since libcurl reqires a long.
|
||||
// There is also no way around the reinterpret_cast.
|
||||
// NOLINTNEXTLINE(google-runtime-int, cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
: data{reinterpret_cast<data_t>(&(*begin))}, datalen{static_cast<size_t>(std::distance(begin, end))}, filename(std::move(p_filename)) {
|
||||
is_random_access_iterator(begin, end);
|
||||
static_assert(sizeof(*begin) == 1, "Only byte buffers can be used");
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
typename std::enable_if<std::is_same<typename std::iterator_traits<Iterator>::iterator_category, std::random_access_iterator_tag>::value>::type is_random_access_iterator(Iterator /* begin */, Iterator /* end */) {}
|
||||
|
||||
data_t data;
|
||||
size_t datalen;
|
||||
const fs::path filename;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
42
vendor/CPR/include/cpr/callback.h
vendored
42
vendor/CPR/include/cpr/callback.h
vendored
@@ -3,7 +3,9 @@
|
||||
|
||||
#include "cprtypes.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace cpr {
|
||||
@@ -14,11 +16,11 @@ class ReadCallback {
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
ReadCallback(std::function<bool(char* buffer, size_t& size, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{-1}, callback{std::move(p_callback)} {}
|
||||
ReadCallback(cpr_off_t p_size, std::function<bool(char* buffer, size_t& size, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{p_size}, callback{std::move(p_callback)} {}
|
||||
bool operator()(char* buffer, size_t& size) const {
|
||||
return callback(buffer, size, userdata);
|
||||
bool operator()(char* buffer, size_t& buffer_size) const {
|
||||
return callback(buffer, buffer_size, userdata);
|
||||
}
|
||||
|
||||
intptr_t userdata;
|
||||
intptr_t userdata{};
|
||||
cpr_off_t size{};
|
||||
std::function<bool(char* buffer, size_t& size, intptr_t userdata)> callback;
|
||||
};
|
||||
@@ -32,7 +34,7 @@ class HeaderCallback {
|
||||
return callback(std::move(header), userdata);
|
||||
}
|
||||
|
||||
intptr_t userdata;
|
||||
intptr_t userdata{};
|
||||
std::function<bool(std::string header, intptr_t userdata)> callback;
|
||||
};
|
||||
|
||||
@@ -45,7 +47,7 @@ class WriteCallback {
|
||||
return callback(std::move(data), userdata);
|
||||
}
|
||||
|
||||
intptr_t userdata;
|
||||
intptr_t userdata{};
|
||||
std::function<bool(std::string data, intptr_t userdata)> callback;
|
||||
};
|
||||
|
||||
@@ -53,13 +55,13 @@ class ProgressCallback {
|
||||
public:
|
||||
ProgressCallback() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
ProgressCallback(std::function<bool(cpr_off_t downloadTotal, cpr_off_t downloadNow, cpr_off_t uploadTotal, cpr_off_t uploadNow, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {}
|
||||
bool operator()(cpr_off_t downloadTotal, cpr_off_t downloadNow, cpr_off_t uploadTotal, cpr_off_t uploadNow) const {
|
||||
ProgressCallback(std::function<bool(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {}
|
||||
bool operator()(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow) const {
|
||||
return callback(downloadTotal, downloadNow, uploadTotal, uploadNow, userdata);
|
||||
}
|
||||
|
||||
intptr_t userdata;
|
||||
std::function<bool(size_t downloadTotal, size_t downloadNow, size_t uploadTotal, size_t uploadNow, intptr_t userdata)> callback;
|
||||
intptr_t userdata{};
|
||||
std::function<bool(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow, intptr_t userdata)> callback;
|
||||
};
|
||||
|
||||
class DebugCallback {
|
||||
@@ -80,10 +82,30 @@ class DebugCallback {
|
||||
callback(type, std::move(data), userdata);
|
||||
}
|
||||
|
||||
intptr_t userdata;
|
||||
intptr_t userdata{};
|
||||
std::function<void(InfoType type, std::string data, intptr_t userdata)> callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Functor class for progress functions that will be used in cancellable requests.
|
||||
*/
|
||||
class CancellationCallback {
|
||||
public:
|
||||
CancellationCallback() = default;
|
||||
explicit CancellationCallback(std::shared_ptr<std::atomic_bool>&& cs) : cancellation_state{std::move(cs)} {}
|
||||
|
||||
CancellationCallback(std::shared_ptr<std::atomic_bool>&& cs, ProgressCallback& u_cb) : cancellation_state{std::move(cs)}, user_cb{std::reference_wrapper{u_cb}} {}
|
||||
|
||||
bool operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const;
|
||||
|
||||
void SetProgressCallback(ProgressCallback& u_cb);
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::atomic_bool> cancellation_state;
|
||||
std::optional<std::reference_wrapper<ProgressCallback>> user_cb;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
|
||||
37
vendor/CPR/include/cpr/cert_info.h
vendored
Normal file
37
vendor/CPR/include/cpr/cert_info.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef CPR_CERT_INFO_H
|
||||
#define CPR_CERT_INFO_H
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class CertInfo {
|
||||
private:
|
||||
std::vector<std::string> cert_info_;
|
||||
|
||||
public:
|
||||
CertInfo() = default;
|
||||
CertInfo(const CertInfo& other) = default;
|
||||
CertInfo(CertInfo&& old) = default;
|
||||
CertInfo(const std::initializer_list<std::string>& entry) : cert_info_{entry} {}
|
||||
~CertInfo() noexcept = default;
|
||||
|
||||
using iterator = std::vector<std::string>::iterator;
|
||||
using const_iterator = std::vector<std::string>::const_iterator;
|
||||
|
||||
std::string& operator[](const size_t& pos);
|
||||
iterator begin();
|
||||
iterator end();
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
void emplace_back(const std::string& str);
|
||||
void push_back(const std::string& str);
|
||||
void pop_back();
|
||||
};
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
61
vendor/CPR/include/cpr/cookies.h
vendored
61
vendor/CPR/include/cpr/cookies.h
vendored
@@ -2,12 +2,49 @@
|
||||
#define CPR_COOKIES_H
|
||||
|
||||
#include "cpr/curlholder.h"
|
||||
#include <chrono>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
/**
|
||||
* EXPIRES_STRING_SIZE is an explicitly static and const variable that could be only accessed within the same namespace and is immutable.
|
||||
* To be used for "std::array", the expression must have a constant value, so EXPIRES_STRING_SIZE must be a const value.
|
||||
**/
|
||||
static const std::size_t EXPIRES_STRING_SIZE = 100;
|
||||
|
||||
class Cookie {
|
||||
public:
|
||||
Cookie() = default;
|
||||
/**
|
||||
* Some notes for the default value used by expires:
|
||||
* std::chrono::system_clock::time_point::min() won't work on Windows due to the min, max clash there.
|
||||
* So we fall back to std::chrono::system_clock::from_time_t(0) for the minimum value here.
|
||||
**/
|
||||
Cookie(const std::string& name, const std::string& value, const std::string& domain = "", bool p_isIncludingSubdomains = false, const std::string& path = "/", bool p_isHttpsOnly = false, std::chrono::system_clock::time_point expires = std::chrono::system_clock::from_time_t(0)) : name_{name}, value_{value}, domain_{domain}, includeSubdomains_{p_isIncludingSubdomains}, path_{path}, httpsOnly_{p_isHttpsOnly}, expires_{expires} {}
|
||||
const std::string GetDomain() const;
|
||||
bool IsIncludingSubdomains() const;
|
||||
const std::string GetPath() const;
|
||||
bool IsHttpsOnly() const;
|
||||
const std::chrono::system_clock::time_point GetExpires() const;
|
||||
const std::string GetExpiresString() const;
|
||||
const std::string GetName() const;
|
||||
const std::string GetValue() const;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string value_;
|
||||
std::string domain_;
|
||||
bool includeSubdomains_{};
|
||||
std::string path_;
|
||||
bool httpsOnly_{};
|
||||
/**
|
||||
* TODO: Update the implementation using `std::chrono::utc_clock` of C++20
|
||||
**/
|
||||
std::chrono::system_clock::time_point expires_{};
|
||||
};
|
||||
|
||||
class Cookies {
|
||||
public:
|
||||
@@ -25,19 +62,16 @@ class Cookies {
|
||||
bool encode{true};
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Cookies(bool p_encode = true) : encode(p_encode) {}
|
||||
Cookies(const std::initializer_list<std::pair<const std::string, std::string>>& pairs,
|
||||
bool p_encode = true)
|
||||
: encode(p_encode), map_{pairs} {}
|
||||
Cookies(bool p_encode = true) : encode{p_encode} {}
|
||||
Cookies(const std::initializer_list<cpr::Cookie>& cookies, bool p_encode = true) : encode{p_encode}, cookies_{cookies} {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Cookies(const std::map<std::string, std::string>& map, bool p_encode = true)
|
||||
: encode(p_encode), map_{map} {}
|
||||
Cookies(const cpr::Cookie& cookie, bool p_encode = true) : encode{p_encode}, cookies_{cookie} {}
|
||||
|
||||
std::string& operator[](const std::string& key);
|
||||
std::string GetEncoded(const CurlHolder& holder) const;
|
||||
cpr::Cookie& operator[](size_t pos);
|
||||
const std::string GetEncoded(const CurlHolder& holder) const;
|
||||
|
||||
using iterator = std::map<std::string, std::string>::iterator;
|
||||
using const_iterator = std::map<std::string, std::string>::const_iterator;
|
||||
using iterator = std::vector<cpr::Cookie>::iterator;
|
||||
using const_iterator = std::vector<cpr::Cookie>::const_iterator;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
@@ -45,9 +79,12 @@ class Cookies {
|
||||
const_iterator end() const;
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
void emplace_back(const Cookie& str);
|
||||
void push_back(const Cookie& str);
|
||||
void pop_back();
|
||||
|
||||
protected:
|
||||
std::map<std::string, std::string> map_;
|
||||
std::vector<cpr::Cookie> cookies_;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
31
vendor/CPR/include/cpr/cpr.h
vendored
31
vendor/CPR/include/cpr/cpr.h
vendored
@@ -3,12 +3,43 @@
|
||||
|
||||
#include "cpr/api.h"
|
||||
#include "cpr/auth.h"
|
||||
#include "cpr/bearer.h"
|
||||
#include "cpr/callback.h"
|
||||
#include "cpr/cert_info.h"
|
||||
#include "cpr/connect_timeout.h"
|
||||
#include "cpr/cookies.h"
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/cprver.h"
|
||||
#include "cpr/curl_container.h"
|
||||
#include "cpr/curlholder.h"
|
||||
#include "cpr/error.h"
|
||||
#include "cpr/http_version.h"
|
||||
#include "cpr/interceptor.h"
|
||||
#include "cpr/interface.h"
|
||||
#include "cpr/limit_rate.h"
|
||||
#include "cpr/local_port.h"
|
||||
#include "cpr/local_port_range.h"
|
||||
#include "cpr/low_speed.h"
|
||||
#include "cpr/multipart.h"
|
||||
#include "cpr/multiperform.h"
|
||||
#include "cpr/parameters.h"
|
||||
#include "cpr/payload.h"
|
||||
#include "cpr/proxies.h"
|
||||
#include "cpr/proxyauth.h"
|
||||
#include "cpr/range.h"
|
||||
#include "cpr/redirect.h"
|
||||
#include "cpr/reserve_size.h"
|
||||
#include "cpr/resolve.h"
|
||||
#include "cpr/response.h"
|
||||
#include "cpr/session.h"
|
||||
#include "cpr/ssl_ctx.h"
|
||||
#include "cpr/ssl_options.h"
|
||||
#include "cpr/status_codes.h"
|
||||
#include "cpr/timeout.h"
|
||||
#include "cpr/unix_socket.h"
|
||||
#include "cpr/user_agent.h"
|
||||
#include "cpr/util.h"
|
||||
#include "cpr/verbose.h"
|
||||
|
||||
#define CPR_LIBCURL_VERSION_NUM LIBCURL_VERSION_NUM
|
||||
|
||||
|
||||
19
vendor/CPR/include/cpr/cprtypes.h
vendored
19
vendor/CPR/include/cpr/cprtypes.h
vendored
@@ -2,11 +2,13 @@
|
||||
#define CPR_CPR_TYPES_H
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/system.h>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
@@ -15,12 +17,21 @@ namespace cpr {
|
||||
**/
|
||||
using cpr_off_t = curl_off_t;
|
||||
|
||||
/**
|
||||
* The argument type for progress functions, dependent on libcurl version
|
||||
**/
|
||||
#if LIBCURL_VERSION_NUM < 0x072000
|
||||
using cpr_pf_arg_t = double;
|
||||
#else
|
||||
using cpr_pf_arg_t = cpr_off_t;
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class StringHolder {
|
||||
public:
|
||||
StringHolder() = default;
|
||||
explicit StringHolder(const std::string& str) : str_(str) {}
|
||||
explicit StringHolder(std::string&& str) : str_(std::move(str)) {}
|
||||
explicit StringHolder(std::string str) : str_(std::move(str)) {}
|
||||
explicit StringHolder(std::string_view str) : str_(str) {}
|
||||
explicit StringHolder(const char* str) : str_(str) {}
|
||||
StringHolder(const char* str, size_t len) : str_(str, len) {}
|
||||
StringHolder(const std::initializer_list<std::string> args) {
|
||||
@@ -107,9 +118,9 @@ class Url : public StringHolder<Url> {
|
||||
public:
|
||||
Url() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Url(const std::string& url) : StringHolder<Url>(url) {}
|
||||
Url(std::string url) : StringHolder<Url>(std::move(url)) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Url(std::string&& url) : StringHolder<Url>(std::move(url)) {}
|
||||
Url(std::string_view url) : StringHolder<Url>(url) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Url(const char* url) : StringHolder<Url>(url) {}
|
||||
Url(const char* str, size_t len) : StringHolder<Url>(std::string(str, len)) {}
|
||||
|
||||
30
vendor/CPR/include/cpr/cprver.h
vendored
Normal file
30
vendor/CPR/include/cpr/cprver.h
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef CPR_CPRVER_H
|
||||
#define CPR_CPRVER_H
|
||||
|
||||
/**
|
||||
* CPR version as a string.
|
||||
**/
|
||||
#define CPR_VERSION "1.10.4"
|
||||
|
||||
/**
|
||||
* CPR version split up into parts.
|
||||
**/
|
||||
#define CPR_VERSION_MAJOR 1
|
||||
#define CPR_VERSION_MINOR 10
|
||||
#define CPR_VERSION_PATCH 4
|
||||
|
||||
/**
|
||||
* CPR version as a single hex digit.
|
||||
* it can be split up into three parts:
|
||||
* 0xAABBCC
|
||||
* AA: The current CPR major version number in a hex format.
|
||||
* BB: The current CPR minor version number in a hex format.
|
||||
* CC: The current CPR patch version number in a hex format.
|
||||
*
|
||||
* Examples:
|
||||
* '0x010702' -> 01.07.02 -> CPR_VERSION: 1.7.2
|
||||
* '0xA13722' -> A1.37.22 -> CPR_VERSION: 161.55.34
|
||||
**/
|
||||
#define CPR_VERSION_NUM 0x011004
|
||||
|
||||
#endif
|
||||
8
vendor/CPR/include/cpr/curl_container.h
vendored
8
vendor/CPR/include/cpr/curl_container.h
vendored
@@ -12,18 +12,14 @@
|
||||
namespace cpr {
|
||||
|
||||
struct Parameter {
|
||||
Parameter(const std::string& p_key, const std::string& p_value) : key{p_key}, value{p_value} {}
|
||||
Parameter(std::string&& p_key, std::string&& p_value)
|
||||
: key{std::move(p_key)}, value{std::move(p_value)} {}
|
||||
Parameter(std::string p_key, std::string p_value) : key{std::move(p_key)}, value{std::move(p_value)} {}
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct Pair {
|
||||
Pair(const std::string& p_key, const std::string& p_value) : key(p_key), value(p_value) {}
|
||||
Pair(std::string&& p_key, std::string&& p_value)
|
||||
: key(std::move(p_key)), value(std::move(p_value)) {}
|
||||
Pair(std::string p_key, std::string p_value) : key(std::move(p_key)), value(std::move(p_value)) {}
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
|
||||
12
vendor/CPR/include/cpr/curlholder.h
vendored
12
vendor/CPR/include/cpr/curlholder.h
vendored
@@ -17,14 +17,18 @@ struct CurlHolder {
|
||||
* https://curl.haxx.se/libcurl/c/curl_easy_init.html
|
||||
* https://curl.haxx.se/libcurl/c/threadsafe.html
|
||||
**/
|
||||
// It does not make sense to make a std::mutex const.
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static std::mutex curl_easy_init_mutex_;
|
||||
|
||||
// Avoids initalization order problems in a static build
|
||||
static std::mutex& curl_easy_init_mutex_() {
|
||||
static std::mutex curl_easy_init_mutex_;
|
||||
return curl_easy_init_mutex_;
|
||||
}
|
||||
|
||||
public:
|
||||
CURL* handle{nullptr};
|
||||
struct curl_slist* chunk{nullptr};
|
||||
struct curl_httppost* formpost{nullptr};
|
||||
struct curl_slist* resolveCurlList{nullptr};
|
||||
curl_mime* multipart{nullptr};
|
||||
std::array<char, CURL_ERROR_SIZE> error{};
|
||||
|
||||
CurlHolder();
|
||||
|
||||
18
vendor/CPR/include/cpr/curlmultiholder.h
vendored
Normal file
18
vendor/CPR/include/cpr/curlmultiholder.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef CPR_CURLMULTIHOLDER_H
|
||||
#define CPR_CURLMULTIHOLDER_H
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class CurlMultiHolder {
|
||||
public:
|
||||
CurlMultiHolder();
|
||||
~CurlMultiHolder();
|
||||
|
||||
CURLM* handle{nullptr};
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
15
vendor/CPR/include/cpr/digest.h
vendored
15
vendor/CPR/include/cpr/digest.h
vendored
@@ -1,15 +0,0 @@
|
||||
#ifndef CPR_DIGEST_H
|
||||
#define CPR_DIGEST_H
|
||||
|
||||
#include "cpr/auth.h"
|
||||
|
||||
namespace cpr {
|
||||
class Digest : public Authentication {
|
||||
public:
|
||||
Digest(const std::string& username, const std::string& password)
|
||||
: Authentication{username, password} {}
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
5
vendor/CPR/include/cpr/error.h
vendored
5
vendor/CPR/include/cpr/error.h
vendored
@@ -27,6 +27,7 @@ enum class ErrorCode {
|
||||
GENERIC_SSL_ERROR,
|
||||
UNSUPPORTED_PROTOCOL,
|
||||
REQUEST_CANCELLED,
|
||||
TOO_MANY_REDIRECTS,
|
||||
UNKNOWN_ERROR = 1000,
|
||||
};
|
||||
|
||||
@@ -37,9 +38,7 @@ class Error {
|
||||
|
||||
Error() = default;
|
||||
|
||||
Error(const std::int32_t& curl_code, std::string&& p_error_message)
|
||||
: code{getErrorCodeForCurlError(curl_code)},
|
||||
message(std::move(p_error_message)) {}
|
||||
Error(const std::int32_t& curl_code, std::string&& p_error_message) : code{getErrorCodeForCurlError(curl_code)}, message(std::move(p_error_message)) {}
|
||||
|
||||
explicit operator bool() const {
|
||||
return code != ErrorCode::OK;
|
||||
|
||||
59
vendor/CPR/include/cpr/file.h
vendored
Normal file
59
vendor/CPR/include/cpr/file.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef CPR_FILE_H
|
||||
#define CPR_FILE_H
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cpr/filesystem.h>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
struct File {
|
||||
explicit File(std::string p_filepath, const std::string& p_overriden_filename = {}) : filepath(std::move(p_filepath)), overriden_filename(p_overriden_filename) {}
|
||||
|
||||
std::string filepath;
|
||||
std::string overriden_filename;
|
||||
|
||||
[[nodiscard]] bool hasOverridenFilename() const noexcept {
|
||||
return !overriden_filename.empty();
|
||||
}
|
||||
};
|
||||
|
||||
class Files {
|
||||
public:
|
||||
Files() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
Files(const File& p_file) : files{p_file} {}
|
||||
|
||||
Files(const Files& other) = default;
|
||||
Files(Files&& old) noexcept = default;
|
||||
|
||||
Files(const std::initializer_list<File>& p_files) : files{p_files} {}
|
||||
Files(const std::initializer_list<std::string>& p_filepaths);
|
||||
|
||||
~Files() noexcept = default;
|
||||
|
||||
Files& operator=(const Files& other);
|
||||
Files& operator=(Files&& old) noexcept;
|
||||
|
||||
using iterator = std::vector<File>::iterator;
|
||||
using const_iterator = std::vector<File>::const_iterator;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
[[nodiscard]] const_iterator begin() const;
|
||||
[[nodiscard]] const_iterator end() const;
|
||||
[[nodiscard]] const_iterator cbegin() const;
|
||||
[[nodiscard]] const_iterator cend() const;
|
||||
void emplace_back(const File& file);
|
||||
void push_back(const File& file);
|
||||
void pop_back();
|
||||
|
||||
private:
|
||||
std::vector<File> files;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
26
vendor/CPR/include/cpr/filesystem.h
vendored
Normal file
26
vendor/CPR/include/cpr/filesystem.h
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef CPR_FILESYSTEM_H
|
||||
#define CPR_FILESYSTEM_H
|
||||
|
||||
// Include filesystem into the namespace "fs" from either "filesystem" or "experimental/filesystem" or "boost/filesystem"
|
||||
#ifdef CPR_USE_BOOST_FILESYSTEM
|
||||
#define BOOST_FILESYSTEM_VERSION 4 // Use the latest, with the closest behavior to std::filesystem.
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace cpr {
|
||||
namespace fs = boost::filesystem;
|
||||
}
|
||||
// cppcheck-suppress preprocessorErrorDirective
|
||||
#elif __has_include(<filesystem>)
|
||||
#include <filesystem>
|
||||
namespace cpr {
|
||||
namespace fs = std::filesystem;
|
||||
}
|
||||
#elif __has_include("experimental/filesystem")
|
||||
#include <experimental/filesystem>
|
||||
namespace cpr {
|
||||
namespace fs = std::experimental::filesystem;
|
||||
}
|
||||
#else
|
||||
#error "Failed to include <filesystem> header!"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
67
vendor/CPR/include/cpr/http_version.h
vendored
Normal file
67
vendor/CPR/include/cpr/http_version.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef CPR_HTTP_VERSION_H
|
||||
#define CPR_HTTP_VERSION_H
|
||||
|
||||
#include <curl/curlver.h>
|
||||
|
||||
namespace cpr {
|
||||
enum class HttpVersionCode {
|
||||
/**
|
||||
* Let libcurl decide which version is the best.
|
||||
**/
|
||||
VERSION_NONE,
|
||||
/**
|
||||
* Enforce HTTP 1.0 requests.
|
||||
**/
|
||||
VERSION_1_0,
|
||||
/**
|
||||
* Enforce HTTP 1.1 requests.
|
||||
**/
|
||||
VERSION_1_1,
|
||||
#if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0
|
||||
/**
|
||||
* Attempt HTTP 2.0 requests.
|
||||
* Fallback to HTTP 1.1 if negotiation fails.
|
||||
**/
|
||||
VERSION_2_0,
|
||||
#endif
|
||||
#if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0
|
||||
/**
|
||||
* Attempt HTTP 2.0 for HTTPS requests only.
|
||||
* Fallback to HTTP 1.1 if negotiation fails.
|
||||
* HTTP 1.1 will be used for HTTP connections.
|
||||
**/
|
||||
VERSION_2_0_TLS,
|
||||
#endif
|
||||
#if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0
|
||||
/**
|
||||
* Start HTTP 2.0 for HTTP requests.
|
||||
* Requires prior knowledge that the server supports HTTP 2.0.
|
||||
* For HTTPS requests we will negotiate the protocol version in the TLS handshake.
|
||||
**/
|
||||
VERSION_2_0_PRIOR_KNOWLEDGE,
|
||||
#endif
|
||||
#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0
|
||||
/**
|
||||
* Attempt HTTP 3.0 requests.
|
||||
* Requires prior knowledge that the server supports HTTP 3.0 since there is no gracefully downgrade.
|
||||
* Fallback to HTTP 1.1 if negotiation fails.
|
||||
**/
|
||||
VERSION_3_0
|
||||
#endif
|
||||
};
|
||||
|
||||
class HttpVersion {
|
||||
public:
|
||||
/**
|
||||
* The HTTP version that should be used by libcurl when initiating a HTTP(S) connection.
|
||||
* Default: HttpVersionCode::VERSION_NONE
|
||||
**/
|
||||
HttpVersionCode code = HttpVersionCode::VERSION_NONE;
|
||||
|
||||
HttpVersion() = default;
|
||||
explicit HttpVersion(HttpVersionCode _code) : code(_code) {}
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
74
vendor/CPR/include/cpr/interceptor.h
vendored
Normal file
74
vendor/CPR/include/cpr/interceptor.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef CPR_INTERCEPTOR_H
|
||||
#define CPR_INTERCEPTOR_H
|
||||
|
||||
#include "cpr/multiperform.h"
|
||||
#include "cpr/response.h"
|
||||
#include "cpr/session.h"
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
class Interceptor {
|
||||
public:
|
||||
enum class ProceedHttpMethod {
|
||||
GET_REQUEST = 0,
|
||||
POST_REQUEST,
|
||||
PUT_REQUEST,
|
||||
DELETE_REQUEST,
|
||||
PATCH_REQUEST,
|
||||
HEAD_REQUEST,
|
||||
OPTIONS_REQUEST,
|
||||
DOWNLOAD_CALLBACK_REQUEST,
|
||||
DOWNLOAD_FILE_REQUEST,
|
||||
};
|
||||
|
||||
Interceptor() = default;
|
||||
Interceptor(const Interceptor& other) = default;
|
||||
Interceptor(Interceptor&& old) = default;
|
||||
virtual ~Interceptor() = default;
|
||||
|
||||
Interceptor& operator=(const Interceptor& other) = default;
|
||||
Interceptor& operator=(Interceptor&& old) = default;
|
||||
|
||||
virtual Response intercept(Session& session) = 0;
|
||||
|
||||
protected:
|
||||
static Response proceed(Session& session);
|
||||
static Response proceed(Session& session, ProceedHttpMethod httpMethod);
|
||||
static Response proceed(Session& session, ProceedHttpMethod httpMethod, std::ofstream& file);
|
||||
static Response proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write);
|
||||
};
|
||||
|
||||
class InterceptorMulti {
|
||||
public:
|
||||
enum class ProceedHttpMethod {
|
||||
GET_REQUEST = 0,
|
||||
POST_REQUEST,
|
||||
PUT_REQUEST,
|
||||
DELETE_REQUEST,
|
||||
PATCH_REQUEST,
|
||||
HEAD_REQUEST,
|
||||
OPTIONS_REQUEST,
|
||||
DOWNLOAD_CALLBACK_REQUEST,
|
||||
DOWNLOAD_FILE_REQUEST,
|
||||
};
|
||||
|
||||
InterceptorMulti() = default;
|
||||
InterceptorMulti(const InterceptorMulti& other) = default;
|
||||
InterceptorMulti(InterceptorMulti&& old) = default;
|
||||
virtual ~InterceptorMulti() = default;
|
||||
|
||||
InterceptorMulti& operator=(const InterceptorMulti& other) = default;
|
||||
InterceptorMulti& operator=(InterceptorMulti&& old) = default;
|
||||
|
||||
virtual std::vector<Response> intercept(MultiPerform& multi) = 0;
|
||||
|
||||
protected:
|
||||
static std::vector<Response> proceed(MultiPerform& multi);
|
||||
|
||||
static void PrepareDownloadSession(MultiPerform& multi, size_t sessions_index, const WriteCallback& write);
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
|
||||
#endif
|
||||
8
vendor/CPR/include/cpr/interface.h
vendored
8
vendor/CPR/include/cpr/interface.h
vendored
@@ -10,11 +10,11 @@ namespace cpr {
|
||||
|
||||
class Interface : public StringHolder<Interface> {
|
||||
public:
|
||||
Interface() : StringHolder<Interface>() {}
|
||||
Interface() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Interface(const std::string& iface) : StringHolder<Interface>(iface) {}
|
||||
Interface(std::string iface) : StringHolder<Interface>(std::move(iface)) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Interface(std::string&& iface) : StringHolder<Interface>(std::move(iface)) {}
|
||||
Interface(std::string_view iface) : StringHolder<Interface>(iface) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Interface(const char* iface) : StringHolder<Interface>(iface) {}
|
||||
Interface(const char* str, size_t len) : StringHolder<Interface>(str, len) {}
|
||||
@@ -29,4 +29,4 @@ class Interface : public StringHolder<Interface> {
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
5
vendor/CPR/include/cpr/limit_rate.h
vendored
5
vendor/CPR/include/cpr/limit_rate.h
vendored
@@ -7,8 +7,7 @@ namespace cpr {
|
||||
|
||||
class LimitRate {
|
||||
public:
|
||||
LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate)
|
||||
: downrate(p_downrate), uprate(p_uprate) {}
|
||||
LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate) : downrate(p_downrate), uprate(p_uprate) {}
|
||||
|
||||
std::int64_t downrate = 0;
|
||||
std::int64_t uprate = 0;
|
||||
@@ -16,4 +15,4 @@ class LimitRate {
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
23
vendor/CPR/include/cpr/local_port.h
vendored
Normal file
23
vendor/CPR/include/cpr/local_port.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef CPR_LOCAL_PORT_H
|
||||
#define CPR_LOCAL_PORT_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class LocalPort {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
LocalPort(const std::uint16_t p_localport) : localport_(p_localport) {}
|
||||
|
||||
operator std::uint16_t() const {
|
||||
return localport_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint16_t localport_ = 0;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
23
vendor/CPR/include/cpr/local_port_range.h
vendored
Normal file
23
vendor/CPR/include/cpr/local_port_range.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef CPR_LOCAL_PORT_RANGE_H
|
||||
#define CPR_LOCAL_PORT_RANGE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class LocalPortRange {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
LocalPortRange(const std::uint16_t p_localportrange) : localportrange_(p_localportrange) {}
|
||||
|
||||
operator std::uint16_t() const {
|
||||
return localportrange_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint16_t localportrange_ = 0;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
62
vendor/CPR/include/cpr/multipart.h
vendored
62
vendor/CPR/include/cpr/multipart.h
vendored
@@ -7,69 +7,35 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "file.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
struct File {
|
||||
explicit File(std::string&& p_filepath) : filepath(std::move(p_filepath)) {}
|
||||
explicit File(const std::string& p_filepath) : filepath(p_filepath) {}
|
||||
const std::string filepath;
|
||||
};
|
||||
|
||||
struct Buffer {
|
||||
using data_t = const unsigned char*;
|
||||
|
||||
template <typename Iterator>
|
||||
Buffer(Iterator begin, Iterator end, std::string&& p_filename)
|
||||
// Ignored here since libcurl reqires a long.
|
||||
// There is also no way around the reinterpret_cast.
|
||||
// NOLINTNEXTLINE(google-runtime-int, cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
: data{reinterpret_cast<data_t>(&(*begin))}, datalen{static_cast<long>(
|
||||
std::distance(begin, end))},
|
||||
filename(std::move(p_filename)) {
|
||||
is_random_access_iterator(begin, end);
|
||||
static_assert(sizeof(*begin) == 1, "only byte buffers can be used");
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
typename std::enable_if<std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::random_access_iterator_tag>::value>::type
|
||||
is_random_access_iterator(Iterator /* begin */, Iterator /* end */) {}
|
||||
|
||||
data_t data;
|
||||
// Ignored here since libcurl reqires a long:
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
long datalen;
|
||||
const std::string filename;
|
||||
};
|
||||
|
||||
struct Part {
|
||||
Part(const std::string& p_name, const std::string& p_value, const std::string& p_content_type = {})
|
||||
: name{p_name}, value{p_value},
|
||||
content_type{p_content_type}, is_file{false}, is_buffer{false} {}
|
||||
Part(const std::string& p_name, const std::int32_t& p_value, const std::string& p_content_type = {})
|
||||
: name{p_name}, value{std::to_string(p_value)},
|
||||
content_type{p_content_type}, is_file{false}, is_buffer{false} {}
|
||||
Part(const std::string& p_name, const File& file, const std::string& p_content_type = {})
|
||||
: name{p_name}, value{file.filepath},
|
||||
content_type{p_content_type}, is_file{true}, is_buffer{false} {}
|
||||
Part(const std::string& p_name, const Buffer& buffer, const std::string& p_content_type = {})
|
||||
: name{p_name}, value{buffer.filename}, content_type{p_content_type}, data{buffer.data},
|
||||
datalen{buffer.datalen}, is_file{false}, is_buffer{true} {}
|
||||
Part(const std::string& p_name, const std::string& p_value, const std::string& p_content_type = {}) : name{p_name}, value{p_value}, content_type{p_content_type}, is_file{false}, is_buffer{false} {}
|
||||
Part(const std::string& p_name, const std::int32_t& p_value, const std::string& p_content_type = {}) : name{p_name}, value{std::to_string(p_value)}, content_type{p_content_type}, is_file{false}, is_buffer{false} {}
|
||||
Part(const std::string& p_name, const Files& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {}
|
||||
Part(const std::string& p_name, Files&& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {}
|
||||
Part(const std::string& p_name, const Buffer& buffer, const std::string& p_content_type = {}) : name{p_name}, value{buffer.filename.string()}, content_type{p_content_type}, data{buffer.data}, datalen{buffer.datalen}, is_file{false}, is_buffer{true} {}
|
||||
|
||||
std::string name;
|
||||
// We don't use fs::path here, as this leads to problems using windows
|
||||
std::string value;
|
||||
std::string content_type;
|
||||
Buffer::data_t data{nullptr};
|
||||
// Ignored here since libcurl reqires a long:
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
long datalen{0};
|
||||
size_t datalen{0};
|
||||
bool is_file;
|
||||
bool is_buffer;
|
||||
|
||||
Files files;
|
||||
};
|
||||
|
||||
class Multipart {
|
||||
public:
|
||||
Multipart(const std::initializer_list<Part>& parts);
|
||||
Multipart(const std::vector<Part>& parts);
|
||||
Multipart(const std::vector<Part>&& parts);
|
||||
|
||||
std::vector<Part> parts;
|
||||
};
|
||||
|
||||
137
vendor/CPR/include/cpr/multiperform.h
vendored
Normal file
137
vendor/CPR/include/cpr/multiperform.h
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef CPR_MULTIPERFORM_H
|
||||
#define CPR_MULTIPERFORM_H
|
||||
|
||||
#include "cpr/curlmultiholder.h"
|
||||
#include "cpr/response.h"
|
||||
#include "cpr/session.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class InterceptorMulti;
|
||||
|
||||
class MultiPerform {
|
||||
public:
|
||||
enum class HttpMethod {
|
||||
UNDEFINED = 0,
|
||||
GET_REQUEST,
|
||||
POST_REQUEST,
|
||||
PUT_REQUEST,
|
||||
DELETE_REQUEST,
|
||||
PATCH_REQUEST,
|
||||
HEAD_REQUEST,
|
||||
OPTIONS_REQUEST,
|
||||
DOWNLOAD_REQUEST,
|
||||
};
|
||||
|
||||
MultiPerform();
|
||||
MultiPerform(const MultiPerform& other) = delete;
|
||||
MultiPerform(MultiPerform&& old) = default;
|
||||
~MultiPerform();
|
||||
|
||||
MultiPerform& operator=(const MultiPerform& other) = delete;
|
||||
MultiPerform& operator=(MultiPerform&& old) noexcept = default;
|
||||
|
||||
std::vector<Response> Get();
|
||||
std::vector<Response> Delete();
|
||||
template <typename... DownloadArgTypes>
|
||||
std::vector<Response> Download(DownloadArgTypes... args);
|
||||
std::vector<Response> Put();
|
||||
std::vector<Response> Head();
|
||||
std::vector<Response> Options();
|
||||
std::vector<Response> Patch();
|
||||
std::vector<Response> Post();
|
||||
|
||||
std::vector<Response> Perform();
|
||||
template <typename... DownloadArgTypes>
|
||||
std::vector<Response> PerformDownload(DownloadArgTypes... args);
|
||||
|
||||
void AddSession(std::shared_ptr<Session>& session, HttpMethod method = HttpMethod::UNDEFINED);
|
||||
void RemoveSession(const std::shared_ptr<Session>& session);
|
||||
std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>>& GetSessions();
|
||||
[[nodiscard]] const std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>>& GetSessions() const;
|
||||
|
||||
void AddInterceptor(const std::shared_ptr<InterceptorMulti>& pinterceptor);
|
||||
|
||||
private:
|
||||
// Interceptors should be able to call the private proceed() and PrepareDownloadSessions() functions
|
||||
friend InterceptorMulti;
|
||||
|
||||
void SetHttpMethod(HttpMethod method);
|
||||
|
||||
void PrepareSessions();
|
||||
template <typename CurrentDownloadArgType, typename... DownloadArgTypes>
|
||||
void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args);
|
||||
template <typename CurrentDownloadArgType>
|
||||
void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg);
|
||||
void PrepareDownloadSession(size_t sessions_index, std::ofstream& file);
|
||||
void PrepareDownloadSession(size_t sessions_index, const WriteCallback& write);
|
||||
|
||||
void PrepareGet();
|
||||
void PrepareDelete();
|
||||
void PreparePut();
|
||||
void PreparePatch();
|
||||
void PrepareHead();
|
||||
void PrepareOptions();
|
||||
void PreparePost();
|
||||
template <typename... DownloadArgTypes>
|
||||
void PrepareDownload(DownloadArgTypes... args);
|
||||
|
||||
std::vector<Response> intercept();
|
||||
std::vector<Response> proceed();
|
||||
std::vector<Response> MakeRequest();
|
||||
std::vector<Response> MakeDownloadRequest();
|
||||
|
||||
void DoMultiPerform();
|
||||
std::vector<Response> ReadMultiInfo(std::function<Response(Session&, CURLcode)>&& complete_function);
|
||||
|
||||
std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>> sessions_;
|
||||
std::unique_ptr<CurlMultiHolder> multicurl_;
|
||||
bool is_download_multi_perform{false};
|
||||
|
||||
std::queue<std::shared_ptr<InterceptorMulti>> interceptors_;
|
||||
};
|
||||
|
||||
template <typename CurrentDownloadArgType>
|
||||
void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg) {
|
||||
PrepareDownloadSession(sessions_index, current_arg);
|
||||
}
|
||||
|
||||
template <typename CurrentDownloadArgType, typename... DownloadArgTypes>
|
||||
void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args) {
|
||||
PrepareDownloadSession(sessions_index, current_arg);
|
||||
PrepareDownloadSessions<DownloadArgTypes...>(sessions_index + 1, args...);
|
||||
}
|
||||
|
||||
|
||||
template <typename... DownloadArgTypes>
|
||||
void MultiPerform::PrepareDownload(DownloadArgTypes... args) {
|
||||
SetHttpMethod(HttpMethod::DOWNLOAD_REQUEST);
|
||||
PrepareDownloadSessions<DownloadArgTypes...>(0, args...);
|
||||
}
|
||||
|
||||
template <typename... DownloadArgTypes>
|
||||
std::vector<Response> MultiPerform::Download(DownloadArgTypes... args) {
|
||||
if (sizeof...(args) != sessions_.size()) {
|
||||
throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!");
|
||||
}
|
||||
PrepareDownload(args...);
|
||||
return MakeDownloadRequest();
|
||||
}
|
||||
|
||||
template <typename... DownloadArgTypes>
|
||||
std::vector<Response> MultiPerform::PerformDownload(DownloadArgTypes... args) {
|
||||
if (sizeof...(args) != sessions_.size()) {
|
||||
throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!");
|
||||
}
|
||||
PrepareDownloadSessions<DownloadArgTypes...>(0, args...);
|
||||
return MakeDownloadRequest();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
15
vendor/CPR/include/cpr/ntlm.h
vendored
15
vendor/CPR/include/cpr/ntlm.h
vendored
@@ -1,15 +0,0 @@
|
||||
#ifndef CPR_NTLM_H
|
||||
#define CPR_NTLM_H
|
||||
|
||||
#include "cpr/auth.h"
|
||||
|
||||
namespace cpr {
|
||||
class NTLM : public Authentication {
|
||||
public:
|
||||
NTLM(const std::string& username, const std::string& password)
|
||||
: Authentication{username, password} {}
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
2
vendor/CPR/include/cpr/parameters.h
vendored
2
vendor/CPR/include/cpr/parameters.h
vendored
@@ -10,7 +10,7 @@ namespace cpr {
|
||||
class Parameters : public CurlContainer<Parameter> {
|
||||
public:
|
||||
Parameters() = default;
|
||||
Parameters(const std::initializer_list<Parameter>& parameters);
|
||||
Parameters(const std::initializer_list<Parameter>& parameters) : CurlContainer<Parameter>(parameters) {}
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
2
vendor/CPR/include/cpr/payload.h
vendored
2
vendor/CPR/include/cpr/payload.h
vendored
@@ -15,7 +15,7 @@ class Payload : public CurlContainer<Pair> {
|
||||
Add(*pair);
|
||||
}
|
||||
}
|
||||
Payload(const std::initializer_list<Pair>& pairs);
|
||||
Payload(const std::initializer_list<Pair>& pairs) : CurlContainer<Pair>(pairs) {}
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
1
vendor/CPR/include/cpr/proxies.h
vendored
1
vendor/CPR/include/cpr/proxies.h
vendored
@@ -10,6 +10,7 @@ class Proxies {
|
||||
public:
|
||||
Proxies() = default;
|
||||
Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts);
|
||||
Proxies(const std::map<std::string, std::string>& hosts);
|
||||
|
||||
bool has(const std::string& protocol) const;
|
||||
const std::string& operator[](const std::string& protocol);
|
||||
|
||||
26
vendor/CPR/include/cpr/proxyauth.h
vendored
26
vendor/CPR/include/cpr/proxyauth.h
vendored
@@ -3,36 +3,44 @@
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "cpr/auth.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
class ProxyAuthentication;
|
||||
|
||||
class EncodedAuthentication {
|
||||
friend ProxyAuthentication;
|
||||
|
||||
public:
|
||||
EncodedAuthentication() : auth_string_{""} {}
|
||||
EncodedAuthentication(const std::string& username, const std::string& password) : auth_string_{cpr::util::urlEncode(username) + ":" + cpr::util::urlEncode(password)} {}
|
||||
EncodedAuthentication(std::string&& username, std::string&& password) : auth_string_{cpr::util::urlEncode(std::move(username)) + ":" + cpr::util::urlEncode(std::move(password))} {}
|
||||
EncodedAuthentication() = default;
|
||||
EncodedAuthentication(const std::string& p_username, const std::string& p_password) : username(util::urlEncode(p_username)), password(util::urlEncode(p_password)) {}
|
||||
EncodedAuthentication(const EncodedAuthentication& other) = default;
|
||||
EncodedAuthentication(EncodedAuthentication&& old) noexcept = default;
|
||||
virtual ~EncodedAuthentication() noexcept = default;
|
||||
virtual ~EncodedAuthentication() noexcept;
|
||||
|
||||
EncodedAuthentication& operator=(EncodedAuthentication&& old) noexcept = default;
|
||||
EncodedAuthentication& operator=(const EncodedAuthentication& other) = default;
|
||||
|
||||
const char* GetAuthString() const noexcept;
|
||||
[[nodiscard]] const std::string& GetUsername() const;
|
||||
[[nodiscard]] const std::string& GetPassword() const;
|
||||
|
||||
protected:
|
||||
std::string auth_string_;
|
||||
private:
|
||||
std::string username;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
class ProxyAuthentication {
|
||||
public:
|
||||
ProxyAuthentication() = default;
|
||||
ProxyAuthentication(const std::initializer_list<std::pair<const std::string, EncodedAuthentication>>& auths) : proxyAuth_{auths} {}
|
||||
explicit ProxyAuthentication(const std::map<std::string, EncodedAuthentication>& auths) : proxyAuth_{auths} {}
|
||||
|
||||
bool has(const std::string& protocol) const;
|
||||
const char* operator[](const std::string& protocol);
|
||||
[[nodiscard]] bool has(const std::string& protocol) const;
|
||||
const char* GetUsername(const std::string& protocol);
|
||||
const char* GetPassword(const std::string& protocol);
|
||||
|
||||
private:
|
||||
std::map<std::string, EncodedAuthentication> proxyAuth_;
|
||||
|
||||
44
vendor/CPR/include/cpr/range.h
vendored
Normal file
44
vendor/CPR/include/cpr/range.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef CPR_RANGE_H
|
||||
#define CPR_RANGE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class Range {
|
||||
public:
|
||||
Range(const std::optional<std::int64_t> p_resume_from = std::nullopt, const std::optional<std::int64_t> p_finish_at = std::nullopt) {
|
||||
resume_from = p_resume_from.value_or(0);
|
||||
finish_at = p_finish_at.value_or(-1);
|
||||
}
|
||||
|
||||
std::int64_t resume_from;
|
||||
std::int64_t finish_at;
|
||||
|
||||
const std::string str() const {
|
||||
std::string from_str = (resume_from < 0U) ? "" : std::to_string(resume_from);
|
||||
std::string to_str = (finish_at < 0U) ? "" : std::to_string(finish_at);
|
||||
return from_str + "-" + to_str;
|
||||
}
|
||||
};
|
||||
|
||||
class MultiRange {
|
||||
public:
|
||||
MultiRange(std::initializer_list<Range> rs) : ranges{rs} {}
|
||||
|
||||
const std::string str() const {
|
||||
std::string multi_range_string{};
|
||||
for (Range range : ranges) {
|
||||
multi_range_string += ((multi_range_string.empty()) ? "" : ", ") + range.str();
|
||||
}
|
||||
return multi_range_string;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Range> ranges;
|
||||
}; // namespace cpr
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
17
vendor/CPR/include/cpr/redirect.h
vendored
17
vendor/CPR/include/cpr/redirect.h
vendored
@@ -50,7 +50,7 @@ class Redirect {
|
||||
* Default: 50
|
||||
* https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html
|
||||
**/
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers, google-runtime-int)
|
||||
// NOLINTNEXTLINE (google-runtime-int)
|
||||
long maximum{50L};
|
||||
/**
|
||||
* Follow 3xx redirects.
|
||||
@@ -58,6 +58,12 @@ class Redirect {
|
||||
* https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html
|
||||
**/
|
||||
bool follow{true};
|
||||
/**
|
||||
* Continue to send authentication (user+password) credentials when following locations, even when hostname changed.
|
||||
* Default: false
|
||||
* https://curl.se/libcurl/c/CURLOPT_UNRESTRICTED_AUTH.html
|
||||
**/
|
||||
bool cont_send_cred{false};
|
||||
/**
|
||||
* Flags to control how to act after a redirect for a post request.
|
||||
* Default: POST_ALL
|
||||
@@ -66,11 +72,12 @@ class Redirect {
|
||||
|
||||
Redirect() = default;
|
||||
// NOLINTNEXTLINE (google-runtime-int)
|
||||
Redirect(long p_maximum, bool p_follow, PostRedirectFlags p_post_flags) : maximum(p_maximum), follow(p_follow), post_flags(p_post_flags){};
|
||||
Redirect(long p_maximum, bool p_follow, bool p_cont_send_cred, PostRedirectFlags p_post_flags) : maximum(p_maximum), follow(p_follow), cont_send_cred(p_cont_send_cred), post_flags(p_post_flags){}
|
||||
// NOLINTNEXTLINE (google-runtime-int)
|
||||
explicit Redirect(long p_maximum) : maximum(p_maximum){};
|
||||
explicit Redirect(bool p_follow) : follow(p_follow){};
|
||||
explicit Redirect(PostRedirectFlags p_post_flags) : post_flags(p_post_flags){};
|
||||
explicit Redirect(long p_maximum) : maximum(p_maximum){}
|
||||
explicit Redirect(bool p_follow) : follow(p_follow){}
|
||||
Redirect(bool p_follow, bool p_cont_send_cred) : follow(p_follow), cont_send_cred(p_cont_send_cred){}
|
||||
explicit Redirect(PostRedirectFlags p_post_flags) : post_flags(p_post_flags){}
|
||||
};
|
||||
} // namespace cpr
|
||||
|
||||
|
||||
17
vendor/CPR/include/cpr/reserve_size.h
vendored
Normal file
17
vendor/CPR/include/cpr/reserve_size.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CPR_RESERVE_SIZE_H
|
||||
#define CPR_RESERVE_SIZE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class ReserveSize {
|
||||
public:
|
||||
ReserveSize(const size_t _size) : size(_size) {}
|
||||
|
||||
size_t size = 0;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
23
vendor/CPR/include/cpr/resolve.h
vendored
Normal file
23
vendor/CPR/include/cpr/resolve.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef CPR_RESOLVE_H
|
||||
#define CPR_RESOLVE_H
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace cpr {
|
||||
class Resolve {
|
||||
public:
|
||||
std::string host;
|
||||
std::string addr;
|
||||
std::set<uint16_t> ports;
|
||||
|
||||
Resolve(const std::string& host_param, const std::string& addr_param, const std::set<uint16_t>& ports_param = std::set<uint16_t>{80U, 443U}): host(host_param), addr(addr_param), ports(ports_param) {
|
||||
if (this->ports.empty()) {
|
||||
this->ports.insert(80U);
|
||||
this->ports.insert(443U);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
10
vendor/CPR/include/cpr/response.h
vendored
10
vendor/CPR/include/cpr/response.h
vendored
@@ -3,12 +3,12 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <curl/curl.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "cpr/cert_info.h"
|
||||
#include "cpr/cookies.h"
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/error.h"
|
||||
@@ -17,8 +17,11 @@
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class MultiPerform;
|
||||
|
||||
class Response {
|
||||
protected:
|
||||
friend MultiPerform;
|
||||
std::shared_ptr<CurlHolder> curl_{nullptr};
|
||||
|
||||
public:
|
||||
@@ -41,9 +44,8 @@ class Response {
|
||||
long redirect_count{};
|
||||
|
||||
Response() = default;
|
||||
Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string,
|
||||
Cookies&& p_cookies, Error&& p_error);
|
||||
std::vector<std::string> GetCertInfo();
|
||||
Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string, Cookies&& p_cookies, Error&& p_error);
|
||||
std::vector<CertInfo> GetCertInfos();
|
||||
Response(const Response& other) = default;
|
||||
Response(Response&& old) noexcept = default;
|
||||
~Response() noexcept = default;
|
||||
|
||||
182
vendor/CPR/include/cpr/session.h
vendored
182
vendor/CPR/include/cpr/session.h
vendored
@@ -3,8 +3,13 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include "cpr/accept_encoding.h"
|
||||
#include "cpr/async_wrapper.h"
|
||||
#include "cpr/auth.h"
|
||||
#include "cpr/bearer.h"
|
||||
#include "cpr/body.h"
|
||||
@@ -13,35 +18,45 @@
|
||||
#include "cpr/cookies.h"
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/curlholder.h"
|
||||
#include "cpr/digest.h"
|
||||
#include "cpr/http_version.h"
|
||||
#include "cpr/interface.h"
|
||||
#include "cpr/limit_rate.h"
|
||||
#include "cpr/local_port.h"
|
||||
#include "cpr/local_port_range.h"
|
||||
#include "cpr/low_speed.h"
|
||||
#include "cpr/multipart.h"
|
||||
#include "cpr/ntlm.h"
|
||||
#include "cpr/parameters.h"
|
||||
#include "cpr/payload.h"
|
||||
#include "cpr/proxies.h"
|
||||
#include "cpr/proxyauth.h"
|
||||
#include "cpr/range.h"
|
||||
#include "cpr/redirect.h"
|
||||
#include "cpr/reserve_size.h"
|
||||
#include "cpr/resolve.h"
|
||||
#include "cpr/response.h"
|
||||
#include "cpr/ssl_options.h"
|
||||
#include "cpr/timeout.h"
|
||||
#include "cpr/unix_socket.h"
|
||||
#include "cpr/user_agent.h"
|
||||
#include "cpr/util.h"
|
||||
#include "cpr/verbose.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class Session {
|
||||
using AsyncResponse = AsyncWrapper<Response>;
|
||||
|
||||
class Interceptor;
|
||||
class MultiPerform;
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
Session();
|
||||
Session(Session&& old) noexcept;
|
||||
Session(const Session& other) = delete;
|
||||
Session(Session&& old) = default;
|
||||
|
||||
~Session();
|
||||
~Session() = default;
|
||||
|
||||
Session& operator=(Session&& old) noexcept;
|
||||
Session& operator=(Session&& old) noexcept = default;
|
||||
Session& operator=(const Session& other) = delete;
|
||||
|
||||
void SetUrl(const Url& url);
|
||||
@@ -52,7 +67,11 @@ class Session {
|
||||
void SetTimeout(const Timeout& timeout);
|
||||
void SetConnectTimeout(const ConnectTimeout& timeout);
|
||||
void SetAuth(const Authentication& auth);
|
||||
void SetDigest(const Digest& auth);
|
||||
// Only supported with libcurl >= 7.61.0.
|
||||
// As an alternative use SetHeader and add the token manually.
|
||||
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||||
void SetBearer(const Bearer& token);
|
||||
#endif
|
||||
void SetUserAgent(const UserAgent& ua);
|
||||
void SetPayload(Payload&& payload);
|
||||
void SetPayload(const Payload& payload);
|
||||
@@ -62,7 +81,6 @@ class Session {
|
||||
void SetProxyAuth(const ProxyAuthentication& proxy_auth);
|
||||
void SetMultipart(Multipart&& multipart);
|
||||
void SetMultipart(const Multipart& multipart);
|
||||
void SetNTLM(const NTLM& auth);
|
||||
void SetRedirect(const Redirect& redirect);
|
||||
void SetCookies(const Cookies& cookies);
|
||||
void SetBody(Body&& body);
|
||||
@@ -78,6 +96,20 @@ class Session {
|
||||
void SetDebugCallback(const DebugCallback& debug);
|
||||
void SetVerbose(const Verbose& verbose);
|
||||
void SetInterface(const Interface& iface);
|
||||
void SetLocalPort(const LocalPort& local_port);
|
||||
void SetLocalPortRange(const LocalPortRange& local_port_range);
|
||||
void SetHttpVersion(const HttpVersion& version);
|
||||
void SetRange(const Range& range);
|
||||
void SetResolve(const Resolve& resolve);
|
||||
void SetResolves(const std::vector<Resolve>& resolves);
|
||||
void SetMultiRange(const MultiRange& multi_range);
|
||||
void SetReserveSize(const ReserveSize& reserve_size);
|
||||
void SetAcceptEncoding(const AcceptEncoding& accept_encoding);
|
||||
void SetAcceptEncoding(AcceptEncoding&& accept_encoding);
|
||||
void SetLimitRate(const LimitRate& limit_rate);
|
||||
|
||||
// For cancellable requests
|
||||
void SetCancellationParam(std::shared_ptr<std::atomic_bool> param);
|
||||
|
||||
// Used in templated functions
|
||||
void SetOption(const Url& url);
|
||||
@@ -92,7 +124,6 @@ class Session {
|
||||
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||||
void SetOption(const Bearer& auth);
|
||||
#endif
|
||||
void SetOption(const Digest& auth);
|
||||
void SetOption(const UserAgent& ua);
|
||||
void SetOption(Payload&& payload);
|
||||
void SetOption(const Payload& payload);
|
||||
@@ -103,7 +134,6 @@ class Session {
|
||||
void SetOption(const ProxyAuthentication& proxy_auth);
|
||||
void SetOption(Multipart&& multipart);
|
||||
void SetOption(const Multipart& multipart);
|
||||
void SetOption(const NTLM& auth);
|
||||
void SetOption(const Redirect& redirect);
|
||||
void SetOption(const Cookies& cookies);
|
||||
void SetOption(Body&& body);
|
||||
@@ -119,8 +149,29 @@ class Session {
|
||||
void SetOption(const UnixSocket& unix_socket);
|
||||
void SetOption(const SslOptions& options);
|
||||
void SetOption(const Interface& iface);
|
||||
void SetOption(const LocalPort& local_port);
|
||||
void SetOption(const LocalPortRange& local_port_range);
|
||||
void SetOption(const HttpVersion& version);
|
||||
void SetOption(const Range& range);
|
||||
void SetOption(const MultiRange& multi_range);
|
||||
void SetOption(const ReserveSize& reserve_size);
|
||||
void SetOption(const AcceptEncoding& accept_encoding);
|
||||
void SetOption(AcceptEncoding&& accept_encoding);
|
||||
void SetOption(const Resolve& resolve);
|
||||
void SetOption(const std::vector<Resolve>& resolves);
|
||||
|
||||
cpr_off_t GetDownloadFileLength();
|
||||
/**
|
||||
* Attempt to preallocate enough memory for specified number of characters in the response string.
|
||||
* Pass 0 to disable this behavior and let the response string be allocated dynamically on demand.
|
||||
*
|
||||
* Example:
|
||||
* cpr::Session session;
|
||||
* session.SetUrl(cpr::Url{"http://xxx/file"});
|
||||
* session.ResponseStringReserve(1024 * 512); // Reserve space for at least 1024 * 512 characters
|
||||
* cpr::Response r = session.Get();
|
||||
**/
|
||||
void ResponseStringReserve(size_t size);
|
||||
Response Delete();
|
||||
Response Download(const WriteCallback& write);
|
||||
Response Download(std::ofstream& file);
|
||||
@@ -131,7 +182,33 @@ class Session {
|
||||
Response Post();
|
||||
Response Put();
|
||||
|
||||
AsyncResponse GetAsync();
|
||||
AsyncResponse DeleteAsync();
|
||||
AsyncResponse DownloadAsync(const WriteCallback& write);
|
||||
AsyncResponse DownloadAsync(std::ofstream& file);
|
||||
AsyncResponse HeadAsync();
|
||||
AsyncResponse OptionsAsync();
|
||||
AsyncResponse PatchAsync();
|
||||
AsyncResponse PostAsync();
|
||||
AsyncResponse PutAsync();
|
||||
|
||||
template <typename Then>
|
||||
auto GetCallback(Then then);
|
||||
template <typename Then>
|
||||
auto PostCallback(Then then);
|
||||
template <typename Then>
|
||||
auto PutCallback(Then then);
|
||||
template <typename Then>
|
||||
auto HeadCallback(Then then);
|
||||
template <typename Then>
|
||||
auto DeleteCallback(Then then);
|
||||
template <typename Then>
|
||||
auto OptionsCallback(Then then);
|
||||
template <typename Then>
|
||||
auto PatchCallback(Then then);
|
||||
|
||||
std::shared_ptr<CurlHolder> GetCurlHolder();
|
||||
std::string GetFullRequestUrl();
|
||||
|
||||
void PrepareDelete();
|
||||
void PrepareGet();
|
||||
@@ -140,13 +217,92 @@ class Session {
|
||||
void PreparePatch();
|
||||
void PreparePost();
|
||||
void PreparePut();
|
||||
void PrepareDownload(const WriteCallback& write);
|
||||
void PrepareDownload(std::ofstream& file);
|
||||
Response Complete(CURLcode curl_error);
|
||||
Response CompleteDownload(CURLcode curl_error);
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl_;
|
||||
void AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor);
|
||||
|
||||
private:
|
||||
// Interceptors should be able to call the private proceed() function
|
||||
friend Interceptor;
|
||||
friend MultiPerform;
|
||||
|
||||
|
||||
bool hasBodyOrPayload_{false};
|
||||
bool chunkedTransferEncoding_{false};
|
||||
std::shared_ptr<CurlHolder> curl_;
|
||||
Url url_;
|
||||
Parameters parameters_;
|
||||
Proxies proxies_;
|
||||
ProxyAuthentication proxyAuth_;
|
||||
Header header_;
|
||||
AcceptEncoding acceptEncoding_;
|
||||
/**
|
||||
* Will be set by the read callback.
|
||||
* Ensures that the "Transfer-Encoding" is set to "chunked", if not overriden in header_.
|
||||
**/
|
||||
ReadCallback readcb_;
|
||||
HeaderCallback headercb_;
|
||||
WriteCallback writecb_;
|
||||
ProgressCallback progresscb_;
|
||||
DebugCallback debugcb_;
|
||||
CancellationCallback cancellationcb_;
|
||||
|
||||
size_t response_string_reserve_size_{0};
|
||||
std::string response_string_;
|
||||
std::string header_string_;
|
||||
std::queue<std::shared_ptr<Interceptor>> interceptors_;
|
||||
bool isUsedInMultiPerform{false};
|
||||
bool isCancellable{false};
|
||||
|
||||
Response makeDownloadRequest();
|
||||
Response makeRequest();
|
||||
Response proceed();
|
||||
Response intercept();
|
||||
void prepareCommon();
|
||||
void prepareCommonDownload();
|
||||
void SetHeaderInternal();
|
||||
std::shared_ptr<Session> GetSharedPtrFromThis();
|
||||
CURLcode DoEasyPerform();
|
||||
};
|
||||
|
||||
template <typename Then>
|
||||
auto Session::GetCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Get()); }, std::move(then));
|
||||
}
|
||||
|
||||
template <typename Then>
|
||||
auto Session::PostCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Post()); }, std::move(then));
|
||||
}
|
||||
|
||||
template <typename Then>
|
||||
auto Session::PutCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Put()); }, std::move(then));
|
||||
}
|
||||
|
||||
template <typename Then>
|
||||
auto Session::HeadCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Head()); }, std::move(then));
|
||||
}
|
||||
|
||||
template <typename Then>
|
||||
auto Session::DeleteCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Delete()); }, std::move(then));
|
||||
}
|
||||
|
||||
template <typename Then>
|
||||
auto Session::OptionsCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Options()); }, std::move(then));
|
||||
}
|
||||
|
||||
template <typename Then>
|
||||
auto Session::PatchCallback(Then then) {
|
||||
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Patch()); }, std::move(then));
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
|
||||
47
vendor/CPR/include/cpr/singleton.h
vendored
Normal file
47
vendor/CPR/include/cpr/singleton.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef CPR_SINGLETON_H
|
||||
#define CPR_SINGLETON_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifndef CPR_DISABLE_COPY
|
||||
#define CPR_DISABLE_COPY(Class) \
|
||||
Class(const Class&) = delete; \
|
||||
Class& operator=(const Class&) = delete;
|
||||
#endif
|
||||
|
||||
#ifndef CPR_SINGLETON_DECL
|
||||
#define CPR_SINGLETON_DECL(Class) \
|
||||
public: \
|
||||
static Class* GetInstance(); \
|
||||
static void ExitInstance(); \
|
||||
private: \
|
||||
CPR_DISABLE_COPY(Class) \
|
||||
static Class* s_pInstance; \
|
||||
static std::mutex s_mutex;
|
||||
#endif
|
||||
|
||||
#ifndef CPR_SINGLETON_IMPL
|
||||
#define CPR_SINGLETON_IMPL(Class) \
|
||||
Class* Class::s_pInstance = nullptr; \
|
||||
std::mutex Class::s_mutex; \
|
||||
Class* Class::GetInstance() { \
|
||||
if (s_pInstance == nullptr) { \
|
||||
s_mutex.lock(); \
|
||||
if (s_pInstance == nullptr) { \
|
||||
s_pInstance = new Class; \
|
||||
} \
|
||||
s_mutex.unlock(); \
|
||||
} \
|
||||
return s_pInstance; \
|
||||
} \
|
||||
void Class::ExitInstance() { \
|
||||
s_mutex.lock(); \
|
||||
if (s_pInstance) { \
|
||||
delete s_pInstance; \
|
||||
s_pInstance = nullptr; \
|
||||
} \
|
||||
s_mutex.unlock(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
26
vendor/CPR/include/cpr/ssl_ctx.h
vendored
Normal file
26
vendor/CPR/include/cpr/ssl_ctx.h
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef CPR_SSL_CTX_H
|
||||
#define CPR_SSL_CTX_H
|
||||
|
||||
#include "cpr/ssl_options.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
|
||||
namespace cpr {
|
||||
|
||||
/**
|
||||
* This callback function loads a CA certificate from raw_cert_buf and gets called by libcurl
|
||||
* just before the initialization of an SSL connection.
|
||||
* The raw_cert_buf argument is set with the CURLOPT_SSL_CTX_DATA option and has to be a nul
|
||||
* terminated buffer.
|
||||
*
|
||||
* Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html
|
||||
* https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html
|
||||
*/
|
||||
CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* curl, void* sslctx, void* raw_cert_buf);
|
||||
|
||||
} // Namespace cpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
163
vendor/CPR/include/cpr/ssl_options.h
vendored
163
vendor/CPR/include/cpr/ssl_options.h
vendored
@@ -1,67 +1,70 @@
|
||||
#ifndef CPR_SSLOPTIONS_H
|
||||
#define CPR_SSLOPTIONS_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cpr/filesystem.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "cpr/util.h"
|
||||
#include <utility>
|
||||
|
||||
#define __LIBCURL_VERSION_GTE(major, minor) \
|
||||
((LIBCURL_VERSION_MAJOR > (major)) || \
|
||||
((LIBCURL_VERSION_MAJOR == (major)) && (LIBCURL_VERSION_MINOR >= (minor))))
|
||||
#define __LIBCURL_VERSION_LT(major, minor) \
|
||||
((LIBCURL_VERSION_MAJOR < (major)) || \
|
||||
((LIBCURL_VERSION_MAJOR == (major)) && (LIBCURL_VERSION_MINOR < (minor))))
|
||||
|
||||
#ifndef SUPPORT_ALPN
|
||||
#define SUPPORT_ALPN __LIBCURL_VERSION_GTE(7, 36)
|
||||
#define SUPPORT_ALPN LIBCURL_VERSION_NUM >= 0x072400 // 7.36.0
|
||||
#endif
|
||||
#ifndef SUPPORT_NPN
|
||||
#define SUPPORT_NPN __LIBCURL_VERSION_GTE(7, 36)
|
||||
#define SUPPORT_NPN LIBCURL_VERSION_NUM >= 0x072400 && LIBCURL_VERSION_NUM <= 0x078600 // 7.36.0 - 7.86.0
|
||||
#endif
|
||||
|
||||
#ifndef SUPPORT_SSLv2
|
||||
#define SUPPORT_SSLv2 __LIBCURL_VERSION_LT(7, 19)
|
||||
#define SUPPORT_SSLv2 LIBCURL_VERSION_NUM <= 0x071300 // 7.19.0
|
||||
#endif
|
||||
#ifndef SUPPORT_SSLv3
|
||||
#define SUPPORT_SSLv3 __LIBCURL_VERSION_LT(7, 39)
|
||||
#define SUPPORT_SSLv3 LIBCURL_VERSION_NUM <= 0x072700 // 7.39.0
|
||||
#endif
|
||||
#ifndef SUPPORT_TLSv1_0
|
||||
#define SUPPORT_TLSv1_0 __LIBCURL_VERSION_GTE(7, 34)
|
||||
#define SUPPORT_TLSv1_0 LIBCURL_VERSION_NUM >= 0x072200 // 7.34.0
|
||||
#endif
|
||||
#ifndef SUPPORT_TLSv1_1
|
||||
#define SUPPORT_TLSv1_1 __LIBCURL_VERSION_GTE(7, 34)
|
||||
#define SUPPORT_TLSv1_1 LIBCURL_VERSION_NUM >= 0x072200 // 7.34.0
|
||||
#endif
|
||||
#ifndef SUPPORT_TLSv1_2
|
||||
#define SUPPORT_TLSv1_2 __LIBCURL_VERSION_GTE(7, 34)
|
||||
#define SUPPORT_TLSv1_2 LIBCURL_VERSION_NUM >= 0x072200 // 7.34.0
|
||||
#endif
|
||||
#ifndef SUPPORT_TLSv1_3
|
||||
#define SUPPORT_TLSv1_3 __LIBCURL_VERSION_GTE(7, 52)
|
||||
#define SUPPORT_TLSv1_3 LIBCURL_VERSION_NUM >= 0x073400 // 7.52.0
|
||||
#endif
|
||||
#ifndef SUPPORT_MAX_TLS_VERSION
|
||||
#define SUPPORT_MAX_TLS_VERSION __LIBCURL_VERSION_GTE(7, 54)
|
||||
#define SUPPORT_MAX_TLS_VERSION LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0
|
||||
#endif
|
||||
#ifndef SUPPORT_MAX_TLSv1_1
|
||||
#define SUPPORT_MAX_TLSv1_1 __LIBCURL_VERSION_GTE(7, 54)
|
||||
#define SUPPORT_MAX_TLSv1_1 LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0
|
||||
#endif
|
||||
#ifndef SUPPORT_MAX_TLSv1_2
|
||||
#define SUPPORT_MAX_TLSv1_2 __LIBCURL_VERSION_GTE(7, 54)
|
||||
#define SUPPORT_MAX_TLSv1_2 LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0
|
||||
#endif
|
||||
#ifndef SUPPORT_MAX_TLSv1_3
|
||||
#define SUPPORT_MAX_TLSv1_3 __LIBCURL_VERSION_GTE(7, 54)
|
||||
#define SUPPORT_MAX_TLSv1_3 LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0
|
||||
#endif
|
||||
#ifndef SUPPORT_TLSv13_CIPHERS
|
||||
#define SUPPORT_TLSv13_CIPHERS __LIBCURL_VERSION_GTE(7, 61)
|
||||
#define SUPPORT_TLSv13_CIPHERS LIBCURL_VERSION_NUM >= 0x073D00 // 7.61.0
|
||||
#endif
|
||||
#ifndef SUPPORT_SESSIONID_CACHE
|
||||
#define SUPPORT_SESSIONID_CACHE __LIBCURL_VERSION_GTE(7, 16)
|
||||
#define SUPPORT_SESSIONID_CACHE LIBCURL_VERSION_NUM >= 0x071000 // 7.16.0
|
||||
#endif
|
||||
#ifndef SUPPORT_SSL_FALSESTART
|
||||
#define SUPPORT_SSL_FALSESTART __LIBCURL_VERSION_GTE(7, 42)
|
||||
#define SUPPORT_SSL_FALSESTART LIBCURL_VERSION_NUM >= 0x072A00 // 7.42.0
|
||||
#endif
|
||||
#ifndef SUPPORT_SSL_NO_REVOKE
|
||||
#define SUPPORT_SSL_NO_REVOKE __LIBCURL_VERSION_GTE(7, 44)
|
||||
#define SUPPORT_SSL_NO_REVOKE LIBCURL_VERSION_NUM >= 0x072C00 // 7.44.0
|
||||
#endif
|
||||
#ifndef SUPPORT_CURLOPT_SSLKEY_BLOB
|
||||
#define SUPPORT_CURLOPT_SSLKEY_BLOB LIBCURL_VERSION_NUM >= 0x074700 // 7.71.0
|
||||
#endif
|
||||
#ifndef SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
#define SUPPORT_CURLOPT_SSL_CTX_FUNCTION LIBCURL_VERSION_NUM >= 0x070B00 // 7.11.0
|
||||
#endif
|
||||
|
||||
namespace cpr {
|
||||
@@ -85,9 +88,11 @@ namespace ssl {
|
||||
class CertFile {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
CertFile(std::string&& p_filename) : filename(std::move(p_filename)) {}
|
||||
CertFile(fs::path&& p_filename) : filename(std::move(p_filename)) {}
|
||||
|
||||
const std::string filename;
|
||||
virtual ~CertFile() = default;
|
||||
|
||||
const fs::path filename;
|
||||
|
||||
virtual const char* GetCertType() const {
|
||||
return "PEM";
|
||||
@@ -99,7 +104,9 @@ using PemCert = CertFile;
|
||||
class DerCert : public CertFile {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
DerCert(std::string&& p_filename) : CertFile(std::move(p_filename)) {}
|
||||
DerCert(fs::path&& p_filename) : CertFile(std::move(p_filename)) {}
|
||||
|
||||
~DerCert() override = default;
|
||||
|
||||
const char* GetCertType() const override {
|
||||
return "DER";
|
||||
@@ -110,13 +117,16 @@ class DerCert : public CertFile {
|
||||
class KeyFile {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
KeyFile(std::string&& p_filename) : filename(std::move(p_filename)) {}
|
||||
KeyFile(fs::path&& p_filename) : filename(std::move(p_filename)) {}
|
||||
|
||||
template <typename FileType, typename PassType>
|
||||
KeyFile(FileType&& p_filename, PassType p_password)
|
||||
: filename(std::forward<FileType>(p_filename)), password(std::move(p_password)) {}
|
||||
KeyFile(FileType&& p_filename, PassType p_password) : filename(std::forward<FileType>(p_filename)), password(std::move(p_password)) {}
|
||||
|
||||
std::string filename;
|
||||
virtual ~KeyFile() {
|
||||
util::secureStringClear(password);
|
||||
}
|
||||
|
||||
fs::path filename;
|
||||
std::string password;
|
||||
|
||||
virtual const char* GetKeyType() const {
|
||||
@@ -124,16 +134,39 @@ class KeyFile {
|
||||
}
|
||||
};
|
||||
|
||||
#if SUPPORT_CURLOPT_SSLKEY_BLOB
|
||||
class KeyBlob {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
KeyBlob(std::string&& p_blob) : blob(std::move(p_blob)) {}
|
||||
|
||||
template <typename BlobType, typename PassType>
|
||||
KeyBlob(BlobType&& p_blob, PassType p_password) : blob(std::forward<BlobType>(p_blob)), password(std::move(p_password)) {}
|
||||
|
||||
virtual ~KeyBlob() {
|
||||
util::secureStringClear(password);
|
||||
}
|
||||
|
||||
std::string blob;
|
||||
std::string password;
|
||||
|
||||
virtual const char* GetKeyType() const {
|
||||
return "PEM";
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
using PemKey = KeyFile;
|
||||
|
||||
class DerKey : public KeyFile {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
DerKey(std::string&& p_filename) : KeyFile(std::move(p_filename)) {}
|
||||
DerKey(fs::path&& p_filename) : KeyFile(std::move(p_filename)) {}
|
||||
|
||||
template <typename FileType, typename PassType>
|
||||
DerKey(FileType&& p_filename, PassType p_password)
|
||||
: KeyFile(std::forward<FileType>(p_filename), std::move(p_password)) {}
|
||||
DerKey(FileType&& p_filename, PassType p_password) : KeyFile(std::forward<FileType>(p_filename), std::move(p_password)) {}
|
||||
|
||||
~DerKey() override = default;
|
||||
|
||||
const char* GetKeyType() const override {
|
||||
return "DER";
|
||||
@@ -277,27 +310,37 @@ struct MaxTLSv1_3 {};
|
||||
class CaInfo {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
CaInfo(std::string&& p_filename) : filename(std::move(p_filename)) {}
|
||||
CaInfo(fs::path&& p_filename) : filename(std::move(p_filename)) {}
|
||||
|
||||
std::string filename;
|
||||
fs::path filename;
|
||||
};
|
||||
|
||||
// specify directory holding CA certificates
|
||||
class CaPath {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
CaPath(std::string&& p_filename) : filename(std::move(p_filename)) {}
|
||||
CaPath(fs::path&& p_filename) : filename(std::move(p_filename)) {}
|
||||
|
||||
std::string filename;
|
||||
fs::path filename;
|
||||
};
|
||||
|
||||
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
class CaBuffer {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
CaBuffer(std::string&& p_buffer) : buffer(std::move(p_buffer)) {}
|
||||
|
||||
const std::string buffer;
|
||||
};
|
||||
#endif
|
||||
|
||||
// specify a Certificate Revocation List file
|
||||
class Crl {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Crl(std::string&& p_filename) : filename(std::move(p_filename)) {}
|
||||
Crl(fs::path&& p_filename) : filename(std::move(p_filename)) {}
|
||||
|
||||
std::string filename;
|
||||
fs::path filename;
|
||||
};
|
||||
|
||||
// specify ciphers to use for TLS
|
||||
@@ -352,7 +395,7 @@ class SslFastStart {
|
||||
#endif
|
||||
|
||||
class NoRevoke {
|
||||
public:
|
||||
public:
|
||||
NoRevoke() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
NoRevoke(bool p_enabled) : enabled(p_enabled) {}
|
||||
@@ -367,9 +410,14 @@ public:
|
||||
} // namespace ssl
|
||||
|
||||
struct SslOptions {
|
||||
// We don't use fs::path here, as this leads to problems using windows
|
||||
std::string cert_file;
|
||||
std::string cert_type;
|
||||
// We don't use fs::path here, as this leads to problems using windows
|
||||
std::string key_file;
|
||||
#if SUPPORT_CURLOPT_SSLKEY_BLOB
|
||||
std::string key_blob;
|
||||
#endif
|
||||
std::string key_type;
|
||||
std::string key_pass;
|
||||
std::string pinned_public_key;
|
||||
@@ -389,8 +437,14 @@ struct SslOptions {
|
||||
#if SUPPORT_MAX_TLS_VERSION
|
||||
int max_version = CURL_SSLVERSION_MAX_DEFAULT;
|
||||
#endif
|
||||
// We don't use fs::path here, as this leads to problems using windows
|
||||
std::string ca_info;
|
||||
// We don't use fs::path here, as this leads to problems using windows
|
||||
std::string ca_path;
|
||||
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
std::string ca_buffer;
|
||||
#endif
|
||||
// We don't use fs::path here, as this leads to problems using windows
|
||||
std::string crl_file;
|
||||
std::string ciphers;
|
||||
#if SUPPORT_TLSv13_CIPHERS
|
||||
@@ -400,15 +454,29 @@ struct SslOptions {
|
||||
bool session_id_cache = true;
|
||||
#endif
|
||||
|
||||
~SslOptions() noexcept {
|
||||
#if SUPPORT_CURLOPT_SSLKEY_BLOB
|
||||
util::secureStringClear(key_blob);
|
||||
#endif
|
||||
util::secureStringClear(key_pass);
|
||||
}
|
||||
|
||||
void SetOption(const ssl::CertFile& opt) {
|
||||
cert_file = opt.filename;
|
||||
cert_file = opt.filename.string();
|
||||
cert_type = opt.GetCertType();
|
||||
}
|
||||
void SetOption(const ssl::KeyFile& opt) {
|
||||
key_file = opt.filename;
|
||||
key_file = opt.filename.string();
|
||||
key_type = opt.GetKeyType();
|
||||
key_pass = opt.password;
|
||||
}
|
||||
#if SUPPORT_CURLOPT_SSLKEY_BLOB
|
||||
void SetOption(const ssl::KeyBlob& opt) {
|
||||
key_blob = opt.blob;
|
||||
key_type = opt.GetKeyType();
|
||||
key_pass = opt.password;
|
||||
}
|
||||
#endif
|
||||
void SetOption(const ssl::PinnedPublicKey& opt) {
|
||||
pinned_public_key = opt.pinned_public_key;
|
||||
}
|
||||
@@ -496,13 +564,18 @@ struct SslOptions {
|
||||
}
|
||||
#endif
|
||||
void SetOption(const ssl::CaInfo& opt) {
|
||||
ca_info = opt.filename;
|
||||
ca_info = opt.filename.string();
|
||||
}
|
||||
void SetOption(const ssl::CaPath& opt) {
|
||||
ca_path = opt.filename;
|
||||
ca_path = opt.filename.string();
|
||||
}
|
||||
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
void SetOption(const ssl::CaBuffer& opt) {
|
||||
ca_buffer = opt.buffer;
|
||||
}
|
||||
#endif
|
||||
void SetOption(const ssl::Crl& opt) {
|
||||
crl_file = opt.filename;
|
||||
crl_file = opt.filename.string();
|
||||
}
|
||||
void SetOption(const ssl::Ciphers& opt) {
|
||||
ciphers = opt.ciphers;
|
||||
|
||||
4
vendor/CPR/include/cpr/status_codes.h
vendored
4
vendor/CPR/include/cpr/status_codes.h
vendored
@@ -1,5 +1,5 @@
|
||||
#ifndef _CPR_STATUS_CODES
|
||||
#define _CPR_STATUS_CODES
|
||||
#ifndef CPR_STATUS_CODES
|
||||
#define CPR_STATUS_CODES
|
||||
#include <cstdint>
|
||||
namespace cpr {
|
||||
namespace status {
|
||||
|
||||
122
vendor/CPR/include/cpr/threadpool.h
vendored
Normal file
122
vendor/CPR/include/cpr/threadpool.h
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifndef CPR_THREAD_POOL_H
|
||||
#define CPR_THREAD_POOL_H
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#define CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency()
|
||||
|
||||
constexpr size_t CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM = 1;
|
||||
constexpr std::chrono::milliseconds CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME{60000};
|
||||
|
||||
namespace cpr {
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
using Task = std::function<void()>;
|
||||
|
||||
explicit ThreadPool(size_t min_threads = CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM, size_t max_threads = CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM, std::chrono::milliseconds max_idle_ms = CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME);
|
||||
|
||||
virtual ~ThreadPool();
|
||||
|
||||
void SetMinThreadNum(size_t min_threads) {
|
||||
min_thread_num = min_threads;
|
||||
}
|
||||
void SetMaxThreadNum(size_t max_threads) {
|
||||
max_thread_num = max_threads;
|
||||
}
|
||||
void SetMaxIdleTime(std::chrono::milliseconds ms) {
|
||||
max_idle_time = ms;
|
||||
}
|
||||
size_t GetCurrentThreadNum() {
|
||||
return cur_thread_num;
|
||||
}
|
||||
size_t GetIdleThreadNum() {
|
||||
return idle_thread_num;
|
||||
}
|
||||
bool IsStarted() {
|
||||
return status != STOP;
|
||||
}
|
||||
bool IsStopped() {
|
||||
return status == STOP;
|
||||
}
|
||||
|
||||
int Start(size_t start_threads = 0);
|
||||
int Stop();
|
||||
int Pause();
|
||||
int Resume();
|
||||
int Wait();
|
||||
|
||||
/**
|
||||
* Return a future, calling future.get() will wait task done and return RetType.
|
||||
* Submit(fn, args...)
|
||||
* Submit(std::bind(&Class::mem_fn, &obj))
|
||||
* Submit(std::mem_fn(&Class::mem_fn, &obj))
|
||||
**/
|
||||
template <class Fn, class... Args>
|
||||
auto Submit(Fn&& fn, Args&&... args) {
|
||||
if (status == STOP) {
|
||||
Start();
|
||||
}
|
||||
if (idle_thread_num <= 0 && cur_thread_num < max_thread_num) {
|
||||
CreateThread();
|
||||
}
|
||||
using RetType = decltype(fn(args...));
|
||||
auto task = std::make_shared<std::packaged_task<RetType()> >(std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...));
|
||||
std::future<RetType> future = task->get_future();
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(task_mutex);
|
||||
tasks.emplace([task] { (*task)(); });
|
||||
}
|
||||
|
||||
task_cond.notify_one();
|
||||
return future;
|
||||
}
|
||||
|
||||
private:
|
||||
bool CreateThread();
|
||||
void AddThread(std::thread* thread);
|
||||
void DelThread(std::thread::id id);
|
||||
|
||||
public:
|
||||
size_t min_thread_num;
|
||||
size_t max_thread_num;
|
||||
std::chrono::milliseconds max_idle_time;
|
||||
|
||||
private:
|
||||
enum Status {
|
||||
STOP,
|
||||
RUNNING,
|
||||
PAUSE,
|
||||
};
|
||||
|
||||
struct ThreadData {
|
||||
std::shared_ptr<std::thread> thread;
|
||||
std::thread::id id;
|
||||
Status status;
|
||||
time_t start_time;
|
||||
time_t stop_time;
|
||||
};
|
||||
|
||||
std::atomic<Status> status;
|
||||
std::atomic<size_t> cur_thread_num;
|
||||
std::atomic<size_t> idle_thread_num;
|
||||
std::list<ThreadData> threads;
|
||||
std::mutex thread_mutex;
|
||||
std::queue<Task> tasks;
|
||||
std::mutex task_mutex;
|
||||
std::condition_variable task_cond;
|
||||
};
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif
|
||||
2
vendor/CPR/include/cpr/timeout.h
vendored
2
vendor/CPR/include/cpr/timeout.h
vendored
@@ -12,6 +12,8 @@ class Timeout {
|
||||
Timeout(const std::chrono::milliseconds& duration) : ms{duration} {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Timeout(const std::int32_t& milliseconds) : Timeout{std::chrono::milliseconds(milliseconds)} {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
Timeout(const std::chrono::seconds& duration) : ms{std::chrono::milliseconds(duration).count()} {}
|
||||
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
|
||||
2
vendor/CPR/include/cpr/unix_socket.h
vendored
2
vendor/CPR/include/cpr/unix_socket.h
vendored
@@ -8,7 +8,7 @@ namespace cpr {
|
||||
class UnixSocket {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
UnixSocket(std::string&& unix_socket) : unix_socket_(std::move(unix_socket)) {}
|
||||
UnixSocket(std::string unix_socket) : unix_socket_(std::move(unix_socket)) {}
|
||||
|
||||
const char* GetUnixSocketString() const noexcept;
|
||||
|
||||
|
||||
6
vendor/CPR/include/cpr/user_agent.h
vendored
6
vendor/CPR/include/cpr/user_agent.h
vendored
@@ -9,11 +9,11 @@
|
||||
namespace cpr {
|
||||
class UserAgent : public StringHolder<UserAgent> {
|
||||
public:
|
||||
UserAgent() : StringHolder<UserAgent>() {}
|
||||
UserAgent() = default;
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
UserAgent(const std::string& useragent) : StringHolder<UserAgent>(useragent) {}
|
||||
UserAgent(std::string useragent) : StringHolder<UserAgent>(std::move(useragent)) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
UserAgent(std::string&& useragent) : StringHolder<UserAgent>(std::move(useragent)) {}
|
||||
UserAgent(std::string_view useragent) : StringHolder<UserAgent>(useragent) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
UserAgent(const char* useragent) : StringHolder<UserAgent>(useragent) {}
|
||||
UserAgent(const char* str, size_t len) : StringHolder<UserAgent>(str, len) {}
|
||||
|
||||
35
vendor/CPR/include/cpr/util.h
vendored
35
vendor/CPR/include/cpr/util.h
vendored
@@ -10,31 +10,36 @@
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/curlholder.h"
|
||||
|
||||
namespace cpr {
|
||||
namespace util {
|
||||
namespace cpr::util {
|
||||
|
||||
Header parseHeader(const std::string& headers, std::string* status_line = nullptr,
|
||||
std::string* reason = nullptr);
|
||||
Header parseHeader(const std::string& headers, std::string* status_line = nullptr, std::string* reason = nullptr);
|
||||
Cookies parseCookies(curl_slist* raw_cookies);
|
||||
size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read);
|
||||
size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header);
|
||||
size_t writeFunction(char* ptr, size_t size, size_t nmemb, std::string* data);
|
||||
size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file);
|
||||
size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write);
|
||||
#if LIBCURL_VERSION_NUM < 0x072000
|
||||
int progressUserFunction(const ProgressCallback* progress, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow);
|
||||
#else
|
||||
int progressUserFunction(const ProgressCallback* progress, curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow);
|
||||
#endif
|
||||
int debugUserFunction(CURL* handle, curl_infotype type, char* data, size_t size,
|
||||
const DebugCallback* debug);
|
||||
|
||||
template <typename T = ProgressCallback>
|
||||
int progressUserFunction(const T* progress, cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) {
|
||||
const int cancel_retval{1};
|
||||
static_assert(cancel_retval != CURL_PROGRESSFUNC_CONTINUE);
|
||||
return (*progress)(dltotal, dlnow, ultotal, ulnow) ? 0 : cancel_retval;
|
||||
}
|
||||
int debugUserFunction(CURL* handle, curl_infotype type, char* data, size_t size, const DebugCallback* debug);
|
||||
std::vector<std::string> split(const std::string& to_split, char delimiter);
|
||||
std::string urlEncode(const std::string& s);
|
||||
std::string urlDecode(const std::string& s);
|
||||
|
||||
} // namespace util
|
||||
} // namespace cpr
|
||||
/**
|
||||
* Override the content of the provided string to hide sensitive data. The
|
||||
* string content after invocation is undefined. The string size is reset to zero.
|
||||
* impl. based on:
|
||||
* https://github.com/ojeda/secure_clear/blob/master/example-implementation/secure_clear.h
|
||||
**/
|
||||
void secureStringClear(std::string& s);
|
||||
bool isTrue(const std::string& s);
|
||||
|
||||
} // namespace cpr::util
|
||||
|
||||
#endif
|
||||
|
||||
10
vendor/DPP/CMakeLists.txt
vendored
10
vendor/DPP/CMakeLists.txt
vendored
@@ -31,7 +31,9 @@ include(CheckCXXSymbolExists)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
add_compile_definitions(DPP_BUILD)
|
||||
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/include/dpp/version.h" version_h)
|
||||
set(DPP_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
file(READ "${DPP_ROOT_PATH}/include/dpp/version.h" version_h)
|
||||
|
||||
if(NOT version_h MATCHES "DPP_VERSION_SHORT ([0-9][0-9])([0-9][0-9])([0-9][0-9])")
|
||||
message(FATAL_ERROR "Cannot get DPP_VERSION_SHORT from version.h")
|
||||
@@ -43,7 +45,7 @@ math(EXPR DPP_VERSION_PATCH "${CMAKE_MATCH_3}")
|
||||
|
||||
string(CONCAT DPP_VERSION "${DPP_VERSION_MAJOR}.${DPP_VERSION_MINOR}.${DPP_VERSION_PATCH}")
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_SOURCE_DIR}/cmake/")
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${DPP_ROOT_PATH}/cmake/")
|
||||
|
||||
if (DPP_NO_VCPKG)
|
||||
message("-- INFO: Explicitly disabling VCPKG as running inside the CI action.")
|
||||
@@ -53,7 +55,7 @@ endif()
|
||||
|
||||
if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS)
|
||||
message("-- INFO: Configuring .rc resource script")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/dpp/dpp.rc.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/dpp/dpp.rc" NEWLINE_STYLE WIN32)
|
||||
configure_file("${DPP_ROOT_PATH}/src/dpp/dpp.rc.in" "${DPP_ROOT_PATH}/src/dpp/dpp.rc" NEWLINE_STYLE WIN32)
|
||||
endif()
|
||||
|
||||
if (NOT DPP_NO_VCPKG AND EXISTS "${_VCPKG_ROOT_DIR}")
|
||||
@@ -65,7 +67,7 @@ if (NOT DPP_NO_VCPKG AND EXISTS "${_VCPKG_ROOT_DIR}")
|
||||
HOMEPAGE_URL "https://dpp.dev/"
|
||||
DESCRIPTION "An incredibly lightweight C++ Discord library."
|
||||
)
|
||||
add_subdirectory(library-vcpkg)
|
||||
add_subdirectory(library-vcpkg)
|
||||
else()
|
||||
set(PROJECT_NAME "libdpp")
|
||||
project(
|
||||
|
||||
1
vendor/DPP/buildtools/changelog.php
vendored
1
vendor/DPP/buildtools/changelog.php
vendored
@@ -22,6 +22,7 @@ $categories = [
|
||||
'improvement' => '♻️ Refactoring',
|
||||
'refactor' => '♻️ Refactoring',
|
||||
'refactored' => '♻️ Refactoring',
|
||||
'refactoring' => '♻️ Refactoring',
|
||||
'deprecated' => '♻️ Refactoring',
|
||||
'deprecate' => '♻️ Refactoring',
|
||||
'remove' => '♻️ Refactoring',
|
||||
|
||||
287
vendor/DPP/buildtools/classes/Packager/Vcpkg.php
vendored
Normal file
287
vendor/DPP/buildtools/classes/Packager/Vcpkg.php
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
namespace Dpp\Packager;
|
||||
|
||||
use \RuntimeException;
|
||||
|
||||
const GREEN = "\033[32m";
|
||||
const RED = "\033[31m";
|
||||
const WHITE = "\033[0m";
|
||||
|
||||
class Vcpkg
|
||||
{
|
||||
/**
|
||||
* @var string Git Tag
|
||||
*/
|
||||
private string $latestTag;
|
||||
|
||||
/**
|
||||
* @var string Semver version
|
||||
*/
|
||||
private string $version;
|
||||
|
||||
/**
|
||||
* @var string Path to GIT
|
||||
*/
|
||||
private string $git;
|
||||
|
||||
/**
|
||||
* @var string Path to SUDO
|
||||
*/
|
||||
private string $sudo;
|
||||
|
||||
/**
|
||||
* @var bool True when we have done the first build to get the SHA512 sum
|
||||
*/
|
||||
private bool $firstBuildComplete = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Examines current diretory's git repository to get latest tag and version.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
global $argv;
|
||||
if (count($argv) < 2) {
|
||||
throw new RuntimeException(RED . "Missing github repository owner and access token\n" . WHITE);
|
||||
}
|
||||
echo GREEN . "Starting vcpkg updater...\n" . WHITE;
|
||||
|
||||
/* Get the latest tag from the version of the repository checked out by default into the action */
|
||||
$this->latestTag = preg_replace("/\n/", "", shell_exec("git describe --tags `git rev-list --tags --max-count=1`"));
|
||||
$this->version = preg_replace('/^v/', '', $this->getTag());
|
||||
echo GREEN . "Latest tag: " . $this->getTag() . " version: " . $this->getVersion() . "\n" . WHITE;
|
||||
|
||||
$this->git = trim(`which git`);
|
||||
$this->sudo = trim(`which sudo`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get semver version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the git tag we are building
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTag(): string
|
||||
{
|
||||
return $this->latestTag;
|
||||
}
|
||||
|
||||
private function git(string $parameters, bool $sudo = false): void
|
||||
{
|
||||
system(($sudo ? $this->sudo . ' ' : '') . $this->git . ' ' . $parameters);
|
||||
}
|
||||
|
||||
private function sudo(string $command): void
|
||||
{
|
||||
system($this->sudo . ' ' . $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out a repository by tag or branch name to ~/dpp,
|
||||
* using the personal access token and username passed in as command line parameters.
|
||||
*
|
||||
* @param string $tag Tag to clone
|
||||
* @return bool false if the repository could not be cloned
|
||||
*/
|
||||
function checkoutRepository(string $tag = ""): bool
|
||||
{
|
||||
global $argv;
|
||||
|
||||
if (empty($tag)) {
|
||||
/* Empty tag means use the main branch */
|
||||
$tag = `{$this->git} config --get init.defaultBranch || echo master`;
|
||||
}
|
||||
$repositoryUrl = 'https://' . urlencode($argv[1]) . ':' . urlencode($argv[2]) . '@github.com/brainboxdotcc/DPP';
|
||||
|
||||
echo GREEN . "Check out repository: $tag (user: ". $argv[1] . " branch: " . $tag . ")\n" . WHITE;
|
||||
|
||||
chdir(getenv('HOME'));
|
||||
system('rm -rf ./dpp');
|
||||
$this->git('config --global user.email "noreply@dpp.dev"');
|
||||
$this->git('config --global user.name "DPP VCPKG Bot"');
|
||||
$this->git('clone ' . escapeshellarg($repositoryUrl) . ' ./dpp --depth=1');
|
||||
|
||||
/* This is noisy, silence it */
|
||||
$status = chdir(getenv("HOME") . '/dpp');
|
||||
$this->git('fetch -at 2>/dev/null');
|
||||
$this->git('checkout ' . escapeshellarg($tag) . ' 2>/dev/null');
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create ./vcpkg/ports/dpp/vcpkg.json and return the portfile contents to
|
||||
* build the branch that is cloned at ~/dpp
|
||||
*
|
||||
* @param string $sha512 The SHA512 sum of the tagged download, or initially
|
||||
* zero, which means that the vcpkg install command should obtain it the
|
||||
* second time around.
|
||||
* @return string The portfile content
|
||||
*/
|
||||
function constructPortAndVersionFile(string $sha512 = "0"): string
|
||||
{
|
||||
echo GREEN . "Construct portfile for " . $this->getVersion() . ", sha512: $sha512\n" . WHITE;
|
||||
chdir(getenv("HOME") . '/dpp');
|
||||
|
||||
$portFileContent = 'vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO brainboxdotcc/DPP
|
||||
REF "v${VERSION}"
|
||||
# Auto-generated by release CI action at brainboxdotcc/DPP
|
||||
SHA512 ' . $sha512 . '
|
||||
)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
DISABLE_PARALLEL_CONFIGURE
|
||||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
|
||||
vcpkg_cmake_config_fixup(NO_PREFIX_CORRECTION)
|
||||
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share/dpp")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
|
||||
|
||||
if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin" "${CURRENT_PACKAGES_DIR}/debug/bin")
|
||||
endif()
|
||||
|
||||
file(
|
||||
INSTALL "${SOURCE_PATH}/LICENSE"
|
||||
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}"
|
||||
RENAME copyright
|
||||
)
|
||||
|
||||
file(COPY "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
||||
';
|
||||
// ./vcpkg/ports/dpp/vcpkg.json
|
||||
$versionFileContent = '{
|
||||
"name": "dpp",
|
||||
"version": ' . json_encode($this->getVersion()) . ',
|
||||
"description": "D++ Extremely Lightweight C++ Discord Library.",
|
||||
"homepage": "https://dpp.dev/",
|
||||
"license": "Apache-2.0",
|
||||
"supports": "((windows & !static & !uwp) | linux | osx)",
|
||||
"dependencies": [
|
||||
"libsodium",
|
||||
"nlohmann-json",
|
||||
"openssl",
|
||||
"opus",
|
||||
"zlib",
|
||||
{
|
||||
"name": "vcpkg-cmake",
|
||||
"host": true
|
||||
},
|
||||
{
|
||||
"name": "vcpkg-cmake-config",
|
||||
"host": true
|
||||
}
|
||||
]
|
||||
}';
|
||||
echo GREEN . "Writing portfile...\n" . WHITE;
|
||||
file_put_contents('./vcpkg/ports/dpp/vcpkg.json', $versionFileContent);
|
||||
return $portFileContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt the first build of the vcpkg port. This will always fail, as it is given
|
||||
* an SHA512 sum of 0. When it fails the output contains the SHA512 sum, which is then
|
||||
* extracted from the error output using a regular expression, and saved for a second
|
||||
* attempt.
|
||||
* @param string $portFileContent Portfile content from constructPortAndVersionFile()
|
||||
* with an SHA512 sum of 0 passed in.
|
||||
* @return string SHA512 sum of build output
|
||||
*/
|
||||
function firstBuild(string $portFileContent): string
|
||||
{
|
||||
echo GREEN . "Starting first build\n" . WHITE;
|
||||
|
||||
chdir(getenv("HOME") . '/dpp');
|
||||
echo GREEN . "Create /usr/local/share/vcpkg/ports/dpp/\n" . WHITE;
|
||||
$this->sudo('mkdir -p /usr/local/share/vcpkg/ports/dpp/');
|
||||
echo GREEN . "Copy vcpkg.json to /usr/local/share/vcpkg/ports/dpp/vcpkg.json\n" . WHITE;
|
||||
$this->sudo('cp -v -R ./vcpkg/ports/dpp/vcpkg.json /usr/local/share/vcpkg/ports/dpp/vcpkg.json');
|
||||
file_put_contents('/tmp/portfile', $portFileContent);
|
||||
$this->sudo('cp -v -R /tmp/portfile /usr/local/share/vcpkg/ports/dpp/portfile.cmake');
|
||||
unlink('/tmp/portfile');
|
||||
$buildResults = shell_exec($this->sudo . ' /usr/local/share/vcpkg/vcpkg install dpp:x64-linux');
|
||||
$matches = [];
|
||||
if (preg_match('/Actual hash:\s+([0-9a-fA-F]+)/', $buildResults, $matches)) {
|
||||
echo GREEN . "Obtained SHA512 for first build: " . $matches[1] . "\n" . WHITE;
|
||||
$this->firstBuildComplete = true;
|
||||
return $matches[1];
|
||||
}
|
||||
echo RED . "No SHA512 found during first build :(\n" . WHITE;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Second build using a valid SHA512 sum. This attempt should succeed, allowing us to push
|
||||
* the changed vcpkg portfiles into the master branch, where they can be used in a PR to
|
||||
* microsoft/vcpkg repository later.
|
||||
*
|
||||
* @param string $portFileContent the contents of the portfile, containing a valid SHA512
|
||||
* sum from the first build attempt.
|
||||
* @return bool False if the build failed
|
||||
*/
|
||||
function secondBuild(string $portFileContent): bool
|
||||
{
|
||||
|
||||
if (!$this->firstBuildComplete) {
|
||||
throw new RuntimeException("No SHA512 sum is available, first build has not been run!");
|
||||
}
|
||||
|
||||
echo GREEN . "Executing second build\n" . WHITE;
|
||||
echo GREEN . "Copy local port files to /usr/local/share...\n" . WHITE;
|
||||
chdir(getenv("HOME") . '/dpp');
|
||||
file_put_contents('./vcpkg/ports/dpp/portfile.cmake', $portFileContent);
|
||||
$this->sudo('cp -v -R ./vcpkg/ports/dpp/vcpkg.json /usr/local/share/vcpkg/ports/dpp/vcpkg.json');
|
||||
$this->sudo('cp -v -R ./vcpkg/ports/dpp/portfile.cmake /usr/local/share/vcpkg/ports/dpp/portfile.cmake');
|
||||
$this->sudo('cp -v -R ./vcpkg/ports/* /usr/local/share/vcpkg/ports/');
|
||||
|
||||
echo GREEN . "vcpkg x-add-version...\n" . WHITE;
|
||||
chdir('/usr/local/share/vcpkg');
|
||||
$this->sudo('./vcpkg format-manifest ./ports/dpp/vcpkg.json');
|
||||
/* Note: We commit this in /usr/local, but we never push it (we can't) */
|
||||
$this->git('add .', true);
|
||||
$this->git('commit -m "[bot] VCPKG info update"', true);
|
||||
$this->sudo('/usr/local/share/vcpkg/vcpkg x-add-version dpp');
|
||||
|
||||
echo GREEN . "Copy back port files from /usr/local/share...\n" . WHITE;
|
||||
chdir(getenv('HOME') . '/dpp');
|
||||
system('cp -v -R /usr/local/share/vcpkg/ports/dpp/vcpkg.json ./vcpkg/ports/dpp/vcpkg.json');
|
||||
system('cp -v -R /usr/local/share/vcpkg/versions/baseline.json ./vcpkg/versions/baseline.json');
|
||||
system('cp -v -R /usr/local/share/vcpkg/versions/d-/dpp.json ./vcpkg/versions/d-/dpp.json');
|
||||
|
||||
echo GREEN . "Commit and push changes to master branch\n" . WHITE;
|
||||
$this->git('add .');
|
||||
$this->git('commit -m "[bot] VCPKG info update [skip ci]"');
|
||||
$this->git('config pull.rebase false');
|
||||
$this->git('pull');
|
||||
$this->git('push origin master');
|
||||
|
||||
echo GREEN . "vcpkg install...\n" . WHITE;
|
||||
$resultCode = 0;
|
||||
$output = [];
|
||||
exec($this->sudo . ' /usr/local/share/vcpkg/vcpkg install dpp:x64-linux', $output, $resultCode);
|
||||
|
||||
if ($resultCode != 0) {
|
||||
echo RED . "There were build errors!\n\nBuild log:\n" . WHITE;
|
||||
readfile("/usr/local/share/vcpkg/buildtrees/dpp/install-x64-linux-dbg-out.log");
|
||||
}
|
||||
|
||||
return $resultCode == 0;
|
||||
}
|
||||
};
|
||||
10
vendor/DPP/buildtools/make_struct.php
vendored
10
vendor/DPP/buildtools/make_struct.php
vendored
@@ -42,6 +42,8 @@ $forcedReturn = [
|
||||
'message_create' => 'message',
|
||||
'message_edit' => 'message',
|
||||
'thread_create_in_forum' => 'thread',
|
||||
'threads_get_active' => 'active_threads',
|
||||
'user_get_cached' => 'user_identified',
|
||||
];
|
||||
|
||||
/* Get the contents of cluster.h into an array */
|
||||
@@ -61,8 +63,11 @@ if (!$generator->checkForChanges()) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$lastFunc = '<none>';
|
||||
$l = 0;
|
||||
/* Scan every line of the C++ source */
|
||||
foreach ($clustercpp as $cpp) {
|
||||
$l++;
|
||||
/* Look for declaration of function body */
|
||||
if ($state == STATE_SEARCH_FOR_FUNCTION &&
|
||||
preg_match('/^\s*void\s+cluster::([^(]+)\s*\((.*)command_completion_event_t\s*callback\s*\)/', $cpp, $matches)) {
|
||||
@@ -111,10 +116,15 @@ foreach ($clustercpp as $cpp) {
|
||||
$content .= $generator->generateHeaderDef($returnType, $currentFunction, $parameters, $noDefaults, $parameterNames);
|
||||
$cppcontent .= $generator->generateCppDef($returnType, $currentFunction, $parameters, $noDefaults, $parameterNames);
|
||||
}
|
||||
$lastFunc = $currentFunction;
|
||||
$currentFunction = $parameters = $returnType = '';
|
||||
$state = STATE_SEARCH_FOR_FUNCTION;
|
||||
}
|
||||
}
|
||||
if ($state != STATE_SEARCH_FOR_FUNCTION) {
|
||||
die("\n\n\nBuilding headers is broken ($l) - state machine finished in the middle of function $currentFunction (previous $lastFunc) with parameters $parameters rv $returnType state=$state\n\n\n");
|
||||
}
|
||||
|
||||
$content .= <<<EOT
|
||||
|
||||
/* End of auto-generated definitions */
|
||||
|
||||
62
vendor/DPP/buildtools/make_vcpkg.php
vendored
Normal file
62
vendor/DPP/buildtools/make_vcpkg.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Automatic CI process for generating new vcpkg releases.
|
||||
* Based loosely on RealTimeChris's shell script version.
|
||||
*
|
||||
* This updates the content of ./vcpkg directory within the DPP
|
||||
* repository on the master branch, which can then be diffed into
|
||||
* the microsoft/vcpkg master branch to build a PR for the new
|
||||
* release.
|
||||
*
|
||||
* The procedure for this is:
|
||||
*
|
||||
* 1) Generate various configuration files and put them into the
|
||||
* systemwide vcpkg installation inside the CI container
|
||||
* 2) Attempt to build the package from the release tag,
|
||||
* this will fail due to invalid SHA512 sum and return the
|
||||
* correct SHA512 sum in the error output. Inability to get the
|
||||
* SHA512 sum here will return nonzero from the script, failing
|
||||
* the CI action.
|
||||
* 3) Capture the SHA512 from the error output, switch to master
|
||||
* 4) Copy the correct configuration into both the systemwide
|
||||
* vcpkg install in the container, and into the vcpkg directory
|
||||
* of master branch.
|
||||
* 5) Rerun the `vcpkg install` process again to verify it is working.
|
||||
* A build failure here will return a nonzero return code from
|
||||
* the script, failing the CI action.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
use Dpp\Packager\Vcpkg;
|
||||
|
||||
$vcpkg = new Vcpkg();
|
||||
|
||||
/* Check out source for latest tag */
|
||||
if (!$vcpkg->checkoutRepository($vcpkg->getTag())) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* First run with SHA512 of 0 to gather actual value and save it */
|
||||
$sha512 = $vcpkg->firstBuild(
|
||||
$vcpkg->constructPortAndVersionFile()
|
||||
);
|
||||
if (!empty($sha512)) {
|
||||
/* Now check out master */
|
||||
if (!$vcpkg->checkoutRepository()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Attempt second build with the valid SHA512 sum. Program exit
|
||||
* status is the exit status of `vcpkg install`
|
||||
*/
|
||||
exit(
|
||||
$vcpkg->secondBuild(
|
||||
$vcpkg->constructPortAndVersionFile($sha512)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/* Error if no SHA sum could be generated */
|
||||
exit(1);
|
||||
2
vendor/DPP/cmake/ARM64ToolChain.cmake
vendored
2
vendor/DPP/cmake/ARM64ToolChain.cmake
vendored
@@ -10,7 +10,7 @@ SET(CMAKE_LIBRARY_ARCHITECTURE aarch64-linux-gnu)
|
||||
SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE aarch64)
|
||||
SET(CPACK_RPM_PACKAGE_ARCHITECTURE aarch64)
|
||||
|
||||
SET(RASPBERRY_ROOT_PATH ${CMAKE_SOURCE_DIR}/arm_raspberry)
|
||||
SET(RASPBERRY_ROOT_PATH ${DPP_ROOT_PATH}/arm_raspberry)
|
||||
SET(RASPBERRY_KINETIC_PATH ${RASPBERRY_ROOT_PATH}/opt/ros/kinetic)
|
||||
|
||||
SET(CMAKE_FIND_ROOT_PATH ${RASPBERRY_ROOT_PATH} ${CATKIN_DEVEL_PREFIX})
|
||||
|
||||
24
vendor/DPP/cmake/ARMv6ToolChain.cmake
vendored
24
vendor/DPP/cmake/ARMv6ToolChain.cmake
vendored
@@ -3,7 +3,7 @@ SET(CMAKE_SYSTEM_NAME Linux)
|
||||
#SET(CMAKE_SYSTEM_PROCESSOR armhf)
|
||||
|
||||
#If you have installed cross compiler to somewhere else, please specify that path.
|
||||
SET(COMPILER_ROOT /opt/cross-pi-gcc)
|
||||
SET(COMPILER_ROOT /opt/cross-pi-gcc)
|
||||
|
||||
SET(CMAKE_C_COMPILER ${COMPILER_ROOT}/bin/arm-linux-gnueabihf-gcc-8.3.0)
|
||||
SET(CMAKE_CXX_COMPILER ${COMPILER_ROOT}/bin/arm-linux-gnueabihf-g++)
|
||||
@@ -34,17 +34,17 @@ UNSET(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES)
|
||||
SET(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||
INCLUDE_DIRECTORIES(
|
||||
${COMPILER_ROOT}/arm-linux-gnueabihf/libc/usr/include
|
||||
${COMPILER_ROOT}/arm-linux-gnueabihf/include
|
||||
${COMPILER_ROOT}/arm-linux-gnueabihf/include
|
||||
${COMPILER_ROOT}/arm-linux-gnueabihf/include/c++/8.3.0
|
||||
${COMPILER_ROOT}/arm-linux-gnueabihf/include/c++/8.3.0/arm-linux-gnueabihf
|
||||
${COMPILER_ROOT}/lib/gcc/arm-linux-gnueabihf/8.3.0/include
|
||||
${COMPILER_ROOT}/lib/gcc/arm-linux-gnueabihf/8.3.0/include-fixed
|
||||
${CMAKE_SOURCE_DIR}/rootfs/usr/include/arm-linux-gnueabihf)
|
||||
${DPP_ROOT_PATH}/rootfs/usr/include/arm-linux-gnueabihf)
|
||||
SET(CMAKE_INCLUDE_DIRECTORIES_BEFORE OFF)
|
||||
|
||||
SET(ZLIB_LIBRARY ${CMAKE_SOURCE_DIR}/rootfs/lib/arm-linux-gnueabihf/libz.so.1.2.11)
|
||||
SET(OPENSSL_CRYPTO_LIBRARY ${CMAKE_SOURCE_DIR}/rootfs/usr/lib/arm-linux-gnueabihf/libcrypto.so.1.1)
|
||||
SET(OPENSSL_SSL_LIBRARY ${CMAKE_SOURCE_DIR}/rootfs/usr/lib/arm-linux-gnueabihf/libssl.so.1.1)
|
||||
SET(ZLIB_LIBRARY ${DPP_ROOT_PATH}/rootfs/lib/arm-linux-gnueabihf/libz.so.1.2.11)
|
||||
SET(OPENSSL_CRYPTO_LIBRARY ${DPP_ROOT_PATH}/rootfs/usr/lib/arm-linux-gnueabihf/libcrypto.so.1.1)
|
||||
SET(OPENSSL_SSL_LIBRARY ${DPP_ROOT_PATH}/rootfs/usr/lib/arm-linux-gnueabihf/libssl.so.1.1)
|
||||
|
||||
SET(CMAKE_CXX_COMPILER_WORKS 1)
|
||||
SET(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -nostdinc --sysroot=${RASPBERRY_ROOT_PATH} -Wno-psabi " CACHE INTERNAL "" FORCE)
|
||||
@@ -54,11 +54,11 @@ SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} --sysroot=${RASPBERRY_ROOT_PAT
|
||||
|
||||
SET(LD_LIBRARY_PATH ${RASPBERRY_KINETIC_PATH}/lib)
|
||||
|
||||
EXECUTE_PROCESS(COMMAND wget -P ${CMAKE_SOURCE_DIR}/rootfs -q http://content.dpp.dev/zlib1g_1.2.11.dfsg-1_armhf.deb http://content.dpp.dev/zlib1g-dev_1.2.11.dfsg-1_armhf.deb http://content.dpp.dev/libssl1.1_1.1.1m-1_armhf.deb http://content.dpp.dev/libssl-dev_1.1.1m-1_armhf.deb https://content.dpp.dev/raspi-toolchain.tar.gz)
|
||||
EXECUTE_PROCESS(COMMAND wget -P ${DPP_ROOT_PATH}/rootfs -q http://content.dpp.dev/zlib1g_1.2.11.dfsg-1_armhf.deb http://content.dpp.dev/zlib1g-dev_1.2.11.dfsg-1_armhf.deb http://content.dpp.dev/libssl1.1_1.1.1m-1_armhf.deb http://content.dpp.dev/libssl-dev_1.1.1m-1_armhf.deb https://content.dpp.dev/raspi-toolchain.tar.gz)
|
||||
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND tar -xzf ${CMAKE_SOURCE_DIR}/rootfs/raspi-toolchain.tar.gz -C /opt
|
||||
COMMAND sudo dpkg-deb -x ${CMAKE_SOURCE_DIR}/rootfs/zlib1g-dev_1.2.11.dfsg-1_armhf.deb ${CMAKE_SOURCE_DIR}/rootfs
|
||||
COMMAND sudo dpkg-deb -x ${CMAKE_SOURCE_DIR}/rootfs/zlib1g_1.2.11.dfsg-1_armhf.deb ${CMAKE_SOURCE_DIR}/rootfs
|
||||
COMMAND sudo dpkg-deb -x ${CMAKE_SOURCE_DIR}/rootfs/libssl-dev_1.1.1m-1_armhf.deb ${CMAKE_SOURCE_DIR}/rootfs
|
||||
COMMAND sudo dpkg-deb -x ${CMAKE_SOURCE_DIR}/rootfs/libssl1.1_1.1.1m-1_armhf.deb ${CMAKE_SOURCE_DIR}/rootfs)
|
||||
COMMAND tar -xzf ${DPP_ROOT_PATH}/rootfs/raspi-toolchain.tar.gz -C /opt
|
||||
COMMAND sudo dpkg-deb -x ${DPP_ROOT_PATH}/rootfs/zlib1g-dev_1.2.11.dfsg-1_armhf.deb ${DPP_ROOT_PATH}/rootfs
|
||||
COMMAND sudo dpkg-deb -x ${DPP_ROOT_PATH}/rootfs/zlib1g_1.2.11.dfsg-1_armhf.deb ${DPP_ROOT_PATH}/rootfs
|
||||
COMMAND sudo dpkg-deb -x ${DPP_ROOT_PATH}/rootfs/libssl-dev_1.1.1m-1_armhf.deb ${DPP_ROOT_PATH}/rootfs
|
||||
COMMAND sudo dpkg-deb -x ${DPP_ROOT_PATH}/rootfs/libssl1.1_1.1.1m-1_armhf.deb ${DPP_ROOT_PATH}/rootfs)
|
||||
|
||||
6
vendor/DPP/cmake/ARMv7ToolChain.cmake
vendored
6
vendor/DPP/cmake/ARMv7ToolChain.cmake
vendored
@@ -10,13 +10,13 @@ SET(CMAKE_LIBRARY_ARCHITECTURE arm-linux-gnueabihf)
|
||||
SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE armhf)
|
||||
SET(CPACK_RPM_PACKAGE_ARCHITECTURE armhf)
|
||||
|
||||
SET(RASPBERRY_ROOT_PATH ${CMAKE_SOURCE_DIR}/arm_raspberry)
|
||||
SET(RASPBERRY_ROOT_PATH ${DPP_ROOT_PATH}/arm_raspberry)
|
||||
SET(RASPBERRY_KINETIC_PATH ${RASPBERRY_ROOT_PATH}/opt/ros/kinetic)
|
||||
|
||||
SET(CMAKE_FIND_ROOT_PATH ${RASPBERRY_ROOT_PATH} ${CATKIN_DEVEL_PREFIX})
|
||||
|
||||
#If you have installed cross compiler to somewhere else, please specify that path.
|
||||
SET(COMPILER_ROOT /usr/bin)
|
||||
SET(COMPILER_ROOT /usr/bin)
|
||||
|
||||
#Have to set this one to BOTH, to allow CMake to find rospack
|
||||
#This set of variables controls whether the CMAKE_FIND_ROOT_PATH and CMAKE_SYSROOT are used for find_xxx() operations.
|
||||
@@ -41,7 +41,7 @@ SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} --sysroot=${RASPBERRY_ROOT_PAT
|
||||
|
||||
SET(LD_LIBRARY_PATH ${RASPBERRY_KINETIC_PATH}/lib)
|
||||
|
||||
EXECUTE_PROCESS(COMMAND printf "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main multiverse restricted universe\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ focal main multiverse restricted universe\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ focal-updates main multiverse restricted universe\ndeb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal-updates main multiverse restricted universe\ndeb [arch=amd64] http://security.ubuntu.com/ubuntu/ focal-security main multiverse restricted universe"
|
||||
EXECUTE_PROCESS(COMMAND printf "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main multiverse restricted universe\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ focal main multiverse restricted universe\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ focal-updates main multiverse restricted universe\ndeb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal-updates main multiverse restricted universe\ndeb [arch=amd64] http://security.ubuntu.com/ubuntu/ focal-security main multiverse restricted universe"
|
||||
OUTPUT_FILE TMPFILE)
|
||||
EXECUTE_PROCESS(COMMAND sudo mv TMPFILE /etc/apt/sources.list)
|
||||
EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture armhf)
|
||||
|
||||
4
vendor/DPP/cmake/CPackSetup.cmake
vendored
4
vendor/DPP/cmake/CPackSetup.cmake
vendored
@@ -17,7 +17,7 @@ if (WIN32)
|
||||
ARCHIVE DESTINATION ${DPP_INSTALL_LIBRARY_DIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${DPP_INSTALL_INCLUDE_DIR})
|
||||
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/" DESTINATION "${DPP_INSTALL_INCLUDE_DIR}")
|
||||
install(DIRECTORY "${DPP_ROOT_PATH}/include/" DESTINATION "${DPP_INSTALL_INCLUDE_DIR}")
|
||||
else()
|
||||
install(TARGETS dpp
|
||||
EXPORT ${DPP_EXPORT_NAME}
|
||||
@@ -34,7 +34,7 @@ write_basic_package_version_file(${DPP_VERSION_FILE}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
## Include the file which allows `find_package(dpp)` to function.
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/cmake/dpp-config.cmake" "${DPP_VERSION_FILE}" DESTINATION "${DPP_CMAKE_DIR}")
|
||||
install(FILES "${DPP_ROOT_PATH}/cmake/dpp-config.cmake" "${DPP_VERSION_FILE}" DESTINATION "${DPP_CMAKE_DIR}")
|
||||
|
||||
## Export the targets to allow other projects to easily include this project
|
||||
install(EXPORT "${DPP_EXPORT_NAME}" DESTINATION "${DPP_CMAKE_DIR}" NAMESPACE dpp::)
|
||||
|
||||
8
vendor/DPP/cmake/LINUXx86ToolChain.cmake
vendored
8
vendor/DPP/cmake/LINUXx86ToolChain.cmake
vendored
@@ -24,7 +24,9 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 " CACHE INTERNAL "" FORCE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 " CACHE INTERNAL "" FORCE)
|
||||
|
||||
EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture i386)
|
||||
EXECUTE_PROCESS(COMMAND sudo apt update)
|
||||
EXECUTE_PROCESS(COMMAND sudo apt install -y g++-10 gcc-10-multilib glibc-*:i386 libc6-dev-i386 g++-10-multilib zlib1g-dev:i386 libssl-dev:i386 libopus-dev:i386 libsodium-dev:i386)
|
||||
EXECUTE_PROCESS(COMMAND sudo mv /usr/lib/i386-linux-gnu/pkgconfig/libsodium.pc /usr/lib/pkgconfig/)
|
||||
EXECUTE_PROCESS(COMMAND sudo apt-get update)
|
||||
EXECUTE_PROCESS(COMMAND sudo apt-get install -qq -y g++-10 gcc-10-multilib glibc-*:i386 libc6-dev-i386 g++-10-multilib zlib1g-dev:i386 libssl-dev:i386 libopus-dev:i386 libsodium-dev:i386)
|
||||
EXECUTE_PROCESS(COMMAND export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig/)
|
||||
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
HEAD_REF master
|
||||
PATCHES
|
||||
make-pkgconfig-required.patch
|
||||
)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
|
||||
109
vendor/DPP/docpages/01_frequently_asked_questions.md
vendored
109
vendor/DPP/docpages/01_frequently_asked_questions.md
vendored
@@ -1,109 +0,0 @@
|
||||
# Frequently Asked Questions (FAQ)
|
||||
|
||||
[TOC]
|
||||
|
||||
## Is this library in production use?
|
||||
This library powers the bot [TriviaBot](https://triviabot.co.uk) which has over **151,000 servers**, and [Sporks](https://sporks.gg) which has over **3,500 severs**. The library's use in these bots shows that the library is production ready for bots of all sizes.
|
||||
|
||||
## How much RAM does this library use?
|
||||
In production on TriviaBot, the bot takes approximately 2gb of ram to run 18 separate processes (this is approximately **140mb** per process) on a production bot with 36 million users and 151,000 guilds. Each process takes under 1% CPU. This is less than a quarter of the memory of a similar C++ Discord library, **Aegis.cpp** (version 2).
|
||||
|
||||
For a very small bot, you can get the memory usage as low as **6 megabytes** on a Raspberry Pi.
|
||||
|
||||
## How do I use this library in Windows?
|
||||
The easiest way is to use our [template project](https://github.com/brainboxdotcc/windows-bot-template). If you are unable to do this, download the precompiled latest release from our GitHub releases, and take the dlls, .lib file, and header files (`bin`, `lib` and `include` directories), placing them in a easily accessible place on your computer. Go into Visual Studio project settings in a new project, and point the project directories (notably the library directories and and include directories) at the correct locations. Add the `include` folder you extracted to your include directories, and add `dpp.lib` to your library directories. Ensure the project is set to C++17 standard in the settings. You should then be able to compile example programs within that project. When you run the program you have compiled you must ensure that all the dll files from the `bin` directory exist in the same directory as your executable.
|
||||
|
||||
## Does this library support Visual Studio 2022?
|
||||
Yes! The master branch comes with pre-built binaries for Visual Studio 2022 and our windows bot template has a [vs2022 branch](https://github.com/brainboxdotcc/windows-bot-template/tree/vs2022) which you can clone to get Visual Studio 2022 specific code. For the time being we support both Visual Studio 2019 and 2022. At some point in the future only 2022 may be supported as 2019 becomes outdated.
|
||||
|
||||
## How much of the library is completed?
|
||||
All REST calls (outbound commands) are completed including all currently available interactions, and all Discord events are available. The library also has voice support.
|
||||
|
||||
## How do I chat with the developers or get help?
|
||||
The best place to do this is on the [Discord server](https://discord.gg/dpp). You most likely won't get an answer immediately (we have lives, and need to sleep sometimes), but we will be willing to help!
|
||||
|
||||
## How can I contribute to development?
|
||||
Just star and fork a copy of the repository, and submit a Pull Request! We won't bite! Authors of accepted pull requests get a special role on our [Discord server](https://discord.gg/dpp).
|
||||
|
||||
## Whats the best way to learn C++?
|
||||
A simple search can find some learning tools, however not all are good. Here is a list of some (good) learning resources:
|
||||
|
||||
* [CodeAcademy](https://www.codecademy.com/learn/c-plus-plus)
|
||||
* [Learn CPP](https://www.learncpp.com/)
|
||||
* [Learn CPP (Very Basic)](https://www.learn-cpp.org/)
|
||||
|
||||
If you don't understand something then feel free to ask in the [Discord server](https://discord.gg/dpp) ...*we don't bite!*
|
||||
|
||||
## Do I need to be an expert in C++ to use this library?
|
||||
NO! Definitely not! We have tried to keep things as simple as possible. We only use language features where they make sense, not just because they exist. Take a look at the example program (`test.cpp` and you'll see just how simple it is to get up and running quickly). We use a small subset of C++17 and C++14 features.
|
||||
|
||||
## Why is D++ also called DPP
|
||||
DPP is short for *D Plus Plus* (D++), a play on the Discord and C++ names. You'll see the library referred to as `dpp` within source code as `d++` is not a valid symbol so we couldn't exactly use that as our namespace name.
|
||||
|
||||
## Is D++ a single header library?
|
||||
No, D++ is a classically designed library which installs itself to your library directory/system directory as a shared object or dll. You must link to its .lib file and include its header files to make use of it. We have no plans for a single-header build.
|
||||
|
||||
## Does this library support slash commands/interactions?
|
||||
Yes! This library supports slash commands and interactions. For more information please see \ref slashcommands "Using Slash Commands and Interactions".
|
||||
|
||||
## Does this library support buttons/drop down menus (message components)?
|
||||
Yes! This library supports button message components, e.g. interactive buttons on the bottom of messages. For more information please see our \ref components "Using component interactions" and \ref components2 "Using component interactions (advanced)" examples.
|
||||
|
||||
## Is the library asynchronous?
|
||||
All functions within D++ are multi-threaded. You should still avoid doing long operations within event handlers or within callbacks, to prevent starvation of the threads managing each shard. Various blocking operations such as running files and making HTTP requests are offered as library functions (for example dpp::utility::exec)
|
||||
|
||||
## Does this library support voice?
|
||||
Yes! This library supports voice and will automatically enable voice if your system has the libopus and libsodium libraries. When running `cmake` the script will identify if these libraries are found. See the example programs for information on how to send audio.
|
||||
|
||||
## Does this library support sharding?
|
||||
Yes! D++ supports sharding and also clustering (grouping of shards into one process) to ensure it is scalable for small and large bots alike.
|
||||
|
||||
## How do I contribute to the documentation and website?
|
||||
The documentation and website are built using Doxygen. To contribute to site pages, submit a Pull Request to the main repository. The site pages can be found within the `docpages` directory. Details of classes, variables, namespaces etc are auto generated from Doxygen comments within the library source code in the `include` and `src` folders.
|
||||
|
||||
## What version of the Discord API does this library support?
|
||||
D++ only supports Discord API v10, the latest version. D++ major version numbers match the supported Discord API version.
|
||||
|
||||
## Does this Discord library support the threads feature?
|
||||
Yes! D++ supports Discord threads. You can create, edit and delete threads and also attach events watching for messages within threads.
|
||||
|
||||
## Does D++ require C++20 support?
|
||||
No, at the current time we do not use any C++20 features. Some C++17 features are used, which are available in all recent compilers.
|
||||
|
||||
## When I start my bot i get an error: "error while loading shared libraries: libdpp.so: cannot open shared object file: No such file or directory"
|
||||
To fix this issue, run `ldconfig`: `sudo ldconfig` as root. Log out if your SSH session and log back in, and the bot should be able to find the library.
|
||||
|
||||
## When compiling with voice support, i get an error: "No rule to make target 'sodium_LIBRARY_DEBUG-NOTFOUND', needed by 'libdpp.so'. Stop."
|
||||
The libsodium package requires pkg-config, but does not check for it when installed. Install it as root, e.g. `sudo apt install pkg-config`. Rerun cmake, and rebuild the library.
|
||||
|
||||
## When I try to instantiate a dpp::cluster in windows, a std::bad_alloc exception is thrown
|
||||
If this happens, ensure you are using the correct precompiled build of the library. Our precompiled binaries are built in two forms, **release mode** and **debug mode** for Visual Studio 2019/2022. These two versions of the library are not cross-compatible due to differences in the debug and release libstdc++. You should not need to build your own copy, but please see the section about \ref buildwindows for more information on how to build your own copy, if needed.
|
||||
|
||||
## Does this library build/run on Raspberry Pi?
|
||||
Yes! This project will build and run on Raspberry Pi and is very much suited to this kind of system. It may take some time (read: hours) to compile the project on your Raspberry Pi unless you build it using a cross compiler. We offer pre-built `.deb` files for arm6, arm7 and arm64, you should use these where possible to avoid having to compile it by hand, or you can use a cross-compiler to build it on your PC then transfer the compiled binaries across.
|
||||
|
||||
## There are so many versions! Which deb file do i need for my Raspberry Pi?
|
||||
Depending on which Raspberry Pi version you have, you will need to download a different release binary:
|
||||
<table>
|
||||
<tr>
|
||||
<th>Raspberry Pi Model</th>
|
||||
<th>Deb file to install</th>
|
||||
<th>Arch</th>
|
||||
</tr>
|
||||
<tr><td>Raspberry Pi Zero/Zero W</td><td>`libdpp-x.x.x-linux-rpi-arm6.deb`</td><td>ARMv6</td></tr>
|
||||
<tr><td>Raspberry Pi 3</td><td>`libdpp-x.x.x-linux-rpi-arm7hf.deb`</td><td>ARMv7HF</td></tr>
|
||||
<tr><td>Raspberry Pi 4</td><td>`libdpp-x.x.x-linux-rpi-arm7hf.deb`</td><td>ARMv7HF</td></tr>
|
||||
<tr><td>Raspberry Pi 4 with 64 Bit Linux</td><td>`libdpp-x.x.x-linux-rpi-arm64.deb`</td><td>ARM64</td></tr>
|
||||
</table>
|
||||
|
||||
## Are other ARM devices supported?
|
||||
Yes! We have confirmed that the D++ deb file will successfully install and operate on various forms of cellphone or non-pi ARM devices. If you get it working on any other devices please let us know and we can build a compatibility chart.
|
||||
|
||||
## Can I run a D++ bot in repl.it?
|
||||
Yes! You can indeed run your bot in a repl.it container. [You can find a ready to go demo repl here](https://replit.com/@braindigitalis/dpp-demo-bot). We also have a [guide showing how to do this](https://dpp.dev/building-a-cpp-discord-bot-in-repl.html).
|
||||
|
||||
## Why do the "get" functions like "messages_get" return void rather than what I'm after?
|
||||
All the functions that obtain data directly from Discord (as opposed to the cache) perform HTTPS requests and may have to wait, either for the request itself or for their turn in a queue to respect rate limits. As such, it does not make sense that they should return a value, as this would mean they block execution of your event. Instead, each has a lambda, a function handler which receives the result of the request, which you can then read from within that function to get the data you are interested in. Note that this result will arrive on a different thread to the one which made the request. If you instead want the function to return a value, use the methods ending with `_sync` that will block until they have a response. Note that these forms of call will throw an exception on failure.
|
||||
|
||||
## Can i use a user token with this library (as opposed to a bot token)?
|
||||
No. This feature is not supported as it is against the Discord Terms Of Service, and therefore we have no plans to ever support it. You should not automate any user token. Some libraries used to support this but it is a legacy feature of those libraries (where still available) dating back to before Discord offered an official public API. Please be aware that if Discord ever catch you automating a user token (or making a user client that uses a bot token) they can and do ban people for this.
|
||||
11
vendor/DPP/docpages/01_installing.md
vendored
11
vendor/DPP/docpages/01_installing.md
vendored
@@ -1,11 +0,0 @@
|
||||
# Installing D++
|
||||
|
||||
There are many ways to install D++, either from a package manager, or from source. Please choose your desired option from the list below:
|
||||
|
||||
* \subpage install-linux-deb
|
||||
* \subpage install-linux-rpm
|
||||
* \subpage install-vcpkg
|
||||
* \subpage install-arch-aur
|
||||
* \subpage install-windows-zip
|
||||
* \subpage install-xmake
|
||||
* \subpage install-from-source
|
||||
14
vendor/DPP/docpages/02_building_a_bot.md
vendored
14
vendor/DPP/docpages/02_building_a_bot.md
vendored
@@ -1,14 +0,0 @@
|
||||
# Creating a Discord Bot
|
||||
|
||||
If you are wanting to build a bot using C++, you're in the right place! The fast and easy tutorials below will guide you through how to build a bot using the D++ library on either a UNIX-like (e.g. Linux) system with CMake or with Windows using Visual Studio 2019.
|
||||
|
||||
Click on a link below for a guide specifically for your system:
|
||||
|
||||
* \subpage creating-a-bot-application "Creating a Bot Token"
|
||||
* \subpage build-a-discord-bot-windows-visual-studio "Building a discord bot in Windows using Visual Studio"
|
||||
* \subpage build-a-discord-bot-windows-wsl "Building a discord bot in Windows using WSL (Windows Subsystem for Linux)"
|
||||
* \subpage build-a-discord-bot-linux-clion "Building a discord bot in Linux using CLion"
|
||||
* \subpage buildcmake "Building a Discord Bot using CMake/UNIX"
|
||||
* \subpage buildmeson "Building a Discord Bot using Meson"
|
||||
* \subpage building-a-cpp-discord-bot-in-repl "Creating a Discord bot in Repl.it"
|
||||
|
||||
10
vendor/DPP/docpages/03_example_programs.md
vendored
10
vendor/DPP/docpages/03_example_programs.md
vendored
@@ -1,10 +0,0 @@
|
||||
# Example Programs
|
||||
|
||||
There are example programs here for all skill levels demonstrating a great many features of the bot. New examples are added frequently, please check regularly for new content.
|
||||
|
||||
* \subpage the-basics
|
||||
* \subpage interactions-and-components
|
||||
* \subpage music-and-audio
|
||||
* \subpage misc
|
||||
|
||||
Is the example you are looking for missing from these sections? Pop over to our [discord server](https://discord.com/dpp) and let us know what you need... Or, even better, if you know how to do something and want to contribute an example of your own, just submit a PR!
|
||||
7
vendor/DPP/docpages/04_advanced_reference.md
vendored
7
vendor/DPP/docpages/04_advanced_reference.md
vendored
@@ -1,7 +0,0 @@
|
||||
# Advanced Reference
|
||||
|
||||
* \subpage clusters-shards-guilds "Clusters, Shards and Guilds"
|
||||
* \subpage thread-model "Thread Model"
|
||||
* \subpage coding-standards "Coding Style Standards"
|
||||
* \subpage unit-tests "Unit Tests"
|
||||
* \subpage lambdas-and-locals "Ownership of local variables and safely transferring into a lambda"
|
||||
BIN
vendor/DPP/docpages/DPP-markdown-logo.png
vendored
BIN
vendor/DPP/docpages/DPP-markdown-logo.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 5.6 KiB |
77
vendor/DPP/docpages/INDEX.md
vendored
77
vendor/DPP/docpages/INDEX.md
vendored
@@ -1,77 +0,0 @@
|
||||
# D++: A C++ Discord API Library for Bots
|
||||
|
||||
## What is D++ (DPP)?
|
||||
|
||||
D++ is a lightweight and simple library for Discord written in modern C++. It is designed to cover as much of the API specification as possible and to have a incredibly small memory footprint, even when caching large amounts of data.
|
||||
|
||||
It is created by the developer of [TriviaBot](https://triviabot.co.uk) and contributed to by a dedicated team of developers.
|
||||
|
||||
*This project is in stable development and accepting PRs and feature requests — Don't be a stranger! If you want to contribute, just get in touch via [GitHub](https://github.com/brainboxdotcc/DPP) or our official [Discord server](https://discord.gg/dpp)!*
|
||||
|
||||
<img src="code_editor.png" style="margin-top: 2rem; margin-bottom: 2rem"/><br />
|
||||
|
||||
## Downloads
|
||||
|
||||
The following downloads are for the most recent version:
|
||||
|
||||
* [Source Code](https://github.com/brainboxdotcc/DPP)
|
||||
* [x64 Linux .deb (64 bit Debian, Ubuntu etc)](https://dl.dpp.dev/latest)
|
||||
* [x86 Linux .deb (32 bit Debian, Ubuntu etc)](https://dl.dpp.dev/latest/linux-i386)
|
||||
* [x64 Linux .rpm (64 bit Redhat, CentOS etc)](https://dl.dpp.dev/latest/linux-x64/rpm)
|
||||
* [x86 Linux .rpm (32 bit Redhat, CentOS etc)](https://dl.dpp.dev/latest/linux-i386/rpm)
|
||||
* [x64 Windows (64 bit vs2019 release build)](https://dl.dpp.dev/latest/win64-release-vs2019)
|
||||
* [x64 Windows (64 bit vs2022 release build)](https://dl.dpp.dev/latest/win64-release-vs2022)
|
||||
* [x64 Windows (64 bit vs2019 debug build)](https://dl.dpp.dev/latest/win64-debug-vs2019)
|
||||
* [x64 Windows (64 bit vs2022 debug build)](https://dl.dpp.dev/latest/win64-debug-vs2022)
|
||||
* [ARM6 Linux .deb (32 bit Raspberry Pi 1, 2)](https://dl.dpp.dev/latest/linux-rpi-arm6)
|
||||
* [ARM7 Linux .deb (32 bit Raspberry Pi 3, 4)](https://dl.dpp.dev/latest/linux-rpi-arm7hf)
|
||||
* [ARM64 Linux .deb (64 bit Raspberry Pi 4, Smartphones)](https://dl.dpp.dev/latest/linux-rpi-arm64)
|
||||
|
||||
You can find further releases in other architectures and formats or the source code on the [GitHub Repository](https://github.com/brainboxdotcc/DPP/releases). For a realtime JSON format list of all download links, click [here](https://dl.dpp.dev/json)
|
||||
|
||||
## Library features
|
||||
|
||||
* Support for Discord API v10
|
||||
* Really small memory footprint
|
||||
* Efficient caching system for guilds, channels, guild members, roles, users
|
||||
* Sharding and clustering (Many shards, one process: specify the number of shards, or let the library decide)
|
||||
* Highly optimised ETF (Erlang Term Format) support for very fast websocket throughput (*no other C++ Discord library has this!*)
|
||||
* [Slash Commands/Interactions support](https://dpp.dev/slashcommands.html)
|
||||
* [Voice support](https://dpp.dev/soundboard.html) (sending **and** receiving audio)
|
||||
* The entire Discord API is available for use in the library
|
||||
* Stable [Windows support](https://dpp.dev/buildwindows.html)
|
||||
* Ready-made compiled packages for Windows, Raspberry Pi (ARM64/ARM7/ARMv6), Debian x86/x64 and RPM based distributions
|
||||
* Highly scalable for large amounts of guilds and users
|
||||
|
||||
## Supported Operating Systems
|
||||
|
||||
### Linux
|
||||
The library runs ideally on **Linux**.
|
||||
|
||||
### Mac OS X and FreeBSD
|
||||
The library is well-functional and stable on **Mac OS X** and **FreeBSD** too.
|
||||
|
||||
### Raspberry Pi
|
||||
For running your bot on a **Raspberry Pi**, we offer a prebuilt .deb package for ARM64, ARM6, and ARM7 so that you do not have to wait for it to compile.
|
||||
|
||||
### Windows
|
||||
**Windows** is well-supported with ready-made compiled DLL and LIB files, please check out our [Windows Bot Template repository](https://github.com/brainboxdotcc/windows-bot-template). The Windows Bot repository can be cloned and integrated immediately into any Visual Studio 2019 and 2022 project in a matter of minutes.
|
||||
|
||||
### Other OS
|
||||
The library should work fine on other operating systems as well, and if you run a D++ bot on something not listed here, please let us know!
|
||||
|
||||
## Getting started
|
||||
* [GitHub Repository](https://github.com/brainboxdotcc/DPP)
|
||||
* [Discord Server](https://discord.gg/dpp)
|
||||
* [Frequently Asked Questions](/md_docpages_01_frequently_asked_questions.html)
|
||||
* [Installing D++](/md_docpages_01_installing.html)
|
||||
* [Example Programs](/md_docpages_03_example_programs.html)
|
||||
|
||||
## Architecture
|
||||
* \ref clusters-shards-guilds
|
||||
* \ref thread-model
|
||||
|
||||
## Learning Resources
|
||||
* [C++ for JavaScript Developers](https://pawelgrzybek.com/cpp-for-javascript-developers/)
|
||||
* [C++ In Four Hours](https://www.youtube.com/watch?v=vLnPwxZdW4Y&vl=en)
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
\page clusters-shards-guilds Clusters, Shards and Guilds
|
||||
|
||||
D++ takes a three-tiered highly scalable approach to bots, with three levels known as Clusters, Shards and Guilds as documented below.
|
||||
|
||||
\dot
|
||||
digraph "Clusters, Shards and Guilds" {
|
||||
node [colorscheme="blues9",fontname="helvetica"];
|
||||
subgraph Bot {
|
||||
node [style=filled, color=1];
|
||||
label = "Bot"
|
||||
"Bot" [shape=folder, label="Bot", bordercolor=black];
|
||||
};
|
||||
subgraph Processes {
|
||||
node [style=filled, color=2];
|
||||
label = "Processes"
|
||||
"Bot" -> "Process 1"
|
||||
"Bot" -> "Process 2"
|
||||
"Process 1" [shape=record, label="Process"];
|
||||
"Process 2" [shape=record, label="Process"];
|
||||
};
|
||||
subgraph Clusters {
|
||||
node [style=filled, color=3];
|
||||
label = "Clusters"
|
||||
"Process 1" -> "Cluster 1"
|
||||
"Process 2" -> "Cluster 2"
|
||||
"Cluster 1" [shape=record, label="Cluster"];
|
||||
"Cluster 2" [shape=record, label="Cluster"];
|
||||
};
|
||||
subgraph Shards {
|
||||
node [style=filled, color=4];
|
||||
label = "Shards"
|
||||
"Shard 1" [shape=record, label="Shard"];
|
||||
"Shard 2" [shape=record, label="Shard"];
|
||||
"Shard 3" [shape=record, label="Shard"];
|
||||
"Shard 4" [shape=record, label="Shard"];
|
||||
"Shard 5" [shape=record, label="Shard"];
|
||||
"Shard 6" [shape=record, label="Shard"];
|
||||
"Shard 7" [shape=record, label="Shard"];
|
||||
"Shard 8" [shape=record, label="Shard"];
|
||||
"Cluster 1" -> "Shard 1"
|
||||
"Cluster 1" -> "Shard 3"
|
||||
"Cluster 2" -> "Shard 2"
|
||||
"Cluster 2" -> "Shard 4"
|
||||
"Cluster 1" -> "Shard 5"
|
||||
"Cluster 1" -> "Shard 7"
|
||||
"Cluster 2" -> "Shard 6"
|
||||
"Cluster 2" -> "Shard 8"
|
||||
};
|
||||
subgraph Guilds {
|
||||
node [style=filled, color=5];
|
||||
label = "Guilds";
|
||||
"Guild 1" [shape=record, label="Guild"];
|
||||
"Guild 2" [shape=record, label="Guild"];
|
||||
"Guild 3" [shape=record, label="Guild"];
|
||||
"Guild 4" [shape=record, label="Guild"];
|
||||
"Guild 5" [shape=record, label="Guild"];
|
||||
"Guild 6" [shape=record, label="Guild"];
|
||||
"Guild 7" [shape=record, label="Guild"];
|
||||
"Guild 8" [shape=record, label="Guild"];
|
||||
"Guild 9" [shape=record, label="Guild"];
|
||||
"Guild 10" [shape=record, label="Guild"];
|
||||
"Guild 11" [shape=record, label="Guild"];
|
||||
"Guild 12" [shape=record, label="Guild"];
|
||||
"Guild 13" [shape=record, label="Guild"];
|
||||
"Guild 14" [shape=record, label="Guild"];
|
||||
"Guild 15" [shape=record, label="Guild"];
|
||||
"Guild 16" [shape=record, label="Guild"];
|
||||
"Shard 1" -> "Guild 1"
|
||||
"Shard 1" -> "Guild 5"
|
||||
"Shard 2" -> "Guild 2"
|
||||
"Shard 2" -> "Guild 6"
|
||||
"Shard 3" -> "Guild 3"
|
||||
"Shard 3" -> "Guild 7"
|
||||
"Shard 4" -> "Guild 4"
|
||||
"Shard 4" -> "Guild 8"
|
||||
"Shard 5" -> "Guild 9"
|
||||
"Shard 5" -> "Guild 11"
|
||||
"Shard 6" -> "Guild 10"
|
||||
"Shard 6" -> "Guild 12"
|
||||
"Shard 7" -> "Guild 13"
|
||||
"Shard 7" -> "Guild 15"
|
||||
"Shard 8" -> "Guild 14"
|
||||
"Shard 8" -> "Guild 16"
|
||||
};
|
||||
}
|
||||
\enddot
|
||||
|
||||
## Clusters
|
||||
|
||||
A bot may be made of one or more clusters. Each cluster maintains a queue of commands waiting to be sent to Discord, a queue of replies from Discord for all commands executed, and zero or more **shards**. Usually, each process has one cluster, but the D++ library does not enforce this as a restriction. Small bots will require just one cluster. Clusters will split the required number of shards equally across themselves. There is no communication between clusters unless you add some yourself, they all remain independent without any central "controller" process. This ensures that there is no single point of failure in the design. Whenever you instantiate the library, you generally instantiate a cluster:
|
||||
|
||||
```cpp
|
||||
#include <dpp/dpp.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
/* This is a cluster */
|
||||
dpp::cluster bot("Token goes here");
|
||||
}
|
||||
```
|
||||
|
||||
## Shards
|
||||
|
||||
A cluster contains zero or more shards. Each shard maintains a persistent websocket connection to Discord via a websocket, which receives all events the bot is made aware of, e.g. messages, channel edits, etc. Requests to the API on the other hand go out to Discord as separate HTTP requests.
|
||||
|
||||
Small bots will require only one shard and this is the default when you instantiate a cluster. The library will automatically determine and create the correct number of shards needed, if you do not configure it by hand. If you do want to specify a number of shards, you can specify this when creating a cluster:
|
||||
|
||||
```cpp
|
||||
#include <dpp/dpp.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
/* This is a cluster */
|
||||
int total_shards = 10;
|
||||
dpp::cluster bot("Token goes here", dpp::i_default_intents, total_shards);
|
||||
}
|
||||
```
|
||||
|
||||
Remember that if there are multiple clusters, the number of shards you request will be split equally across these clusters!
|
||||
|
||||
@note To spawn multiple clusters, you can specify this as the 4th and 5th parameter of the dpp::cluster constructor. You must do this, if you want this functionality. The library will not create additional clusters for you, as what you require is dependent upon your system specifications. It is your responsibility to somehow get the cluster id and total clusters into the process, e.g. via a command line argument. An example of this is shown below based on the cluster setup code of **TriviaBot**:
|
||||
```cpp
|
||||
#include <dpp/dpp.h>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int total_shards = 64;
|
||||
int index;
|
||||
char arg;
|
||||
bool clusters_defined = false;
|
||||
uint32_t clusterid = 0;
|
||||
uint32_t maxclusters = 1;
|
||||
|
||||
/* Parse command line parameters using getopt() */
|
||||
struct option longopts[] =
|
||||
{
|
||||
{ "clusterid", required_argument, NULL, 'c' },
|
||||
{ "maxclusters", required_argument, NULL, 'm' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
opterr = 0;
|
||||
while ((arg = getopt_long_only(argc, argv, "", longopts, &index)) != -1) {
|
||||
switch (arg) {
|
||||
case 'c':
|
||||
clusterid = std::stoul(optarg);
|
||||
clusters_defined = true;
|
||||
break;
|
||||
case 'm':
|
||||
maxclusters = std::stoul(optarg);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown parameter '" << argv[optind - 1] << "'\n";
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (clusters_defined && maxclusters == 0) {
|
||||
std::cerr << "ERROR: You have defined a cluster id with -clusterid but no cluster count with -maxclusters.\n";
|
||||
exit(2);
|
||||
}
|
||||
|
||||
dpp::cluster bot("Token goes here", dpp::default_intents, total_shards, clusterid, maxclusters);
|
||||
}
|
||||
```
|
||||
|
||||
### Large Bot Sharding
|
||||
|
||||
Discord restricts how many shards you can connect to at any one time to one per five seconds, unless your bot is in at least 150,000 guilds. Once you reach 150,000 guilds, Discord allow your bot to connect to more guilds concurrently, and your number of shards must divide cleanly into this value. By default, at 150,000 guilds this concurrency value is 16 meaning D++ will attempt to connect 16 shards in parallel, then wait for all these to connect and then connect another 16, until all shards are connected. In practice, this means a large bot with many shards (read: hundreds!) will connect significantly faster after a full restart. **You do not need to manually configure large bot sharding and connection concurrency, the D++ library will handle this for you if you are able to use it**.
|
||||
|
||||
|
||||
## Guilds
|
||||
|
||||
Guilds are what servers are known as to the Discord API. There can be up to **2500** of these per shard. Once you reach 2500 guilds on your bot, Discord force your bot to shard, the D++ library will automatically create additional shards to accomodate if not explicitly configured with a larger number. Discord *does not restrict sharding* to bots on 2500 guilds or above. You can shard at any size of bot, although it would be a waste of resources to do so unless it is required.
|
||||
@@ -1,116 +0,0 @@
|
||||
\page coding-standards Coding Style Standards
|
||||
|
||||
This page lists the coding style we stick to when maintaining the D++ library. If you are submitting a pull request or other code contribution to the library, you should stick to the styles listed below. If something is not covered here, ask on the [official discord server](https://discord.gg/dpp)!
|
||||
|
||||
## Class names, function names and method names
|
||||
All class, variable/member, function and method names should use `snake_case`, similar to the style of the C++ standard library.
|
||||
|
||||
## Enums
|
||||
Enums and their values should be `snake_case` as with class, function and method names. You do not need to use `enum class`, so make sure that enum values are prefixed with a prefix to make them unique and grouped within the IDE, e.g. `ll_debug`, `ll_trace` etc.
|
||||
|
||||
|
||||
## Curly Braces, Brackets etc
|
||||
|
||||
Open curly braces on the same line as the keyword, for example:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
if (a == b) {
|
||||
c();
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use a space after the comma in parameter lists, and after opening brackets and before closing brackets except when calling a function, e.g.:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
std::vector<std::string> clowns = { "pennywise", "bobo" };
|
||||
|
||||
evaluate_clown(clowns[0], evilness(2.5, factor));
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Indentation
|
||||
Indentation should always be tab characters. It is up to you how wide you set tab characters in your editor for your personal tastes. All code blocks delimited within curly braces should be indented neatly and uniformly.
|
||||
|
||||
## Constants and \#define macros
|
||||
Constants and macros should be all `UPPERCASE` with `SNAKE_CASE` to separate words. Macros should not have any unexpected side effects.
|
||||
|
||||
## Comments
|
||||
All comments should be in `doxygen` format (similar to javadoc). Please see existing class definitions for an example. You should use doxygen style comments in a class definition inside a header file, and can use any other comment types within the .cpp file. Be liberal with comments, especially if your code makes any assumptions!
|
||||
|
||||
## Symbol exporting
|
||||
If you export a class which is to be accessible to users, be sure to prefix it with the `DPP_EXPORT` macro, for example:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
class DPP_EXPORT my_new_class {
|
||||
public:
|
||||
int hats;
|
||||
int clowns;
|
||||
};
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The `DPP_EXPORT` macro ensures that on certain platforms (notably Windows) the symbol is exported to be available to the library user.
|
||||
|
||||
## Public vs private vs protected
|
||||
It is a design philosophy of D++ that everything possible in a class should be public, unless the user really does not need it (you should consider justifying in comments why) or user adjustment of the variable could badly break the functioning of the library. Avoid the use of accessors for setting/getting values in a class, except for bit fields, where you should provide accessors for setting and getting individual bits (for example, see `user.h`), or in the event you want to provide a "fluent" interface. The exception to this is where you want to provide a logic validation of a field, for example if you have a string field with a minimum and maximum length, you can provide a setter the user can *optionally use* which will validate their input.
|
||||
|
||||
## Exceptions
|
||||
All exceptions thrown should derive from dpp::exception (see dpp/exception.h) - when validating string lengths, a string which is too long should be truncated using dpp::utility::utf8substr and any strings that are too short should throw a dpp::length_exception.
|
||||
|
||||
## Inheritance
|
||||
Keep levels of inheritance low. If you need to inherit more than 3 levels deep, it is probable that the design could be simplified. Remember that at scale, there can be tens of millions of certain classes and each level of virtual nesting adds to the `vtable` of that object's instance in RAM.
|
||||
|
||||
## Bit field packing
|
||||
Where discord provides boolean flags, if the user is expected to store many of the object in RAM, or in cache, you should pack all these booleans into bit fields (see `user.h` and `channel.h` for examples). In the event that the object is transient, such as an interaction or a message, packing the data into bit fields is counter intuitive. Remember that you should provide specific accessors for bit field values!
|
||||
|
||||
## Keep dependencies internal!
|
||||
Where you are making use of an external dependency such as `opus` or `libssl`, do not place references to the types/structs, or the header files of these external libraries within the header files of D++. Doing so adds that library as a public dependency to the project (which is bad!). Instead make an opaque class, and/or forward-declare the structs (for examples see `sslclient.h` and `discordvoiceclient.h`).
|
||||
|
||||
## API type names
|
||||
Where discord provide a name in PascalCase we should stick as closely to that name as possible but convert it to `snake_case`. For example, GuildMember would become `guild_member`.
|
||||
|
||||
## Don't introduce any platform-specific code
|
||||
Do not introduce platform specific (e.g. windows only) code or libc functions. If you really must use these functions safely wrap them e.g. in `#ifdef _WIN32` and provide a cross-platform alternative so that it works for everyone.
|
||||
|
||||
## Select the right size type for numeric types
|
||||
If a value will only hold values up to 255, use `uint8_t`. If a value cannot hold over 65536, use `uint16_t`. These types can help use a lot less ram at scale.
|
||||
|
||||
## Fluent design
|
||||
Where possible, if you are adding methods to a class you should consider fluent design. Fluent design is the use of class methods tha return a reference to self (via `return *this`), so that you can chain object method calls together (in the way `dpp::message` and `dpp::embed` do). For example:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
class DPP_EXPORT my_new_class {
|
||||
public:
|
||||
int hats;
|
||||
int clowns;
|
||||
|
||||
my_new_class& set_hats(int new_hats);
|
||||
my_new_class& set_clowns(int new_clowns);
|
||||
};
|
||||
|
||||
my_new_class& my_new_class::set_hats(int new_hats) {
|
||||
hats = new_hats;
|
||||
return *this;
|
||||
}
|
||||
|
||||
my_new_class& my_new_class::set_clowns(int new_clowns) {
|
||||
clowns = new_clowns;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This would allow the user to do this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
dpp::my_new_class nc;
|
||||
nc.set_hats(3).set_clowns(9001);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Keep all D++ related types in the dpp namespace
|
||||
|
||||
All types for the library should be within the `dpp` namespace. There are a couple of additional namespaces, e.g. `dpp::utility` for static standalone helper functions and helper classes, and `dpp::events` for internal websocket event handlers.
|
||||
|
||||
## Commit messages and Git
|
||||
|
||||
All pull requests ("PRs") should be submitted against the `dev` branch in GitHub. It’s good to have descriptive commit messages, or PR titles so that other contributors can understand about your commit or the PR Created. Read [conventional commits](https://www.conventionalcommits.org/en/v1.0.0-beta.3/) for information on how we like to format commit messages.
|
||||
|
||||
All PRs must pass the [GitHub Actions](https://github.com/brainboxdotcc/DPP/actions) tests before being allowed to be merged. This is to ensure that no code committed into the project fails to compile on any of our officially supported platforms or architectures.
|
||||
@@ -1,56 +0,0 @@
|
||||
\page lambdas-and-locals Ownership of local variables and safely transferring into a lambda
|
||||
|
||||
If you are reading this page, you have likely been sent here by someone helping you diagnose why your bot is crashing or why seemingly invalid values are being passed into lambdas within your program that uses D++.
|
||||
|
||||
It is important to remember that when you put a lambda callback onto a function in D++, that this lambda will execute at some point in the **future**. As with all things in the future and as 80s Sci Fi movies will tell you, when you reach the future things may well have changed!
|
||||
|
||||
\image html delorean-time-travel.gif
|
||||
|
||||
To explain this situation and how it causes issues i'd like you to imagine the age old magic trick, where a magician sets a fine table full of cutlery, pots, pans and wine. He indicates to the audience that this is authentic, then with a whip of his wrist, he whips the tablecloth away, leaving the cutlery and other tableware in place (if he is any good as a magician!)
|
||||
|
||||
Now imagine the following code scenario. We will describe this code scenario as the magic trick above, in the steps below:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
bot.on_message_create([&bot](const dpp::message_create_t & event) {
|
||||
int myvar = 0;
|
||||
bot.message_create(dpp::message(event.msg.channel_id, "foobar"), [&](const auto & cc) {
|
||||
myvar = 42;
|
||||
});
|
||||
});
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In this scenario, the outer event, `on_message_create` is your tablecloth. The lambda inside the `bot.message_create` is the tableware and cutlery. The following chain of events happens in this code:
|
||||
|
||||
* The magician executes his magic trick (D++ the `bot.on_message_create entering` the outer lambda)
|
||||
* Your code executes `bot.message_create()` inside this outer lambda
|
||||
* D++ inserts your request to send a message into its queue, in another thread. The inner lambda, where you might later set `myvar = 42` is safely copied into the queue for later calling.
|
||||
* The tablecloth is whipped away... in other words, `bot.on_message_create` ends, and all local variables including `myvar` become invalid
|
||||
* At a later time (usually 80ms through to anything up to 4 seconds depending on rate limits!) the message is sent, and your inner lambda which was saved at the earlier step is called.
|
||||
* Your inner lambda attempts to set `myvar` to 42... but `myvar` no longer exists, as the outer lambda has been destroyed....
|
||||
* The table wobbles... the cutlery shakes... and...
|
||||
* Best case scenario: you access invalid RAM no longer owned by your program by trying to write to `myvar`, and [your bot outright crashes horribly](https://www.youtube.com/watch?v=sm8qb2kP-fQ)!
|
||||
* Worse case scenario: you silently corrupt ram and end up spending days trying to track down a bug that subtly breaks your bot...
|
||||
|
||||
The situation i am trying to describe here is one of object and variable ownership. When you call a lambda, **always assume that every non global reference outside of that lambda will be invalid when the lambda is called**! For any non-global variable always take a **copy** of the variable (not reference, or pointer). Global variables or those declared directly in `main()` are safe to pass as references.
|
||||
|
||||
For example, if we were to fix the broken code above, we could rewrite it like this:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
bot.on_message_create([&bot](const dpp::message_create_t & event) {
|
||||
int myvar = 0;
|
||||
bot.message_create(dpp::message(event.msg.channel_id, "foobar"), [myvar](const auto & cc) {
|
||||
myvar = 42;
|
||||
});
|
||||
std::cout << "here\n";
|
||||
});
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note however that when you set myvar within the inner lambda, this does **not effect** the value of the var outside it. Lambdas should be considered self-contained silos, and as they execute in other threads should not be relied upon to set anything that exists **outside of that lambda**.
|
||||
|
||||
\warning Always avoid just using `[&]` in a lambda to access all in the scope above. It is unlikely that half of this scope will still even be valid by the time you get a look at it!
|
||||
|
||||
Similarly, and important to note, your program **will not wait for bot.message_create to send its message and call its lambda** before continuing on to print `here`. It will instantly insert the request into its queue and bail straight back out (see the steps above) and immediately print the text.
|
||||
|
||||
If you do want to get variables out of your lambda, create a class, or call a separate function, and pass what you need into that function from the lambda **by value** or alternatively, you can use `std::bind` to bind a lambda directly to an object's method instead (this is great for modular bots).
|
||||
|
||||
If you are stuck, as this is a complex subject please do feel free to ask on the [official support server](https://discord.gg/dpp)!
|
||||
@@ -1,81 +0,0 @@
|
||||
\page thread-model Thread Model
|
||||
|
||||
\dot
|
||||
digraph "Thread Model" {
|
||||
graph [ranksep=1];
|
||||
node [colorscheme="blues9",fontname="helvetica"];
|
||||
"Discord Events" -> "Your Program"
|
||||
|
||||
"Your Program" [style=filled, color=1, shape=rect]
|
||||
"Cluster" [style=filled, color=1, shape=rect]
|
||||
|
||||
subgraph cluster_4 {
|
||||
style=filled;
|
||||
color=lightgrey;
|
||||
node [style=filled,color=2]
|
||||
"Your Program"
|
||||
"Cluster"
|
||||
label = "User Code";
|
||||
}
|
||||
|
||||
subgraph cluster_0 {
|
||||
style=filled;
|
||||
color=lightgrey;
|
||||
node [style=filled,color=4]
|
||||
"Shard 1" [style=filled, color=4]
|
||||
"Shard 2"
|
||||
"Shard 3..."
|
||||
label = "Shards (Each is a thread, one per 2500 discord guilds)";
|
||||
}
|
||||
|
||||
subgraph cluster_1 {
|
||||
style=filled
|
||||
color=lightgrey;
|
||||
node [style=filled,color=4]
|
||||
"REST Requests"
|
||||
"Request In Queue 1"
|
||||
"Request In Queue 2"
|
||||
"Request In Queue 3..."
|
||||
"Request Out Queue"
|
||||
label = "REST Requests (Each in queue, and the out queue, are threads)"
|
||||
}
|
||||
|
||||
subgraph cluster_3 {
|
||||
style=filled
|
||||
color=lightgrey;
|
||||
node [style=filled,color=4]
|
||||
"Discord Events" [style=filled,color=4]
|
||||
"User Callback Functions"
|
||||
label = "Events and Callbacks"
|
||||
}
|
||||
|
||||
"Cluster" [shape=rect]
|
||||
"REST Requests" [shape=rect]
|
||||
"Request In Queue 1" [shape=rect]
|
||||
"Request In Queue 2" [shape=rect]
|
||||
"Request In Queue 3..." [shape=rect]
|
||||
"Shard 1" [shape=rect]
|
||||
"Shard 2" [shape=rect]
|
||||
"Shard 3..." [shape=rect]
|
||||
"Request Out Queue" [shape=rect]
|
||||
"Discord Events" [shape=rect]
|
||||
"User Callback Functions" [shape=rect]
|
||||
|
||||
"Cluster" -> "REST Requests"
|
||||
"Shard 1" -> "Discord Events"
|
||||
"Shard 2" -> "Discord Events"
|
||||
"Shard 3..." -> "Discord Events"
|
||||
"Your Program" -> "Cluster"
|
||||
"Cluster" -> "Shard 1"
|
||||
"Cluster" -> "Shard 2"
|
||||
"Cluster" -> "Shard 3..."
|
||||
"REST Requests" -> "Request In Queue 1"
|
||||
"REST Requests" -> "Request In Queue 2"
|
||||
"REST Requests" -> "Request In Queue 3..."
|
||||
"Request In Queue 1" -> "Request Out Queue"
|
||||
"Request In Queue 2" -> "Request Out Queue"
|
||||
"Request In Queue 3..." -> "Request Out Queue"
|
||||
"Request Out Queue" -> "User Callback Functions"
|
||||
"User Callback Functions" -> "Your Program"
|
||||
}
|
||||
\enddot
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user