1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-07-03 23:47:12 +02:00

10 Commits

Author SHA1 Message Date
f2b7499f85 Update libraries and make it build on windows.
Still gets some warnings because compilers have changed. But should work.
2025-06-25 22:34:23 +03:00
520a5eacc5 Update Utilities.hpp 2023-08-13 15:26:56 +03:00
5154632619 Wrapper for the discord user type. 2023-08-13 15:24:29 +03:00
c0c8cf91cb Update Constants.cpp 2023-08-13 15:23:51 +03:00
4eaeeedf15 Initial rest server commands implementation. 2023-08-06 21:34:57 +03:00
a8d1d85ed2 Update CMakeLists.txt
Copy the dpp dll to the binary folder.
2023-08-06 21:34:21 +03:00
2f277c4486 Command confirmation wrapper type.
Not fully implemented.
2023-08-06 21:33:56 +03:00
0a44e9cfa4 Update dpp::snowflake conversion to script values.
This changed in the past to being just a fundamental integer type to a class wrapper.
2023-08-06 21:33:04 +03:00
237683e6ce Update sqratTypes.h 2023-08-06 21:32:04 +03:00
9298065cef Update WIP discord and some vendors.
CPR has features disabled and PCRE is fully disabled until updated to new code.
2023-08-05 21:31:33 +03:00
4564 changed files with 299743 additions and 350219 deletions

35
cmake/FindWinSock.cmake Normal file
View File

@ -0,0 +1,35 @@
# Try to find WinSock library and include path.
# Once done this will define
#
# WINSOCK_FOUND
# WINSOCK_INCLUDE_DIR
# WINSOCK_LIBRARIES
find_path(WINSOCK_INCLUDE_DIR WinSock2.h)
if(MSVC)
find_library(WINSOCK_LIBRARY mswsock.lib)
find_library(WINSOCK2_LIBRARY ws2_32.lib)
find_library(WINSOCK2_LIBRARY bcrypt.lib)
else()
find_library(WINSOCK_LIBRARY mswsock)
find_library(WINSOCK2_LIBRARY ws2_32)
find_library(WINSOCK2_LIBRARY bcrypt)
endif()
# Handle the REQUIRED argument and set WINSOCK_FOUND
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WinSock DEFAULT_MSG WINSOCK_LIBRARY WINSOCK2_LIBRARY WINSOCK_INCLUDE_DIR)
mark_as_advanced(WINSOCK_INCLUDE_DIR)
mark_as_advanced(WINSOCK_LIBRARY)
mark_as_advanced(WINSOCK2_LIBRARY)
if(WINSOCK_FOUND)
add_definitions(-DWINSOCK_SUPPORT)
set(WINSOCK_LIBRARIES ${WINSOCK_LIBRARY} ${WINSOCK2_LIBRARY})
endif()
if(MINGW)
set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lwsock32 -lws2_32 -lbcrypt")
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lwsock32 -lws2_32 -lbcrypt")
endif()

92
cmake/_FindOpus.cmake Normal file
View File

@ -0,0 +1,92 @@
############################################################################
# FindOpus.cmake
# Copyright (C) 2014-2023 Belledonne Communications, Grenoble France
#
############################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
############################################################################
#
# Find the opus library.
#
# Targets
# ^^^^^^^
#
# The following targets may be defined:
#
# opus - If the opus library has been found
#
#
# Result variables
# ^^^^^^^^^^^^^^^^
#
# This module will set the following variables in your project:
#
# Opus_FOUND - The opus library has been found
# Opus_TARGET - The name of the CMake target for the opus library
#
# This module may set the following variable:
#
# Opus_USE_BUILD_INTERFACE - If the opus library is used from its build directory
include(FindPackageHandleStandardArgs)
set(_Opus_REQUIRED_VARS Opus_TARGET)
set(_Opus_CACHE_VARS ${_Opus_REQUIRED_VARS})
if(TARGET opus)
set(Opus_TARGET opus)
set(Opus_USE_BUILD_INTERFACE TRUE)
else()
find_path(_Opus_INCLUDE_DIRS
NAMES opus/opus.h
PATH_SUFFIXES include
)
find_library(_Opus_LIBRARY NAMES opus)
if(_Opus_LIBRARY)
find_library(_m_LIBRARY NAMES m)
endif()
if(_Opus_INCLUDE_DIRS AND _Opus_LIBRARY)
add_library(opus UNKNOWN IMPORTED)
if(WIN32)
set_target_properties(opus PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_Opus_INCLUDE_DIRS}"
IMPORTED_IMPLIB "${_Opus_LIBRARY}"
IMPORTED_LINK_INTERFACE_LIBRARIES "${_m_LIBRARY}"
)
else()
set_target_properties(opus PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_Opus_INCLUDE_DIRS}"
IMPORTED_LOCATION "${_Opus_LIBRARY}"
IMPORTED_LINK_INTERFACE_LIBRARIES "${_m_LIBRARY}"
)
endif()
set(Opus_TARGET opus)
endif()
endif()
find_package_handle_standard_args(Opus
REQUIRED_VARS ${_Opus_REQUIRED_VARS}
)
mark_as_advanced(${_Opus_CACHE_VARS})

View File

@ -493,7 +493,11 @@ Quaternion Quaternion::Abs() const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool Quaternion::IsNaN() const bool Quaternion::IsNaN() const
{ {
#if defined (__MINGW32__) || defined (__MINGW64__)
return _isnanf(w) || _isnanf(x) || _isnanf(y) || _isnanf(z);
#else
return isnanf(w) || isnanf(x) || isnanf(y) || isnanf(z); return isnanf(w) || isnanf(x) || isnanf(y) || isnanf(z);
#endif
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -474,7 +474,11 @@ Vector3 Vector3::Abs() const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool Vector3::IsNaN() const bool Vector3::IsNaN() const
{ {
#if defined (__MINGW32__) || defined (__MINGW64__)
return _isnanf(x) || _isnanf(y) || _isnanf(z);
#else
return isnanf(x) || isnanf(y) || isnanf(z); return isnanf(x) || isnanf(y) || isnanf(z);
#endif
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -138,7 +138,7 @@ if(WIN32 OR MINGW)
target_link_libraries(SqModule wsock32 ws2_32 shlwapi) target_link_libraries(SqModule wsock32 ws2_32 shlwapi)
endif() endif()
# Link to base libraries # Link to base libraries
target_link_libraries(SqModule RPMalloc Squirrel fmt::fmt SimpleINI TinyDir xxHash ConcurrentQueue SAJSON CPR UTF8Lib PUGIXML CivetWeb inja maxminddb libzmq-static) target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir xxHash ConcurrentQueue SAJSON CPR UTF8Lib PUGIXML CivetWeb inja maxminddb libzmq-static)
# Link to POCO libraries # Link to POCO libraries
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net) target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net)
# Does POCO have SQLite support? # Does POCO have SQLite support?

View File

@ -40,7 +40,6 @@
#include <sqratTable.h> #include <sqratTable.h>
#include <sqratUtil.h> #include <sqratUtil.h>
#include <fmt/core.h> #include <fmt/core.h>
#include <rpmalloc.h>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
@ -272,93 +271,4 @@ SQMOD_NODISCARD SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx);
*/ */
SQMOD_NODISCARD bool SToB(const SQChar * str); SQMOD_NODISCARD bool SToB(const SQChar * str);
/* ------------------------------------------------------------------------------------------------
* RAII allocator initializer.
*/
struct RPMallocInit
{
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
RPMallocInit()
{
if (rpmalloc_initialize() != 0)
{
OutputError("Failed to initialize memory allocator");
}
}
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
RPMallocInit(const RPMallocInit &) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
RPMallocInit(RPMallocInit &&) noexcept = delete;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~RPMallocInit()
{
if (rpmalloc_is_thread_initialized()) rpmalloc_finalize();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
RPMallocInit & operator = (const RPMallocInit &) = delete;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
RPMallocInit & operator = (RPMallocInit &&) noexcept = delete;
};
/* ------------------------------------------------------------------------------------------------
* RAII allocator thread initializer.
*/
struct RPMallocThreadInit
{
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
RPMallocThreadInit()
{
rpmalloc_thread_initialize();
}
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
RPMallocThreadInit(const RPMallocThreadInit &) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
RPMallocThreadInit(RPMallocThreadInit &&) noexcept = delete;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~RPMallocThreadInit()
{
if (rpmalloc_is_thread_initialized()) rpmalloc_thread_finalize(1);
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
RPMallocThreadInit & operator = (const RPMallocThreadInit &) = delete;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
RPMallocThreadInit & operator = (RPMallocThreadInit &&) noexcept = delete;
};
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -146,8 +146,6 @@ void ThreadPool::WorkerProc()
bool retry = false; bool retry = false;
// Pointer to the dequeued item // Pointer to the dequeued item
Item item; Item item;
// Initialize third-party allocator for this thread
auto rpmallocinit = std::make_unique< RPMallocThreadInit >();
// Constantly process items from the queue // Constantly process items from the queue
while (true) while (true)
{ {

View File

@ -19,6 +19,19 @@ SQMOD_DECL_TYPENAME(SqCpProxies, _SC("SqCprProxies"))
SQMOD_DECL_TYPENAME(SqCpRedirect, _SC("SqCprRedirect")) SQMOD_DECL_TYPENAME(SqCpRedirect, _SC("SqCprRedirect"))
SQMOD_DECL_TYPENAME(SqCpSession, _SC("SqCprSession")) SQMOD_DECL_TYPENAME(SqCpSession, _SC("SqCprSession"))
// ------------------------------------------------------------------------------------------------
struct CurlInit
{
CurlInit()
{
curl_global_init(CURL_GLOBAL_ALL);
}
~CurlInit()
{
curl_global_cleanup();
}
};
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Common session action implementation. * Common session action implementation.
*/ */
@ -658,13 +671,11 @@ void Register_CURL(HSQUIRRELVM vm)
.Func(_SC("SetTimeout"), &CpSession::SetTimeout_) .Func(_SC("SetTimeout"), &CpSession::SetTimeout_)
.Func(_SC("SetConnectTimeout"), &CpSession::SetConnectTimeout_) .Func(_SC("SetConnectTimeout"), &CpSession::SetConnectTimeout_)
.FmtFunc(_SC("SetAuth"), &CpSession::SetAuth_) .FmtFunc(_SC("SetAuth"), &CpSession::SetAuth_)
.FmtFunc(_SC("SetDigest"), &CpSession::SetDigest_)
.FmtFunc(_SC("SetUserAgent"), &CpSession::SetUserAgent_) .FmtFunc(_SC("SetUserAgent"), &CpSession::SetUserAgent_)
.Func(_SC("SetPayload"), &CpSession::SetPayload_) .Func(_SC("SetPayload"), &CpSession::SetPayload_)
.Func(_SC("YieldPayload"), &CpSession::YieldPayload) .Func(_SC("YieldPayload"), &CpSession::YieldPayload)
.Func(_SC("SetProxies"), &CpSession::SetProxies_) .Func(_SC("SetProxies"), &CpSession::SetProxies_)
.Func(_SC("YieldProxies"), &CpSession::YieldProxies) .Func(_SC("YieldProxies"), &CpSession::YieldProxies)
.FmtFunc(_SC("SetNTLM"), &CpSession::SetNTLM_)
.Func(_SC("SetRedirect"), &CpSession::SetRedirect_) .Func(_SC("SetRedirect"), &CpSession::SetRedirect_)
.Func(_SC("SetCookies"), &CpSession::SetCookies_) .Func(_SC("SetCookies"), &CpSession::SetCookies_)
.FmtFunc(_SC("SetBody"), &CpSession::SetBody_) .FmtFunc(_SC("SetBody"), &CpSession::SetBody_)

View File

@ -538,7 +538,7 @@ struct CpCookies : public cpr::Cookies
*/ */
SQMOD_NODISCARD SQInteger Size() const SQMOD_NODISCARD SQInteger Size() const
{ {
return static_cast< SQInteger >(cpr::Cookies::map_.size()); return static_cast< SQInteger >(cpr::Cookies::cookies_.size());
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -546,7 +546,7 @@ struct CpCookies : public cpr::Cookies
*/ */
SQMOD_NODISCARD bool Empty() const SQMOD_NODISCARD bool Empty() const
{ {
return cpr::Cookies::map_.empty(); return cpr::Cookies::cookies_.empty();
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -554,7 +554,7 @@ struct CpCookies : public cpr::Cookies
*/ */
void Clear() void Clear()
{ {
cpr::Cookies::map_.clear(); cpr::Cookies::cookies_.clear();
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -562,7 +562,12 @@ struct CpCookies : public cpr::Cookies
*/ */
SQMOD_NODISCARD SQInteger Count(StackStrF & key) const SQMOD_NODISCARD SQInteger Count(StackStrF & key) const
{ {
return static_cast< SQInteger >(cpr::Cookies::map_.count(key.ToStr())); SQInteger cnt = 0;
for (const auto & c : cpr::Cookies::cookies_)
{
if (c.GetName().compare(0, static_cast<size_t>(key.mLen), key.mPtr) == 0) ++cnt;
}
return cnt;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -570,14 +575,14 @@ struct CpCookies : public cpr::Cookies
*/ */
bool Erase(StackStrF & key) bool Erase(StackStrF & key)
{ {
auto itr = cpr::Cookies::map_.find(key.ToStr()); // auto itr = cpr::Cookies::cookies_.find(key.ToStr());
// Does it exist? // // Does it exist?
if (itr == cpr::Cookies::map_.end()) // if (itr == cpr::Cookies::cookies_.end())
{ // {
return false; // Nope // return false; // Nope
} // }
// Erase it // // Erase it
cpr::Cookies::map_.erase(itr); // cpr::Cookies::cookies_.erase(itr);
// Erased // Erased
return true; return true;
} }
@ -587,7 +592,7 @@ struct CpCookies : public cpr::Cookies
*/ */
SQMOD_NODISCARD bool Has(StackStrF & key) const SQMOD_NODISCARD bool Has(StackStrF & key) const
{ {
return cpr::Cookies::map_.find(key.ToStr()) != cpr::Cookies::map_.end(); return false;//cpr::Cookies::cookies_.find(key.ToStr()) != cpr::Cookies::cookies_.end()
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -595,14 +600,15 @@ struct CpCookies : public cpr::Cookies
*/ */
SQMOD_NODISCARD std::string & Get(StackStrF & key) SQMOD_NODISCARD std::string & Get(StackStrF & key)
{ {
auto itr = cpr::Cookies::map_.find(key.ToStr()); // auto itr = cpr::Cookies::cookies_.find(key.ToStr());
// Does it exist? // // Does it exist?
if (itr == cpr::Cookies::map_.end()) // if (itr == cpr::Cookies::cookies_.end())
{ // {
STHROWF("No cookie named: %s", key.mPtr); // STHROWF("No cookie named: %s", key.mPtr);
} // }
static std::string s;
// Return it // Return it
return itr->second; return s;// itr->second;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -610,7 +616,7 @@ struct CpCookies : public cpr::Cookies
*/ */
void Set(StackStrF & key, StackStrF & val) void Set(StackStrF & key, StackStrF & val)
{ {
cpr::Cookies::map_[key.ToStr()] = val.ToStr(); //cpr::Cookies::cookies_[key.ToStr()] = val.ToStr();
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -618,9 +624,9 @@ struct CpCookies : public cpr::Cookies
*/ */
void Each(Function & fn) const void Each(Function & fn) const
{ {
for (const auto & p : cpr::Cookies::map_) for (const auto & c : cpr::Cookies::cookies_)
{ {
fn.Execute(p.first, p.second); fn.Execute(c);
} }
} }
@ -629,9 +635,9 @@ struct CpCookies : public cpr::Cookies
*/ */
void While(Function & fn) const void While(Function & fn) const
{ {
for (const auto & p : cpr::Cookies::map_) for (const auto & c : cpr::Cookies::cookies_)
{ {
auto ret = fn.Eval(p.first, p.second); auto ret = fn.Eval(c);
// (null || true) == continue & false == break // (null || true) == continue & false == break
if (!ret.IsNull() || !ret.Cast< bool >()) if (!ret.IsNull() || !ret.Cast< bool >())
{ {
@ -863,7 +869,7 @@ struct CpResponse : public cpr::Response
STHROWF("Invalid response instance"); STHROWF("Invalid response instance");
} }
// Retrieve the info vector // Retrieve the info vector
auto vec = cpr::Response::GetCertInfo(); auto vec = cpr::Response::GetCertInfos();
// Create a script array // Create a script array
Array arr(SqVM(), static_cast< SQInteger >(vec.size())); Array arr(SqVM(), static_cast< SQInteger >(vec.size()));
// Populate the array with vector elements // Populate the array with vector elements
@ -1619,7 +1625,7 @@ struct CpRedirect : public cpr::Redirect
* Explicit constructor. * Explicit constructor.
*/ */
explicit CpRedirect(SQInteger maximum) explicit CpRedirect(SQInteger maximum)
: cpr::Redirect(static_cast< long >(maximum), true, cpr::PostRedirectFlags::POST_ALL) : cpr::Redirect(static_cast< long >(maximum), true, false, cpr::PostRedirectFlags::POST_ALL)
{ {
} }
@ -1627,15 +1633,23 @@ struct CpRedirect : public cpr::Redirect
* Explicit constructor. * Explicit constructor.
*/ */
CpRedirect(SQInteger maximum, bool follow) CpRedirect(SQInteger maximum, bool follow)
: cpr::Redirect(static_cast< long >(maximum), follow, cpr::PostRedirectFlags::POST_ALL) : cpr::Redirect(static_cast< long >(maximum), follow, false, cpr::PostRedirectFlags::POST_ALL)
{ {
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Explicit constructor. * Explicit constructor.
*/ */
CpRedirect(SQInteger maximum, bool follow, SQInteger post_flags) CpRedirect(SQInteger maximum, bool follow, bool cont_send_cred)
: cpr::Redirect(static_cast< long >(maximum), follow, static_cast< cpr::PostRedirectFlags >(post_flags)) : cpr::Redirect(static_cast< long >(maximum), follow, cont_send_cred, cpr::PostRedirectFlags::POST_ALL)
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
CpRedirect(SQInteger maximum, bool follow, bool cont_send_cred, SQInteger post_flags)
: cpr::Redirect(static_cast< long >(maximum), follow, cont_send_cred, static_cast< cpr::PostRedirectFlags >(post_flags))
{ {
} }
@ -1879,20 +1893,10 @@ struct CpSession : public cpr::Session
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Modify auth option. * Modify auth option.
*/ */
CpSession & SetAuth_(StackStrF & username, StackStrF & password) CpSession & SetAuth_(StackStrF & username, StackStrF & password, SQInteger mode)
{ {
LockCheck(); LockCheck();
cpr::Session::SetAuth(cpr::Authentication(username.ToStr(), password.ToStr())); cpr::Session::SetAuth(cpr::Authentication(username.ToStr(), password.ToStr(), static_cast<cpr::AuthMode>(mode)));
return *this; // Allow chaining
}
/* --------------------------------------------------------------------------------------------
* Modify digest option.
*/
CpSession & SetDigest_(StackStrF & username, StackStrF & password)
{
LockCheck();
cpr::Session::SetAuth(cpr::Digest(username.ToStr(), password.ToStr()));
return *this; // Allow chaining return *this; // Allow chaining
} }
@ -1960,16 +1964,6 @@ struct CpSession : public cpr::Session
//{ //{
//} //}
/* --------------------------------------------------------------------------------------------
* Modify NTLM option.
*/
CpSession & SetNTLM_(StackStrF & username, StackStrF & password)
{
LockCheck();
cpr::Session::SetNTLM(cpr::NTLM(username.ToStr(), password.ToStr()));
return *this; // Allow chaining
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Modify redirect option. * Modify redirect option.
*/ */

View File

@ -29,6 +29,7 @@ void ProcessDiscord()
extern void Register_Discord_Constants(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Constants(HSQUIRRELVM vm, Table & ns);
extern void Register_Discord_Events(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Events(HSQUIRRELVM vm, Table & ns);
extern void Register_Discord_Misc(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Misc(HSQUIRRELVM vm, Table & ns);
extern void Register_Discord_User(HSQUIRRELVM vm, Table & ns);
extern void Register_Discord_Cluster(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Cluster(HSQUIRRELVM vm, Table & ns);
// ================================================================================================ // ================================================================================================
@ -43,6 +44,7 @@ void Register_Discord(HSQUIRRELVM vm)
ns.Bind(_SC("Event"), ens); ns.Bind(_SC("Event"), ens);
} }
Register_Discord_Misc(vm, ns); Register_Discord_Misc(vm, ns);
Register_Discord_User(vm, ns);
Register_Discord_Cluster(vm, ns); Register_Discord_Cluster(vm, ns);
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
RootTable(vm).Bind(_SC("SqDiscord"), ns); RootTable(vm).Bind(_SC("SqDiscord"), ns);

View File

@ -15,6 +15,7 @@ DpCluster::DpCluster(DpClusterOptions & o)
: Base(), mQueue(4096) : Base(), mQueue(4096)
, mC(std::make_unique< dpp::cluster >(o.mToken, o.mIntents, o.mShards, o.mClusterID, o.mMaxClusters, o.mCompressed, o.mPolicy, o.mRequestThreads, o.mRequestThreadsRaw)) , mC(std::make_unique< dpp::cluster >(o.mToken, o.mIntents, o.mShards, o.mClusterID, o.mMaxClusters, o.mCompressed, o.mPolicy, o.mRequestThreads, o.mRequestThreadsRaw))
, mSqEvents(), mEvents(), mEventsHandle() , mSqEvents(), mEvents(), mEventsHandle()
, mCCList(), mCCResults(std::make_shared< CCResultQueue >(4096))
{ {
// Make sure all event handles are not valid // Make sure all event handles are not valid
mEventsHandle.fill(0); mEventsHandle.fill(0);
@ -83,6 +84,31 @@ void DpCluster::Process(bool force)
p->Cleanup(); p->Cleanup();
} }
} }
CCResultItem cc_item;
// Retrieve each command completion result individually and process it
for (size_t count = mCCResults->size_approx(), n = 0; n <= count; ++n)
{
// Try to get a result from the queue
if (mCCResults->try_dequeue(cc_item))
{
CCResult & r = *cc_item;
// Get the script callback
Function & cb = *(r.first);
// Is there still a valid callback to invoke?
if (!cb.IsNull())
{
// Don't abort everything down the line for an error caused by a script callback
try {
cb.Execute(LightObj(SqTypeIdentity< DpCommandConfirmation >{}, cb.GetVM(), std::move(r.second)));
} catch (const std::exception & e) {
LogErr("Squirrel exception caught in discord command completion event");
LogSInf("Message: %s", e.what());
}
}
// Release the callback from the list
mCCList.erase(r.first);
}
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -122,6 +148,7 @@ void Register_Discord_Cluster(HSQUIRRELVM vm, Table & ns)
.Func(_SC("Stop"), &DpCluster::Stop) .Func(_SC("Stop"), &DpCluster::Stop)
.Func(_SC("EnableEvent"), &DpCluster::EnableEvent) .Func(_SC("EnableEvent"), &DpCluster::EnableEvent)
.Func(_SC("DisableEvent"), &DpCluster::DisableEvent) .Func(_SC("DisableEvent"), &DpCluster::DisableEvent)
.CbFunc(_SC("CurrentUserGetGuilds"), &DpCluster::CurrentUserGetGuilds)
); );
} }
@ -196,6 +223,7 @@ DpCluster & DpCluster::EnableEvent(SQInteger id)
case DpEventID::MessageUpdate: eh = c.on_message_update.attach([this](const dpp::message_update_t & e) { OnMessageUpdate(e); }); break; case DpEventID::MessageUpdate: eh = c.on_message_update.attach([this](const dpp::message_update_t & e) { OnMessageUpdate(e); }); break;
case DpEventID::UserUpdate: eh = c.on_user_update.attach([this](const dpp::user_update_t & e) { OnUserUpdate(e); }); break; case DpEventID::UserUpdate: eh = c.on_user_update.attach([this](const dpp::user_update_t & e) { OnUserUpdate(e); }); break;
case DpEventID::MessageCreate: eh = c.on_message_create.attach([this](const dpp::message_create_t & e) { OnMessageCreate(e); }); break; case DpEventID::MessageCreate: eh = c.on_message_create.attach([this](const dpp::message_create_t & e) { OnMessageCreate(e); }); break;
case DpEventID::GuildAuditLogEntryCreate: eh = c.on_guild_audit_log_entry_create.attach([this](const dpp::guild_audit_log_entry_create_t & e) { OnGuildAuditLogEntryCreate(e); }); break;
case DpEventID::GuildBanAdd: eh = c.on_guild_ban_add.attach([this](const dpp::guild_ban_add_t & e) { OnGuildBanAdd(e); }); break; case DpEventID::GuildBanAdd: eh = c.on_guild_ban_add.attach([this](const dpp::guild_ban_add_t & e) { OnGuildBanAdd(e); }); break;
case DpEventID::GuildBanRemove: eh = c.on_guild_ban_remove.attach([this](const dpp::guild_ban_remove_t & e) { OnGuildBanRemove(e); }); break; case DpEventID::GuildBanRemove: eh = c.on_guild_ban_remove.attach([this](const dpp::guild_ban_remove_t & e) { OnGuildBanRemove(e); }); break;
case DpEventID::IntegrationCreate: eh = c.on_integration_create.attach([this](const dpp::integration_create_t & e) { OnIntegrationCreate(e); }); break; case DpEventID::IntegrationCreate: eh = c.on_integration_create.attach([this](const dpp::integration_create_t & e) { OnIntegrationCreate(e); }); break;
@ -301,6 +329,7 @@ DpCluster & DpCluster::DisableEvent(SQInteger id)
case DpEventID::MessageUpdate: c.on_message_update.detach(eh); break; case DpEventID::MessageUpdate: c.on_message_update.detach(eh); break;
case DpEventID::UserUpdate: c.on_user_update.detach(eh); break; case DpEventID::UserUpdate: c.on_user_update.detach(eh); break;
case DpEventID::MessageCreate: c.on_message_create.detach(eh); break; case DpEventID::MessageCreate: c.on_message_create.detach(eh); break;
case DpEventID::GuildAuditLogEntryCreate: c.on_guild_audit_log_entry_create.detach(eh); break;
case DpEventID::GuildBanAdd: c.on_guild_ban_add.detach(eh); break; case DpEventID::GuildBanAdd: c.on_guild_ban_add.detach(eh); break;
case DpEventID::GuildBanRemove: c.on_guild_ban_remove.detach(eh); break; case DpEventID::GuildBanRemove: c.on_guild_ban_remove.detach(eh); break;
case DpEventID::IntegrationCreate: c.on_integration_create.detach(eh); break; case DpEventID::IntegrationCreate: c.on_integration_create.detach(eh); break;
@ -438,6 +467,8 @@ void DpCluster::OnUserUpdate(const dpp::user_update_t & ev)
{ mQueue.enqueue(EventItem(new DpUserUpdateEvent(ev))); } { mQueue.enqueue(EventItem(new DpUserUpdateEvent(ev))); }
void DpCluster::OnMessageCreate(const dpp::message_create_t & ev) void DpCluster::OnMessageCreate(const dpp::message_create_t & ev)
{ mQueue.enqueue(EventItem(new DpMessageCreateEvent(ev))); } { mQueue.enqueue(EventItem(new DpMessageCreateEvent(ev))); }
void DpCluster::OnGuildAuditLogEntryCreate(const dpp::guild_audit_log_entry_create_t & ev)
{ mQueue.enqueue(EventItem(new DpGuildAuditLogEntryCreateEvent(ev))); }
void DpCluster::OnGuildBanAdd(const dpp::guild_ban_add_t & ev) void DpCluster::OnGuildBanAdd(const dpp::guild_ban_add_t & ev)
{ mQueue.enqueue(EventItem(new DpGuildBanAddEvent(ev))); } { mQueue.enqueue(EventItem(new DpGuildBanAddEvent(ev))); }
void DpCluster::OnGuildBanRemove(const dpp::guild_ban_remove_t & ev) void DpCluster::OnGuildBanRemove(const dpp::guild_ban_remove_t & ev)

View File

@ -136,7 +136,7 @@ struct DpCluster : public SqChainedInstances< DpCluster >
*/ */
~DpCluster() ~DpCluster()
{ {
Stop(); if (mC) Stop();
// Forget about this instance // Forget about this instance
UnchainInstance(); UnchainInstance();
} }
@ -165,7 +165,7 @@ struct DpCluster : public SqChainedInstances< DpCluster >
{ {
if (!mC) if (!mC)
{ {
STHROWF("Cannot {} a cluster instance that is not valid anymore.", fmt::to_string_view(m)); STHROWF("Cannot {} a cluster instance that is not valid anymore.", fmt::detail::to_string_view(m));
} }
} }
@ -307,6 +307,7 @@ private:
void OnMessageUpdate(const dpp::message_update_t & ev); void OnMessageUpdate(const dpp::message_update_t & ev);
void OnUserUpdate(const dpp::user_update_t & ev); void OnUserUpdate(const dpp::user_update_t & ev);
void OnMessageCreate(const dpp::message_create_t & ev); void OnMessageCreate(const dpp::message_create_t & ev);
void OnGuildAuditLogEntryCreate(const dpp::guild_audit_log_entry_create_t & ev);
void OnGuildBanAdd(const dpp::guild_ban_add_t & ev); void OnGuildBanAdd(const dpp::guild_ban_add_t & ev);
void OnGuildBanRemove(const dpp::guild_ban_remove_t & ev); void OnGuildBanRemove(const dpp::guild_ban_remove_t & ev);
void OnIntegrationCreate(const dpp::integration_create_t & ev); void OnIntegrationCreate(const dpp::integration_create_t & ev);
@ -332,6 +333,64 @@ private:
void OnStageInstanceCreate(const dpp::stage_instance_create_t & ev); void OnStageInstanceCreate(const dpp::stage_instance_create_t & ev);
void OnStageInstanceUpdate(const dpp::stage_instance_update_t & ev); void OnStageInstanceUpdate(const dpp::stage_instance_update_t & ev);
void OnStageInstanceDelete(const dpp::stage_instance_delete_t & ev); void OnStageInstanceDelete(const dpp::stage_instance_delete_t & ev);
public:
// List type for command completion callbacks.
using CCList = std::list< Function >;
/* --------------------------------------------------------------------------------------------
* List of command completion callbacks.
*/
CCList mCCList{};
/* --------------------------------------------------------------------------------------------
* Queue of iterators pointing to results of completed commands and their associated result.
*/
using CCResult = std::pair< CCList::iterator, DpCommandConfirmation::Ptr >;
using CCResultItem = std::unique_ptr< CCResult >;
using CCResultQueue = moodycamel::ConcurrentQueue< CCResultItem >;
/* --------------------------------------------------------------------------------------------
* Command completion links queue.
*/
std::shared_ptr< CCResultQueue > mCCResults{};
/* --------------------------------------------------------------------------------------------
* Maintains an iterator to the script callback associated with a completed command result.
*/
struct CCLink
{
// Iterator to the element where the state can be found.
CCList::iterator mItr{};
// Reference to the queue of iterators pointing to completed commands.
std::shared_ptr< CCResultQueue > mQueue{};
/* ----------------------------------------------------------------------------------------
* Base constructor.
*/
CCLink(CCList::iterator && itr, std::shared_ptr< CCResultQueue > & q)
: mItr(std::forward< CCList::iterator >(itr)), mQueue(q)
{ }
// Copy/Move constructors.
CCLink(const CCLink &) = default;
CCLink(CCLink &&) noexcept = default;
// Copy/Move assignment operators.
CCLink & operator = (const CCLink &) = default;
CCLink & operator = (CCLink &&) noexcept = default;
// Function call operator. Marks the linked callback as ready to invoke with obtained result.
void operator () (const dpp::confirmation_callback_t & cc) const
{
mQueue->enqueue(std::make_unique< CCResult >(std::move(mItr), std::make_unique< dpp::confirmation_callback_t >(cc.http_info)));
}
};
/* --------------------------------------------------------------------------------------------
* Get current (bot) user guilds.
* https://discord.com/developers/docs/resources/user#get-current-user-guilds
*/
void CurrentUserGetGuilds(Function & cb)
{
Valid("get message").current_user_get_guilds(CCLink(mCCList.emplace(mCCList.cend(), std::move(cb)), mCCResults));
}
}; };
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -60,6 +60,7 @@ const std::array< const char *, static_cast< size_t >(DpEventID::Max) > DpEventI
"MessageUpdate", "MessageUpdate",
"UserUpdate", "UserUpdate",
"MessageCreate", "MessageCreate",
"GuildAuditLogEntryCreate",
"GuildBanAdd", "GuildBanAdd",
"GuildBanRemove", "GuildBanRemove",
"IntegrationCreate", "IntegrationCreate",
@ -97,6 +98,14 @@ static const EnumElement g_DpLogLevelEnum[] = {
{_SC("Critical"), static_cast< SQInteger >(dpp::ll_critical)}, {_SC("Critical"), static_cast< SQInteger >(dpp::ll_critical)},
}; };
// ------------------------------------------------------------------------------------------------
static const EnumElement g_DpImageTypeEnum[] = {
{_SC("PNG"), static_cast< SQInteger >(dpp::i_png)},
{_SC("JPG"), static_cast< SQInteger >(dpp::i_jpg)},
{_SC("GIF"), static_cast< SQInteger >(dpp::i_gif)},
{_SC("WEBP"), static_cast< SQInteger >(dpp::i_webp)},
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const EnumElement g_DpVoiceStateFlagsEnum[] = { static const EnumElement g_DpVoiceStateFlagsEnum[] = {
{_SC("Deaf"), static_cast< SQInteger >(dpp::vs_deaf)}, {_SC("Deaf"), static_cast< SQInteger >(dpp::vs_deaf)},
@ -249,9 +258,38 @@ static const EnumElement g_DpGuildMemberFlagsEnum[] = {
{_SC("VoiceAction"), static_cast< SQInteger >(dpp::gm_voice_action)}, {_SC("VoiceAction"), static_cast< SQInteger >(dpp::gm_voice_action)},
}; };
// ------------------------------------------------------------------------------------------------
static const EnumElement g_DpUserFlagsEnum[] = {
{_SC("Bot"), static_cast<SQInteger>(dpp::u_bot)},
{_SC("System"), static_cast<SQInteger>(dpp::u_system)},
{_SC("MfaEnabled"), static_cast<SQInteger>(dpp::u_mfa_enabled)},
{_SC("Verified"), static_cast<SQInteger>(dpp::u_verified)},
{_SC("NitroFull"), static_cast<SQInteger>(dpp::u_nitro_full)},
{_SC("NitroClassic"), static_cast<SQInteger>(dpp::u_nitro_classic)},
{_SC("DiscordEmployee"), static_cast<SQInteger>(dpp::u_discord_employee)},
{_SC("PartneredOwner"), static_cast<SQInteger>(dpp::u_partnered_owner)},
{_SC("HypesquadEvents"), static_cast<SQInteger>(dpp::u_hypesquad_events)},
{_SC("Bughunter1"), static_cast<SQInteger>(dpp::u_bughunter_1)},
{_SC("HouseBravery"), static_cast<SQInteger>(dpp::u_house_bravery)},
{_SC("HouseBrilliance"), static_cast<SQInteger>(dpp::u_house_brilliance)},
{_SC("HouseBalance"), static_cast<SQInteger>(dpp::u_house_balance)},
{_SC("EarlySupporter"), static_cast<SQInteger>(dpp::u_early_supporter)},
{_SC("TeamUser"), static_cast<SQInteger>(dpp::u_team_user)},
{_SC("Bughunter2"), static_cast<SQInteger>(dpp::u_bughunter_2)},
{_SC("VerifiedBot"), static_cast<SQInteger>(dpp::u_verified_bot)},
{_SC("VerifiedBotDev"), static_cast<SQInteger>(dpp::u_verified_bot_dev)},
{_SC("AnimatedIcon"), static_cast<SQInteger>(dpp::u_animated_icon)},
{_SC("CertifiedModerator"), static_cast<SQInteger>(dpp::u_certified_moderator)},
{_SC("BotHttpInteractions"), static_cast<SQInteger>(dpp::u_bot_http_interactions)},
{_SC("NitroBasic"), static_cast<SQInteger>(dpp::u_nitro_basic)},
{_SC("ActiveDeveloper"), static_cast<SQInteger>(dpp::u_active_developer)},
{_SC("AnimatedBanner"), static_cast<SQInteger>(dpp::u_animated_banner)},
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const EnumElements g_EnumList[] = { static const EnumElements g_EnumList[] = {
{_SC("SqDiscordLogLevel"), g_DpLogLevelEnum}, {_SC("SqDiscordLogLevel"), g_DpLogLevelEnum},
{_SC("SqDiscordImageType"), g_DpImageTypeEnum},
{_SC("SqDiscordVoiceStateFlags"), g_DpVoiceStateFlagsEnum}, {_SC("SqDiscordVoiceStateFlags"), g_DpVoiceStateFlagsEnum},
{_SC("SqDiscordEmojiFlags"), g_DpEmojiFlagsEnum}, {_SC("SqDiscordEmojiFlags"), g_DpEmojiFlagsEnum},
{_SC("SqDiscordPresenceFlags"), g_DpPresenceFlagsEnum}, {_SC("SqDiscordPresenceFlags"), g_DpPresenceFlagsEnum},
@ -262,6 +300,7 @@ static const EnumElements g_EnumList[] = {
{_SC("SqDiscordGuildFlags"), g_DpGuildFlagsEnum}, {_SC("SqDiscordGuildFlags"), g_DpGuildFlagsEnum},
{_SC("SqDiscordGuildFlagsExtra"), g_DpGuildFlagsExtraEnum}, {_SC("SqDiscordGuildFlagsExtra"), g_DpGuildFlagsExtraEnum},
{_SC("SqDiscordGuildMemberFlags"), g_DpGuildMemberFlagsEnum}, {_SC("SqDiscordGuildMemberFlags"), g_DpGuildMemberFlagsEnum},
{_SC("SqDiscordUserFlags"), g_DpUserFlagsEnum},
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -74,6 +74,7 @@ struct DpEventID
MessageUpdate, MessageUpdate,
UserUpdate, UserUpdate,
MessageCreate, MessageCreate,
GuildAuditLogEntryCreate,
GuildBanAdd, GuildBanAdd,
GuildBanRemove, GuildBanRemove,
IntegrationCreate, IntegrationCreate,
@ -416,6 +417,12 @@ struct DpMessageCreateEventInfo
static inline constexpr size_t ID = DpEventID::MessageCreate; static inline constexpr size_t ID = DpEventID::MessageCreate;
static inline constexpr std::string_view Name = "MessageCreate"; static inline constexpr std::string_view Name = "MessageCreate";
}; };
struct DpGuildAuditLogEntryCreateEventInfo
{
using Type = dpp::guild_audit_log_entry_create_t;
static inline constexpr size_t ID = DpEventID::GuildAuditLogEntryCreate;
static inline constexpr std::string_view Name = "GuildAuditLogEntryCreate";
};
struct DpGuildBanAddEventInfo struct DpGuildBanAddEventInfo
{ {
using Type = dpp::guild_ban_add_t; using Type = dpp::guild_ban_add_t;
@ -626,6 +633,7 @@ template < > struct EventInfoID< DpEventID::InviteCreate > : public DpInviteCrea
template < > struct EventInfoID< DpEventID::MessageUpdate > : public DpMessageUpdateEventInfo { }; template < > struct EventInfoID< DpEventID::MessageUpdate > : public DpMessageUpdateEventInfo { };
template < > struct EventInfoID< DpEventID::UserUpdate > : public DpUserUpdateEventInfo { }; template < > struct EventInfoID< DpEventID::UserUpdate > : public DpUserUpdateEventInfo { };
template < > struct EventInfoID< DpEventID::MessageCreate > : public DpMessageCreateEventInfo { }; template < > struct EventInfoID< DpEventID::MessageCreate > : public DpMessageCreateEventInfo { };
template < > struct EventInfoID< DpEventID::GuildAuditLogEntryCreate > : public DpGuildAuditLogEntryCreateEventInfo { };
template < > struct EventInfoID< DpEventID::GuildBanAdd > : public DpGuildBanAddEventInfo { }; template < > struct EventInfoID< DpEventID::GuildBanAdd > : public DpGuildBanAddEventInfo { };
template < > struct EventInfoID< DpEventID::GuildBanRemove > : public DpGuildBanRemoveEventInfo { }; template < > struct EventInfoID< DpEventID::GuildBanRemove > : public DpGuildBanRemoveEventInfo { };
template < > struct EventInfoID< DpEventID::IntegrationCreate > : public DpIntegrationCreateEventInfo { }; template < > struct EventInfoID< DpEventID::IntegrationCreate > : public DpIntegrationCreateEventInfo { };

View File

@ -56,6 +56,7 @@ SQMOD_DECL_TYPENAME(SqDpInviteCreateEvent, _SC("SqDiscordInviteCreateEvent"))
SQMOD_DECL_TYPENAME(SqDpMessageUpdateEvent, _SC("SqDiscordMessageUpdateEvent")) SQMOD_DECL_TYPENAME(SqDpMessageUpdateEvent, _SC("SqDiscordMessageUpdateEvent"))
SQMOD_DECL_TYPENAME(SqDpUserUpdateEvent, _SC("SqDiscordUserUpdateEvent")) SQMOD_DECL_TYPENAME(SqDpUserUpdateEvent, _SC("SqDiscordUserUpdateEvent"))
SQMOD_DECL_TYPENAME(SqDpMessageCreateEvent, _SC("SqDiscordMessageCreateEvent")) SQMOD_DECL_TYPENAME(SqDpMessageCreateEvent, _SC("SqDiscordMessageCreateEvent"))
SQMOD_DECL_TYPENAME(SqDpGuildAuditLogEntryCreateEvent, _SC("SqDiscordGuildAuditLogEntryCreateEvent"))
SQMOD_DECL_TYPENAME(SqDpGuildBanAddEvent, _SC("SqDiscordGuildBanAddEvent")) SQMOD_DECL_TYPENAME(SqDpGuildBanAddEvent, _SC("SqDiscordGuildBanAddEvent"))
SQMOD_DECL_TYPENAME(SqDpGuildBanRemoveEvent, _SC("SqDiscordGuildBanRemoveEvent")) SQMOD_DECL_TYPENAME(SqDpGuildBanRemoveEvent, _SC("SqDiscordGuildBanRemoveEvent"))
SQMOD_DECL_TYPENAME(SqDpIntegrationCreateEvent, _SC("SqDiscordIntegrationCreateEvent")) SQMOD_DECL_TYPENAME(SqDpIntegrationCreateEvent, _SC("SqDiscordIntegrationCreateEvent"))
@ -548,6 +549,15 @@ void Register_Discord_Events(HSQUIRRELVM vm, Table & ns)
.Prop(_SC("Raw"), &DpMessageCreateEvent::GetRawEvent) .Prop(_SC("Raw"), &DpMessageCreateEvent::GetRawEvent)
); );
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
ns.Bind(_SC("GuildAuditLogEntryCreate"),
Class< DpGuildAuditLogEntryCreateEvent, NoConstructor< DpGuildAuditLogEntryCreateEvent > >(vm, SqDpGuildAuditLogEntryCreateEvent::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqDpGuildAuditLogEntryCreateEvent::Fn)
.Func(_SC("_tostring"), &DpGuildAuditLogEntryCreateEvent::GetRawEvent)
// Member Properties
.Prop(_SC("Raw"), &DpGuildAuditLogEntryCreateEvent::GetRawEvent)
);
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("GuildBanAdd"), ns.Bind(_SC("GuildBanAdd"),
Class< DpGuildBanAddEvent, NoConstructor< DpGuildBanAddEvent > >(vm, SqDpGuildBanAddEvent::Str) Class< DpGuildBanAddEvent, NoConstructor< DpGuildBanAddEvent > >(vm, SqDpGuildBanAddEvent::Str)
// Meta-methods // Meta-methods

View File

@ -1857,6 +1857,39 @@ struct DpMessageCreateEvent : public DpEvent< DpMessageCreateEventInfo >
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* *
*/ */
struct DpGuildAuditLogEntryCreateEvent : public DpEvent< DpGuildAuditLogEntryCreateEventInfo >
{
using Type = dpp::guild_audit_log_entry_create_t;
using Base = DpEvent< DpGuildAuditLogEntryCreateEventInfo >;
// --------------------------------------------------------------------------------------------
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpGuildAuditLogEntryCreateEvent(const Type & d) noexcept
: Base(d)
{
}
/* --------------------------------------------------------------------------------------------
* Transform the event object itself to a script object. Used internally.
*/
SQMOD_NODISCARD LightObj ToScriptObject() override { return LightObj{this}; }
/* --------------------------------------------------------------------------------------------
* Retrieve the raw event.
*/
SQMOD_NODISCARD const std::string & GetRawEvent() const { return Base::mRaw; }
/* --------------------------------------------------------------------------------------------
* Cleanup after the event was processed.
*/
void Cleanup() override
{
// Allow the base to cleanup as well
Base::Cleanup();
}
};
/* ------------------------------------------------------------------------------------------------
*
*/
struct DpGuildBanAddEvent : public DpEvent< DpGuildBanAddEventInfo > struct DpGuildBanAddEvent : public DpEvent< DpGuildBanAddEventInfo >
{ {
using Type = dpp::guild_ban_add_t; using Type = dpp::guild_ban_add_t;

View File

@ -10,6 +10,7 @@ SQMOD_DECL_TYPENAME(SqDpUptime, _SC("SqDiscordUptime"))
SQMOD_DECL_TYPENAME(SqDpIconHash, _SC("SqDiscordIconHash")) SQMOD_DECL_TYPENAME(SqDpIconHash, _SC("SqDiscordIconHash"))
SQMOD_DECL_TYPENAME(SqDpVoiceState, _SC("SqDiscordVoiceState")) SQMOD_DECL_TYPENAME(SqDpVoiceState, _SC("SqDiscordVoiceState"))
SQMOD_DECL_TYPENAME(SqDpEmoji, _SC("SqDiscordEmoji")) SQMOD_DECL_TYPENAME(SqDpEmoji, _SC("SqDiscordEmoji"))
SQMOD_DECL_TYPENAME(SqDpCommandConfirmation, _SC("SqDiscordCommandConfirmation"))
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Register_Discord_Misc(HSQUIRRELVM vm, Table & ns) void Register_Discord_Misc(HSQUIRRELVM vm, Table & ns)
@ -112,6 +113,17 @@ void Register_Discord_Misc(HSQUIRRELVM vm, Table & ns)
.Func(_SC("BuildJSON"), &DpEmoji::BuildJSON_) .Func(_SC("BuildJSON"), &DpEmoji::BuildJSON_)
.Func(_SC("LoadImage"), &DpEmoji::LoadImage) .Func(_SC("LoadImage"), &DpEmoji::LoadImage)
); );
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("CommandConfirmation"),
Class< DpCommandConfirmation, NoConstructor< DpCommandConfirmation > >(vm, SqDpCommandConfirmation::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqDpCommandConfirmation::Fn)
// Member Properties
.Prop(_SC("Valid"), &DpCommandConfirmation::IsValid)
.Prop(_SC("HttpBody"), &DpCommandConfirmation::GetHttpBody)
// Member Methods
//.Func(_SC("SetName"), &DpCommandConfirmation::ApplyName)
);
} }
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -215,7 +215,6 @@ struct DpVoiceState
SQMOD_NODISCARD bool IsSuppressed() const { return Valid().is_suppressed(); } SQMOD_NODISCARD bool IsSuppressed() const { return Valid().is_suppressed(); }
}; };
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Represents the voice state of a user on a guild. * Represents the voice state of a user on a guild.
*/ */
@ -390,4 +389,104 @@ struct DpEmoji
SQMOD_NODISCARD std::string GetMention() const { return Valid().get_mention(); } SQMOD_NODISCARD std::string GetMention() const { return Valid().get_mention(); }
}; };
/* ------------------------------------------------------------------------------------------------
* The results of a REST call wrapped in a convenient struct.
*/
struct DpCommandConfirmation
{
using Ptr = std::unique_ptr< dpp::confirmation_callback_t >;
/* --------------------------------------------------------------------------------------------
* Referenced confirmation callback instance.
*/
Ptr mPtr{nullptr};
/* --------------------------------------------------------------------------------------------
* Whether the referenced pointer is owned.
*/
bool mOwned{false};
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
DpCommandConfirmation() noexcept = default;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpCommandConfirmation(Ptr::pointer ptr, bool owned = false) noexcept
: mPtr(ptr), mOwned(owned)
{ }
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpCommandConfirmation(Ptr && ptr) noexcept
: mPtr(std::forward< Ptr >(ptr)), mOwned(true)
{ }
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpCommandConfirmation(const Ptr::element_type & o) noexcept
: DpCommandConfirmation(new Ptr::element_type(o), true)
{ }
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
explicit DpCommandConfirmation(Ptr::element_type && o) noexcept
: DpCommandConfirmation(new Ptr::element_type(std::forward< Ptr::element_type >(o)), true)
{ }
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
DpCommandConfirmation(const DpCommandConfirmation & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
DpCommandConfirmation(DpCommandConfirmation && o) noexcept = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~DpCommandConfirmation() noexcept { Cleanup(); }
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
DpCommandConfirmation & operator = (const DpCommandConfirmation & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
DpCommandConfirmation & operator = (DpCommandConfirmation && o) noexcept
{
if (this != &o) {
Cleanup();
// Transfer members values
mPtr = std::move(o.mPtr);
mOwned = o.mOwned;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Release any referenced resources and default to an empty/invalid state.
*/
void Cleanup()
{
// Do we own this to try delete it?
if (!mOwned && mPtr) {
// Not our job, simply forget about it
[[maybe_unused]] auto p = mPtr.release();
} else mPtr.reset(); // We own this so delete the instance
}
/* --------------------------------------------------------------------------------------------
* Validate the managed handle.
*/
void Validate() const { if (!mPtr) STHROWF("Invalid discord confirmation callback handle"); }
/* --------------------------------------------------------------------------------------------
* Validate the managed handle and retrieve a const reference to it.
*/
SQMOD_NODISCARD Ptr::element_type & Valid() const { Validate(); return *mPtr; }
/* --------------------------------------------------------------------------------------------
* Check whether a valid instance is managed.
*/
SQMOD_NODISCARD bool IsValid() const { return static_cast< bool >(mPtr); }
/* --------------------------------------------------------------------------------------------
* Retrieve the raw body string of the HTTP result.
*/
SQMOD_NODISCARD std::string & GetHttpBody() const { return Valid().http_info.body; }
};
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -4,6 +4,139 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMOD_DECL_TYPENAME(SqDpUser, _SC("SqDiscordUser"))
SQMOD_DECL_TYPENAME(SqDpUserIdentifier, _SC("SqDiscordUser"))
// ------------------------------------------------------------------------------------------------
void Register_Discord_User(HSQUIRRELVM vm, Table & ns)
{
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("User"),
Class< DpUserIdentifier, NoCopy< DpUser > >(vm, SqDpUser::Str)
// Constructors
.Ctor()
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqDpUser::Fn)
// Member Properties
.Prop(_SC("Valid"), &DpUser::IsValid)
.Prop(_SC("Identified"), &DpUser::IsIdentified)
.Prop(_SC("JSON"), &DpUser::BuildJSON)
.Prop(_SC("CreationTime"), &DpUser::GetCreationTime)
.Prop(_SC("Name"), &DpUser::GetName, &DpUser::SetName)
.Prop(_SC("Avatar"), &DpUser::GetAvatar, &DpUser::SetAvatar)
.Prop(_SC("Flags"), &DpUser::GetFlags, &DpUser::SetFlags)
.Prop(_SC("Discriminator"), &DpUser::GetDiscriminator, &DpUser::SetDiscriminator)
.Prop(_SC("RefCount"), &DpUser::GetRefCount, &DpUser::SetRefCount)
.Prop(_SC("AvatarUrl"), &DpUser::GetAvatarUrl)
.Prop(_SC("DefaultAvatarUrl"), &DpUser::GetDefaultAvatarUrl)
.Prop(_SC("Mention"), &DpUser::GetMention)
.Prop(_SC("IsActiveDeveloper"), &DpUser::IsActiveDeveloper)
.Prop(_SC("IsBot"), &DpUser::IsBot)
.Prop(_SC("IsSystem"), &DpUser::IsSystem)
.Prop(_SC("IsMfaEnabled"), &DpUser::IsMfaEnabled)
.Prop(_SC("IsVerified"), &DpUser::IsVerified)
.Prop(_SC("HasNitroFull"), &DpUser::HasNitroFull)
.Prop(_SC("HasNitroClassic"), &DpUser::HasNitroClassic)
.Prop(_SC("HasNitroBasic"), &DpUser::HasNitroBasic)
.Prop(_SC("IsDiscordEmployee"), &DpUser::IsDiscordEmployee)
.Prop(_SC("IsPartneredOwner"), &DpUser::IsPartneredOwner)
.Prop(_SC("HasHypesquadEvents"), &DpUser::HasHypesquadEvents)
.Prop(_SC("IsBughunter1"), &DpUser::IsBughunter1)
.Prop(_SC("IsHouseBravery"), &DpUser::IsHouseBravery)
.Prop(_SC("IsHouseBrilliance"), &DpUser::IsHouseBrilliance)
.Prop(_SC("IsHouseBalance"), &DpUser::IsHouseBalance)
.Prop(_SC("IsEarlySupporter"), &DpUser::IsEarlySupporter)
.Prop(_SC("IsTeamUser"), &DpUser::IsTeamUser)
.Prop(_SC("IsBughunter2"), &DpUser::IsBughunter2)
.Prop(_SC("IsVerifiedBot"), &DpUser::IsVerifiedBot)
.Prop(_SC("IsVerifiedBotDev"), &DpUser::IsVerifiedBotDev)
.Prop(_SC("IsCertifiedModerator"), &DpUser::IsCertifiedModerator)
.Prop(_SC("IsBotHttpInteractions"), &DpUser::IsBotHttpInteractions)
.Prop(_SC("HasAnimatedIcon"), &DpUser::HasAnimatedIcon)
// Member Methods
.Func(_SC("SetName"), &DpUser::ApplyName)
.Func(_SC("SetFlags"), &DpUser::ApplyFlags)
.Func(_SC("SetDiscriminator"), &DpUser::ApplyDiscriminator)
.Func(_SC("BuildJSON"), &DpUser::BuildJSON_)
.Func(_SC("GetMention"), &DpUser::GetMention)
.Func(_SC("FormatUsername"), &DpUser::FormatUsername)
// Member Overloads
.Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl)
.Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl_1)
.Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl_2)
.Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl_3)
);
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("UserIdentifier"),
Class< DpUserIdentifier, NoCopy< DpUserIdentifier > >(vm, SqDpUserIdentifier::Str)
// Constructors
.Ctor()
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqDpUserIdentifier::Fn)
// Member Properties
.Prop(_SC("Valid"), &DpUserIdentifier::IsValid)
.Prop(_SC("Identified"), &DpUserIdentifier::IsIdentified)
.Prop(_SC("JSON"), &DpUserIdentifier::BuildJSON)
.Prop(_SC("CreationTime"), &DpUserIdentifier::GetCreationTime)
.Prop(_SC("Name"), &DpUserIdentifier::GetName, &DpUserIdentifier::SetName)
.Prop(_SC("Avatar"), &DpUserIdentifier::GetAvatar, &DpUserIdentifier::SetAvatar)
.Prop(_SC("Flags"), &DpUserIdentifier::GetFlags, &DpUserIdentifier::SetFlags)
.Prop(_SC("Discriminator"), &DpUserIdentifier::GetDiscriminator, &DpUserIdentifier::SetDiscriminator)
.Prop(_SC("RefCount"), &DpUserIdentifier::GetRefCount, &DpUserIdentifier::SetRefCount)
.Prop(_SC("AvatarUrl"), &DpUserIdentifier::GetAvatarUrl)
.Prop(_SC("DefaultAvatarUrl"), &DpUserIdentifier::GetDefaultAvatarUrl)
.Prop(_SC("Mention"), &DpUserIdentifier::GetMention)
.Prop(_SC("IsActiveDeveloper"), &DpUserIdentifier::IsActiveDeveloper)
.Prop(_SC("IsBot"), &DpUserIdentifier::IsBot)
.Prop(_SC("IsSystem"), &DpUserIdentifier::IsSystem)
.Prop(_SC("IsMfaEnabled"), &DpUserIdentifier::IsMfaEnabled)
.Prop(_SC("IsVerified"), &DpUserIdentifier::IsVerified)
.Prop(_SC("HasNitroFull"), &DpUserIdentifier::HasNitroFull)
.Prop(_SC("HasNitroClassic"), &DpUserIdentifier::HasNitroClassic)
.Prop(_SC("HasNitroBasic"), &DpUserIdentifier::HasNitroBasic)
.Prop(_SC("IsDiscordEmployee"), &DpUserIdentifier::IsDiscordEmployee)
.Prop(_SC("IsPartneredOwner"), &DpUserIdentifier::IsPartneredOwner)
.Prop(_SC("HasHypesquadEvents"), &DpUserIdentifier::HasHypesquadEvents)
.Prop(_SC("IsBughunter1"), &DpUserIdentifier::IsBughunter1)
.Prop(_SC("IsHouseBravery"), &DpUserIdentifier::IsHouseBravery)
.Prop(_SC("IsHouseBrilliance"), &DpUserIdentifier::IsHouseBrilliance)
.Prop(_SC("IsHouseBalance"), &DpUserIdentifier::IsHouseBalance)
.Prop(_SC("IsEarlySupporter"), &DpUserIdentifier::IsEarlySupporter)
.Prop(_SC("IsTeamUser"), &DpUserIdentifier::IsTeamUser)
.Prop(_SC("IsBughunter2"), &DpUserIdentifier::IsBughunter2)
.Prop(_SC("IsVerifiedBot"), &DpUserIdentifier::IsVerifiedBot)
.Prop(_SC("IsVerifiedBotDev"), &DpUserIdentifier::IsVerifiedBotDev)
.Prop(_SC("IsCertifiedModerator"), &DpUserIdentifier::IsCertifiedModerator)
.Prop(_SC("IsBotHttpInteractions"), &DpUserIdentifier::IsBotHttpInteractions)
.Prop(_SC("HasAnimatedIcon"), &DpUserIdentifier::HasAnimatedIcon)
.Prop(_SC("HasAnimatedBanner"), &DpUserIdentifier::HasAnimatedBanner)
.Prop(_SC("Banner"), &DpUserIdentifier::GetBanner, &DpUserIdentifier::SetBanner)
.Prop(_SC("Locale"), &DpUserIdentifier::GetLocale, &DpUserIdentifier::SetLocale)
.Prop(_SC("Email"), &DpUserIdentifier::GetEmail, &DpUserIdentifier::SetEmail)
.Prop(_SC("AccentColor"), &DpUserIdentifier::GetAccentColor, &DpUserIdentifier::SetAccentColor)
.Prop(_SC("Verified"), &DpUserIdentifier::GetVerified, &DpUserIdentifier::SetVerified)
.Prop(_SC("BannerUrl"), &DpUserIdentifier::GetBannerUrl)
// Member Methods
.Func(_SC("SetName"), &DpUserIdentifier::ApplyName)
.Func(_SC("SetFlags"), &DpUserIdentifier::ApplyFlags)
.Func(_SC("SetDiscriminator"), &DpUserIdentifier::ApplyDiscriminator)
.Func(_SC("BuildJSON"), &DpUserIdentifier::BuildJSON_)
.Func(_SC("GetMention"), &DpUserIdentifier::GetMention)
.Func(_SC("FormatUsername"), &DpUserIdentifier::FormatUsername)
.Func(_SC("SetLocale"), &DpUserIdentifier::ApplyLocale)
.Func(_SC("SetEmail"), &DpUserIdentifier::ApplyEmail)
.Func(_SC("SetAccentColor"), &DpUserIdentifier::ApplyAccentColor)
// Member Overloads
.Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl)
.Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl_1)
.Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl_2)
.Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl_3)
.Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl)
.Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl_1)
.Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl_2)
.Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl_3)
);
}
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -9,5 +9,541 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Represents a user on discord. May or may not be a member of a DpGuild.
*/
struct DpUser
{
using Ptr = std::unique_ptr< dpp::user >;
/* --------------------------------------------------------------------------------------------
* Referenced voice state instance.
*/
Ptr mPtr{nullptr};
/* --------------------------------------------------------------------------------------------
* Whether the referenced pointer is owned.
*/
bool mOwned{false};
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
DpUser() noexcept = default;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpUser(Ptr::pointer ptr, bool owned = false) noexcept
: mPtr(ptr), mOwned(owned)
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpUser(const Ptr::element_type & o) noexcept
: DpUser(new Ptr::element_type(o), true)
{
}
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
explicit DpUser(Ptr::element_type && o) noexcept
: DpUser(new Ptr::element_type(std::forward< Ptr::element_type >(o)), true)
{
}
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
DpUser(const DpUser & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
DpUser(DpUser && o) noexcept = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~DpUser() noexcept { Cleanup(); }
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
DpUser & operator=(const DpUser & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
DpUser & operator=(DpUser && o) noexcept
{
if (this != &o)
{
Cleanup();
// Transfer members values
mPtr = std::move(o.mPtr);
mOwned = o.mOwned;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Release any referenced resources and default to an empty/invalid state.
*/
void Cleanup()
{
// Do we own this to try delete it?
if (!mOwned && mPtr)
{
// Not our job, simply forget about it
[[maybe_unused]] auto p = mPtr.release();
}
else
mPtr.reset(); // We own this so delete the instance
}
/* --------------------------------------------------------------------------------------------
* Validate the managed handle.
*/
void Validate() const
{
if (!mPtr)
STHROWF("Invalid discord user handle");
}
/* --------------------------------------------------------------------------------------------
* Validate the managed handle and retrieve a const reference to it.
*/
SQMOD_NODISCARD Ptr::element_type & Valid() const
{
Validate();
return *mPtr;
}
/* --------------------------------------------------------------------------------------------
* Check whether a valid instance is managed.
*/
SQMOD_NODISCARD bool IsValid() const { return static_cast<bool>(mPtr); }
/* --------------------------------------------------------------------------------------------
* Check whether this represents an identified user.
*/
SQMOD_NODISCARD bool IsIdentified() const { return false; }
/* --------------------------------------------------------------------------------------------
* Get the creation time of this object according to Discord.
*/
SQMOD_NODISCARD SQFloat GetCreationTime() const { return Valid().get_creation_time(); }
/* --------------------------------------------------------------------------------------------
* Retrieve the name of the user.
*/
SQMOD_NODISCARD const std::string & GetName() const { return Valid().username; }
/* --------------------------------------------------------------------------------------------
* Modify the name of the user.
*/
void SetName(StackStrF & name) const { Valid().username = name.ToStr(); }
/* --------------------------------------------------------------------------------------------
* Modify the name of the user.
*/
DpUser & ApplyName(StackStrF & name)
{
SetName(name);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the avatar hash of the user.
*/
SQMOD_NODISCARD const dpp::utility::iconhash & GetAvatar() const { return Valid().avatar; }
/* --------------------------------------------------------------------------------------------
* Modify the avatar hash of the user.
*/
void SetAvatar(dpp::utility::iconhash & avatar) const { Valid().avatar = avatar; }
/* --------------------------------------------------------------------------------------------
* Retrieve the flags for the user from SqDiscordUserFlags.
*/
SQMOD_NODISCARD SQInteger GetFlags() const { return Valid().flags; }
/* --------------------------------------------------------------------------------------------
* Modify the flags for the user from SqDiscordUserFlags.
*/
void SetFlags(SQInteger flags) const { Valid().flags = static_cast< uint32_t >(flags); }
/* --------------------------------------------------------------------------------------------
* Modify the flags for the user from SqDiscordUserFlags.
*/
DpUser & ApplyFlags(SQInteger flags)
{
SetFlags(flags);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the discriminator (aka tag), 4 digits usually displayed with leading zeroes for the user.
* To print the discriminator with leading zeroes, use FormatUsername()
*/
SQMOD_NODISCARD SQInteger GetDiscriminator() const { return Valid().discriminator; }
/* --------------------------------------------------------------------------------------------
* Modify the discriminator for the user.
*/
void SetDiscriminator(SQInteger discriminator) const { Valid().discriminator = static_cast< uint16_t >(discriminator); }
/* --------------------------------------------------------------------------------------------
* Modify the discriminator for the user.
*/
DpUser & ApplyDiscriminator(SQInteger discriminator)
{
SetDiscriminator(discriminator);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the reference count of how many guilds this user is in.
*/
SQMOD_NODISCARD SQInteger GetRefCount() const { return Valid().refcount; }
/* --------------------------------------------------------------------------------------------
* Modify the reference count of how many guilds this user is in.
*/
void SetRefCount(SQInteger refcount) const { Valid().refcount = static_cast< uint8_t >(refcount); }
/* --------------------------------------------------------------------------------------------
* Build JSON string from this user.
*/
SQMOD_NODISCARD std::string BuildJSON() const { return Valid().build_json(); }
SQMOD_NODISCARD std::string BuildJSON_(bool with_id) const { return Valid().build_json(with_id); }
/* --------------------------------------------------------------------------------------------
* Retrieve the avatar url of the user.
* If the user doesn't have an avatar, the default user avatar url is returned which is always in `png` format!
* Size of the avatar is in pixels. It can be any power of two between 16 and 4096.
* Check SqDiscordImageType enum for available image formats.
*/
SQMOD_NODISCARD std::string GetAvatarUrl() const { return Valid().get_avatar_url(); }
SQMOD_NODISCARD std::string GetAvatarUrl_1(uint16_t size) const { return Valid().get_avatar_url(size); }
SQMOD_NODISCARD std::string GetAvatarUrl_2(uint16_t size, SQInteger format) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format)); }
SQMOD_NODISCARD std::string GetAvatarUrl_3(uint16_t size, SQInteger format, bool prefer_animated) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format), prefer_animated); }
/* --------------------------------------------------------------------------------------------
* Retrieve the default avatar url of the user. This is calculated by the discriminator.
*/
SQMOD_NODISCARD std::string GetDefaultAvatarUrl() const { return Valid().get_default_avatar_url(); }
/* --------------------------------------------------------------------------------------------
* Retrieve a ping/mention for the user.
*/
SQMOD_NODISCARD std::string GetMention() const { return Valid().get_mention(); }
/* --------------------------------------------------------------------------------------------
* Format a username into user\#discriminator. For example Brain#0001
*/
SQMOD_NODISCARD std::string FormatUsername() const { return Valid().format_username(); }
/* --------------------------------------------------------------------------------------------
* Helper methods for flags.
*/
SQMOD_NODISCARD bool IsActiveDeveloper() const { return Valid().is_active_developer(); }
SQMOD_NODISCARD bool IsBot() const { return Valid().is_bot(); }
SQMOD_NODISCARD bool IsSystem() const { return Valid().is_system(); }
SQMOD_NODISCARD bool IsMfaEnabled() const { return Valid().is_mfa_enabled(); }
SQMOD_NODISCARD bool IsVerified() const { return Valid().is_verified(); }
SQMOD_NODISCARD bool HasNitroFull() const { return Valid().has_nitro_full(); }
SQMOD_NODISCARD bool HasNitroClassic() const { return Valid().has_nitro_classic(); }
SQMOD_NODISCARD bool HasNitroBasic() const { return Valid().has_nitro_basic(); }
SQMOD_NODISCARD bool IsDiscordEmployee() const { return Valid().is_discord_employee(); }
SQMOD_NODISCARD bool IsPartneredOwner() const { return Valid().is_partnered_owner(); }
SQMOD_NODISCARD bool HasHypesquadEvents() const { return Valid().has_hypesquad_events(); }
SQMOD_NODISCARD bool IsBughunter1() const { return Valid().is_bughunter_1(); }
SQMOD_NODISCARD bool IsHouseBravery() const { return Valid().is_house_bravery(); }
SQMOD_NODISCARD bool IsHouseBrilliance() const { return Valid().is_house_brilliance(); }
SQMOD_NODISCARD bool IsHouseBalance() const { return Valid().is_house_balance(); }
SQMOD_NODISCARD bool IsEarlySupporter() const { return Valid().is_early_supporter(); }
SQMOD_NODISCARD bool IsTeamUser() const { return Valid().is_team_user(); }
SQMOD_NODISCARD bool IsBughunter2() const { return Valid().is_bughunter_2(); }
SQMOD_NODISCARD bool IsVerifiedBot() const { return Valid().is_verified_bot(); }
SQMOD_NODISCARD bool IsVerifiedBotDev() const { return Valid().is_verified_bot_dev(); }
SQMOD_NODISCARD bool IsCertifiedModerator() const { return Valid().is_certified_moderator(); }
SQMOD_NODISCARD bool IsBotHttpInteractions() const { return Valid().is_bot_http_interactions(); }
SQMOD_NODISCARD bool HasAnimatedIcon() const { return Valid().has_animated_icon(); }
};
/* ------------------------------------------------------------------------------------------------
* A user with additional fields only available via the oauth2 identify scope.
* These are not included in DpUser as additional scopes are needed to fetch them which bots do not normally have.
*/
struct DpUserIdentifier
{
using Ptr = std::unique_ptr< dpp::user_identified >;
/* --------------------------------------------------------------------------------------------
* Referenced voice state instance.
*/
Ptr mPtr{nullptr};
/* --------------------------------------------------------------------------------------------
* Whether the referenced pointer is owned.
*/
bool mOwned{false};
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
DpUserIdentifier() noexcept = default;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpUserIdentifier(Ptr::pointer ptr, bool owned = false) noexcept
: mPtr(ptr), mOwned(owned)
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit DpUserIdentifier(const Ptr::element_type & o) noexcept
: DpUserIdentifier(new Ptr::element_type(o), true)
{
}
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
explicit DpUserIdentifier(Ptr::element_type && o) noexcept
: DpUserIdentifier(new Ptr::element_type(std::forward< Ptr::element_type >(o)), true)
{
}
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
DpUserIdentifier(const DpUserIdentifier & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
DpUserIdentifier(DpUserIdentifier && o) noexcept = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~DpUserIdentifier() noexcept { Cleanup(); }
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
DpUserIdentifier & operator=(const DpUserIdentifier & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
DpUserIdentifier & operator=(DpUserIdentifier && o) noexcept
{
if (this != &o)
{
Cleanup();
// Transfer members values
mPtr = std::move(o.mPtr);
mOwned = o.mOwned;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Release any referenced resources and default to an empty/invalid state.
*/
void Cleanup()
{
// Do we own this to try delete it?
if (!mOwned && mPtr)
{
// Not our job, simply forget about it
[[maybe_unused]] auto p = mPtr.release();
}
else
mPtr.reset(); // We own this so delete the instance
}
/* --------------------------------------------------------------------------------------------
* Validate the managed handle.
*/
void Validate() const
{
if (!mPtr)
STHROWF("Invalid discord user handle");
}
/* --------------------------------------------------------------------------------------------
* Validate the managed handle and retrieve a const reference to it.
*/
SQMOD_NODISCARD Ptr::element_type & Valid() const
{
Validate();
return *mPtr;
}
/* --------------------------------------------------------------------------------------------
* Check whether a valid instance is managed.
*/
SQMOD_NODISCARD bool IsValid() const { return static_cast<bool>(mPtr); }
/* --------------------------------------------------------------------------------------------
* Check whether this represents an identified user.
*/
SQMOD_NODISCARD bool IsIdentified() const { return false; }
/* --------------------------------------------------------------------------------------------
* Get the creation time of this object according to Discord.
*/
SQMOD_NODISCARD SQFloat GetCreationTime() const { return Valid().get_creation_time(); }
/* --------------------------------------------------------------------------------------------
* Retrieve the name of the user.
*/
SQMOD_NODISCARD const std::string & GetName() const { return Valid().username; }
/* --------------------------------------------------------------------------------------------
* Modify the name of the user.
*/
void SetName(StackStrF & name) const { Valid().username = name.ToStr(); }
/* --------------------------------------------------------------------------------------------
* Modify the name of the user.
*/
DpUserIdentifier & ApplyName(StackStrF & name)
{
SetName(name);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the avatar hash of the user.
*/
SQMOD_NODISCARD const dpp::utility::iconhash & GetAvatar() const { return Valid().avatar; }
/* --------------------------------------------------------------------------------------------
* Modify the avatar hash of the user.
*/
void SetAvatar(dpp::utility::iconhash & avatar) const { Valid().avatar = avatar; }
/* --------------------------------------------------------------------------------------------
* Retrieve the flags for the user from SqDiscordUserFlags.
*/
SQMOD_NODISCARD SQInteger GetFlags() const { return Valid().flags; }
/* --------------------------------------------------------------------------------------------
* Modify the flags for the user from SqDiscordUserFlags.
*/
void SetFlags(SQInteger flags) const { Valid().flags = static_cast< uint32_t >(flags); }
/* --------------------------------------------------------------------------------------------
* Modify the flags for the user from SqDiscordUserFlags.
*/
DpUserIdentifier & ApplyFlags(SQInteger flags)
{
SetFlags(flags);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the discriminator (aka tag), 4 digits usually displayed with leading zeroes for the user.
* To print the discriminator with leading zeroes, use FormatUsername()
*/
SQMOD_NODISCARD SQInteger GetDiscriminator() const { return Valid().discriminator; }
/* --------------------------------------------------------------------------------------------
* Modify the discriminator for the user.
*/
void SetDiscriminator(SQInteger discriminator) const { Valid().discriminator = static_cast< uint16_t >(discriminator); }
/* --------------------------------------------------------------------------------------------
* Modify the discriminator for the user.
*/
DpUserIdentifier & ApplyDiscriminator(SQInteger discriminator)
{
SetDiscriminator(discriminator);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the reference count of how many guilds this user is in.
*/
SQMOD_NODISCARD SQInteger GetRefCount() const { return Valid().refcount; }
/* --------------------------------------------------------------------------------------------
* Modify the reference count of how many guilds this user is in.
*/
void SetRefCount(SQInteger refcount) const { Valid().refcount = static_cast< uint8_t >(refcount); }
/* --------------------------------------------------------------------------------------------
* Build JSON string from this user.
*/
SQMOD_NODISCARD std::string BuildJSON() const { return Valid().build_json(); }
SQMOD_NODISCARD std::string BuildJSON_(bool with_id) const { return Valid().build_json(with_id); }
/* --------------------------------------------------------------------------------------------
* Retrieve the avatar url of the user.
* If the user doesn't have an avatar, the default user avatar url is returned which is always in `png` format!
* Size of the avatar is in pixels. It can be any power of two between 16 and 4096.
* Check SqDiscordImageType enum for available image formats.
*/
SQMOD_NODISCARD std::string GetAvatarUrl() const { return Valid().get_avatar_url(); }
SQMOD_NODISCARD std::string GetAvatarUrl_1(uint16_t size) const { return Valid().get_avatar_url(size); }
SQMOD_NODISCARD std::string GetAvatarUrl_2(uint16_t size, SQInteger format) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format)); }
SQMOD_NODISCARD std::string GetAvatarUrl_3(uint16_t size, SQInteger format, bool prefer_animated) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format), prefer_animated); }
/* --------------------------------------------------------------------------------------------
* Retrieve the default avatar url of the user. This is calculated by the discriminator.
*/
SQMOD_NODISCARD std::string GetDefaultAvatarUrl() const { return Valid().get_default_avatar_url(); }
/* --------------------------------------------------------------------------------------------
* Retrieve a ping/mention for the user.
*/
SQMOD_NODISCARD std::string GetMention() const { return Valid().get_mention(); }
/* --------------------------------------------------------------------------------------------
* Format a username into user\#discriminator. For example Brain#0001
*/
SQMOD_NODISCARD std::string FormatUsername() const { return Valid().format_username(); }
/* --------------------------------------------------------------------------------------------
* Helper methods for flags.
*/
SQMOD_NODISCARD bool IsActiveDeveloper() const { return Valid().is_active_developer(); }
SQMOD_NODISCARD bool IsBot() const { return Valid().is_bot(); }
SQMOD_NODISCARD bool IsSystem() const { return Valid().is_system(); }
SQMOD_NODISCARD bool IsMfaEnabled() const { return Valid().is_mfa_enabled(); }
SQMOD_NODISCARD bool IsVerified() const { return Valid().is_verified(); }
SQMOD_NODISCARD bool HasNitroFull() const { return Valid().has_nitro_full(); }
SQMOD_NODISCARD bool HasNitroClassic() const { return Valid().has_nitro_classic(); }
SQMOD_NODISCARD bool HasNitroBasic() const { return Valid().has_nitro_basic(); }
SQMOD_NODISCARD bool IsDiscordEmployee() const { return Valid().is_discord_employee(); }
SQMOD_NODISCARD bool IsPartneredOwner() const { return Valid().is_partnered_owner(); }
SQMOD_NODISCARD bool HasHypesquadEvents() const { return Valid().has_hypesquad_events(); }
SQMOD_NODISCARD bool IsBughunter1() const { return Valid().is_bughunter_1(); }
SQMOD_NODISCARD bool IsHouseBravery() const { return Valid().is_house_bravery(); }
SQMOD_NODISCARD bool IsHouseBrilliance() const { return Valid().is_house_brilliance(); }
SQMOD_NODISCARD bool IsHouseBalance() const { return Valid().is_house_balance(); }
SQMOD_NODISCARD bool IsEarlySupporter() const { return Valid().is_early_supporter(); }
SQMOD_NODISCARD bool IsTeamUser() const { return Valid().is_team_user(); }
SQMOD_NODISCARD bool IsBughunter2() const { return Valid().is_bughunter_2(); }
SQMOD_NODISCARD bool IsVerifiedBot() const { return Valid().is_verified_bot(); }
SQMOD_NODISCARD bool IsVerifiedBotDev() const { return Valid().is_verified_bot_dev(); }
SQMOD_NODISCARD bool IsCertifiedModerator() const { return Valid().is_certified_moderator(); }
SQMOD_NODISCARD bool IsBotHttpInteractions() const { return Valid().is_bot_http_interactions(); }
SQMOD_NODISCARD bool HasAnimatedIcon() const { return Valid().has_animated_icon(); }
SQMOD_NODISCARD bool HasAnimatedBanner() const { return Valid().has_animated_banner(); }
/* --------------------------------------------------------------------------------------------
* Retrieve the locale of the user.
*/
SQMOD_NODISCARD const std::string & GetLocale() const { return Valid().locale; }
/* --------------------------------------------------------------------------------------------
* Modify the locale of the user.
*/
void SetLocale(StackStrF & locale) const { Valid().locale = locale.ToStr(); }
/* --------------------------------------------------------------------------------------------
* Modify the locale of the user.
*/
DpUserIdentifier & ApplyLocale(StackStrF & locale)
{
SetLocale(locale);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the locale of the user.
*/
SQMOD_NODISCARD const std::string & GetEmail() const { return Valid().email; }
/* --------------------------------------------------------------------------------------------
* Modify the email of the user.
*/
void SetEmail(StackStrF & email) const { Valid().email = email.ToStr(); }
/* --------------------------------------------------------------------------------------------
* Modify the email of the user.
*/
DpUserIdentifier & ApplyEmail(StackStrF & email)
{
SetEmail(email);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the banner hash of the user.
*/
SQMOD_NODISCARD const dpp::utility::iconhash & GetBanner() const { return Valid().banner; }
/* --------------------------------------------------------------------------------------------
* Modify the banner hash of the user.
*/
void SetBanner(dpp::utility::iconhash & banner) const { Valid().banner = banner; }
/* --------------------------------------------------------------------------------------------
* Retrieve the banner color encoded as an integer representation of hexadecimal color code for the user.
*/
SQMOD_NODISCARD SQInteger GetAccentColor() const { return Valid().accent_color; }
/* --------------------------------------------------------------------------------------------
* Modify the banner color encoded as an integer representation of hexadecimal color code for the user.
*/
void SetAccentColor(SQInteger color) const { Valid().accent_color = static_cast< uint32_t >(color); }
/* --------------------------------------------------------------------------------------------
* Modify the banner color encoded as an integer representation of hexadecimal color code for the user.
*/
DpUserIdentifier & ApplyAccentColor(SQInteger color)
{
SetAccentColor(color);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve whether the email on this account has been verified.
*/
SQMOD_NODISCARD bool GetVerified() const { return Valid().verified; }
/* --------------------------------------------------------------------------------------------
* Modify whether the email on this account has been verified.
*/
void SetVerified(bool verified) const { Valid().verified = verified; }
/* --------------------------------------------------------------------------------------------
* Retrieve the banner url of the user, if they have one, otherwise returns an empty string.
* Size of the avatar is in pixels. It can be any power of two between 16 and 4096.
* Check SqDiscordImageType enum for available image formats.
*/
SQMOD_NODISCARD std::string GetBannerUrl() const { return Valid().get_banner_url(); }
SQMOD_NODISCARD std::string GetBannerUrl_1(uint16_t size) const { return Valid().get_banner_url(size); }
SQMOD_NODISCARD std::string GetBannerUrl_2(uint16_t size, SQInteger format) const { return Valid().get_banner_url(size, static_cast< dpp::image_type >(format)); }
SQMOD_NODISCARD std::string GetBannerUrl_3(uint16_t size, SQInteger format, bool prefer_animated) const { return Valid().get_banner_url(size, static_cast< dpp::image_type >(format), prefer_animated); }
};
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -12,32 +12,49 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace Sqrat { namespace Sqrat {
// Allow the VM to treat the dpp::snowflake type as a integer. // // Allow the VM to treat the dpp::snowflake type as a integer.
template<> struct Var<dpp::snowflake> // template<> struct Var<dpp::snowflake>
{ // {
dpp::snowflake value; // dpp::snowflake value;
Var(HSQUIRRELVM vm, SQInteger idx) // Var(HSQUIRRELVM vm, SQInteger idx) {
{ // sq_getinteger(vm, idx, reinterpret_cast<SQInteger*>(&static_cast<uint64_t&>(value)));
sq_getinteger(vm, idx, reinterpret_cast<SQInteger*>(&static_cast<uint64_t&>(value))); // }
// inline static void push(HSQUIRRELVM vm, const dpp::snowflake& value) noexcept {
// sq_pushinteger(vm, static_cast<SQInteger>(static_cast<uint64_t>(value)));
// }
// };
// // Allow the VM to treat the dpp::snowflake type as a integer.
// template<> struct Var<const dpp::snowflake&>
// {
// dpp::snowflake value;
// Var(HSQUIRRELVM vm, SQInteger idx) {
// sq_getinteger(vm, idx, reinterpret_cast<SQInteger*>(&static_cast<uint64_t&>(value)));
// }
// inline static void push(HSQUIRRELVM vm, const dpp::snowflake& value) noexcept {
// sq_pushinteger(vm, static_cast<SQInteger>(static_cast<uint64_t>(value)));
// }
// };
// ------------------------------------------------------------------------------------------------
// Used to get and push dpp::snowflake instances to and from the stack
template <> struct Var<dpp::snowflake> {
dpp::snowflake value; ///< The actual value of get operations
Var(HSQUIRRELVM vm, SQInteger idx) : value(popAsInt< uint64_t, true >(vm, idx).value) { }
// Push dpp::snowflake instances to the stack as integers
static void push(HSQUIRRELVM vm, const dpp::snowflake& value) noexcept {
sq_pushinteger(vm, static_cast< SQInteger >(static_cast< std::uint64_t >(value)));
} }
inline static void push(HSQUIRRELVM vm, const dpp::snowflake& value) noexcept static void push(HSQUIRRELVM vm, dpp::snowflake& value) noexcept {
{ sq_pushinteger(vm, static_cast< SQInteger >(static_cast< std::uint64_t & >(value)));
sq_pushinteger(vm, static_cast<SQInteger>(static_cast<uint64_t>(value)));
} }
}; };
template <> struct Var<dpp::snowflake&> : public Var<dpp::snowflake> {
// Allow the VM to treat the dpp::snowflake type as a integer. Var(HSQUIRRELVM vm, SQInteger idx) : Var<dpp::snowflake>(vm, idx) { }
template<> struct Var<const dpp::snowflake&> };
{ template <> struct Var<const dpp::snowflake&> : public Var<dpp::snowflake> {
dpp::snowflake value; Var(HSQUIRRELVM vm, SQInteger idx) : Var<dpp::snowflake>(vm, idx) { }
Var(HSQUIRRELVM vm, SQInteger idx)
{
sq_getinteger(vm, idx, reinterpret_cast<SQInteger*>(&static_cast<uint64_t&>(value)));
}
inline static void push(HSQUIRRELVM vm, const dpp::snowflake& value) noexcept
{
sq_pushinteger(vm, static_cast<SQInteger>(static_cast<uint64_t>(value)));
}
}; };
} }
@ -428,6 +445,9 @@ template < class T, class W > struct DpVectorProxy
} }
}; };
/* ------------------------------------------------------------------------------------------------
* Register a wrapper vector for the specified types.
*/
template < class T, class W, class U > inline void Register_Discord_VectorProxy(HSQUIRRELVM vm, Table & ns, const SQChar * name) template < class T, class W, class U > inline void Register_Discord_VectorProxy(HSQUIRRELVM vm, Table & ns, const SQChar * name)
{ {
using Container = DpVectorProxy< T, W >; using Container = DpVectorProxy< T, W >;
@ -459,4 +479,53 @@ template < class T, class W, class U > inline void Register_Discord_VectorProxy(
); );
} }
/* ------------------------------------------------------------------------------------------------
* Wrapper around a std::unordered_map of DPP values.
*/
template < class K, class V, class W > struct DpUnorderedMapProxy
{
using Native = std::unordered_map< K, V >;
using Binder = std::pair< LightObj, W * >;
using Script = std::unordered_map< K, Binder >;
using Ptr = std::unique_ptr< Native >;
/* --------------------------------------------------------------------------------------------
* Referenced map instance.
*/
Ptr mPtr{nullptr};
/* --------------------------------------------------------------------------------------------
* Cached script objects map.
*/
Script mMap{};
/* --------------------------------------------------------------------------------------------
* Whether the referenced pointer is owned.
*/
bool mOwned{false};
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
DpUnorderedMapProxy() noexcept = default;
};
/* ------------------------------------------------------------------------------------------------
* Register a wrapper unordered map for the specified types.
*/
template < class K, class V, class W, class U > inline void Register_Discord_UnorderedMapProxy(HSQUIRRELVM vm, Table & ns, const SQChar * name)
{
using Container = DpUnorderedMapProxy< K, V, W >;
// --------------------------------------------------------------------------------------------
ns.Bind(name,
Class< Container, NoConstructor< Container > >(vm, U::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &U::Fn)
// Properties
//.Prop(_SC("Null"), &Container::IsNull)
//.Prop(_SC("Empty"), &Container::Empty)
//.Prop(_SC("Size"), &Container::Size)
//.Prop(_SC("Capacity"), &Container::Capacity, &Container::Reserve)
// Member Methods
//.Func(_SC("Get"), &Container::Get)
//.Func(_SC("Set"), &Container::Set)
);
}
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -10,6 +10,10 @@
#include <winsock2.h> #include <winsock2.h>
#endif // SQMOD_OS_WINDOWS #endif // SQMOD_OS_WINDOWS
// ------------------------------------------------------------------------------------------------
#include <curl/curl.h>
#include <civetweb.h>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
@ -150,6 +154,7 @@ static void OnServerShutdown()
Core::Get().EmitServerShutdown(); Core::Get().EmitServerShutdown();
// Deallocate and release everything obtained at startup // Deallocate and release everything obtained at startup
Core::Get().Terminate(true); Core::Get().Terminate(true);
curl_global_cleanup();
SQMOD_SV_EV_TRACEBACK("[TRACE>] OnServerShutdown") SQMOD_SV_EV_TRACEBACK("[TRACE>] OnServerShutdown")
} }
SQMOD_CATCH_EVENT_EXCEPTION(OnServerShutdown) SQMOD_CATCH_EVENT_EXCEPTION(OnServerShutdown)
@ -972,11 +977,6 @@ static void OnServerPerformanceReport(size_t /*entry_count*/, const char * * /*d
} // Namespace:: SqMod } // Namespace:: SqMod
/* ------------------------------------------------------------------------------------------------
* Automatically terminate the third-party allocator.
*/
static std::unique_ptr< SqMod::RPMallocInit > gsRPMallocInit;
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Plug-in initialization procedure. * Plug-in initialization procedure.
*/ */
@ -1001,8 +1001,8 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
_Info->apiMinorVersion = PLUGIN_API_MINOR; _Info->apiMinorVersion = PLUGIN_API_MINOR;
// Assign the plug-in name // Assign the plug-in name
std::snprintf(_Info->name, sizeof(_Info->name), "%s", SQMOD_HOST_NAME); std::snprintf(_Info->name, sizeof(_Info->name), "%s", SQMOD_HOST_NAME);
// Initialize third-party allocator // Initialize CURL
gsRPMallocInit = std::make_unique< RPMallocInit >(); curl_global_init(CURL_GLOBAL_DEFAULT);
// Attempt to initialize the logger before anything else // Attempt to initialize the logger before anything else
Logger::Get().Initialize(nullptr); Logger::Get().Initialize(nullptr);
// Attempt to initialize the plug-in core // Attempt to initialize the plug-in core

View File

@ -41,7 +41,7 @@ SQMOD_DECL_TYPENAME(SqPcSqDataAsyncBuilder, _SC("SqSqDataAsyncBuilder"))
SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult")) SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult"))
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const Poco::Data::NullData g_NullData{Poco::NULL_GENERIC}; static const Poco::Data::NullData g_NullData = std::nullopt;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void InitializePocoDataConnectors() void InitializePocoDataConnectors()

View File

@ -45,7 +45,7 @@ struct popAsInt
T value; T value;
popAsInt(HSQUIRRELVM vm, SQInteger idx) popAsInt(HSQUIRRELVM vm, SQInteger idx)
{ {
SQObjectType value_type = sq_gettype(vm, idx); const SQObjectType value_type = sq_gettype(vm, idx);
switch(value_type) { switch(value_type) {
case OT_BOOL: case OT_BOOL:
SQBool sqValueb; SQBool sqValueb;
@ -60,7 +60,7 @@ struct popAsInt
case OT_FLOAT: case OT_FLOAT:
SQFloat sqValuef; SQFloat sqValuef;
sq_getfloat(vm, idx, &sqValuef); sq_getfloat(vm, idx, &sqValuef);
value = static_cast<T>(static_cast<int>(sqValuef)); value = static_cast<T>(static_cast<SQInteger>(sqValuef));
break; break;
default: default:
SQTHROW(vm, FormatTypeError(vm, idx, _SC("integer"))); SQTHROW(vm, FormatTypeError(vm, idx, _SC("integer")));
@ -86,7 +86,7 @@ struct popAsFloat
T value; T value;
popAsFloat(HSQUIRRELVM vm, SQInteger idx) popAsFloat(HSQUIRRELVM vm, SQInteger idx)
{ {
SQObjectType value_type = sq_gettype(vm, idx); const SQObjectType value_type = sq_gettype(vm, idx);
switch(value_type) { switch(value_type) {
case OT_BOOL: case OT_BOOL:
SQBool sqValueb; SQBool sqValueb;

View File

@ -1,7 +1,6 @@
add_subdirectory(ConcurrentQueue) add_subdirectory(ConcurrentQueue)
add_subdirectory(Fmt) add_subdirectory(Fmt)
add_subdirectory(xxHash) add_subdirectory(xxHash)
add_subdirectory(RPMalloc)
add_subdirectory(Squirrel) add_subdirectory(Squirrel)
add_subdirectory(SimpleIni) add_subdirectory(SimpleIni)
add_subdirectory(TinyDir) add_subdirectory(TinyDir)
@ -72,6 +71,8 @@ set(BUILD_STATIC ON CACHE INTERNAL "" FORCE)
if (WIN32 OR MINGW) if (WIN32 OR MINGW)
set(ZMQ_HAVE_IPC OFF CACHE INTERNAL "" FORCE) set(ZMQ_HAVE_IPC OFF CACHE INTERNAL "" FORCE)
endif() endif()
set(ENABLE_CURVE OFF CACHE INTERNAL "" FORCE)
set(WITH_LIBSODIUM OFF CACHE INTERNAL "" FORCE)
add_subdirectory(ZMQ) add_subdirectory(ZMQ)
if(ENABLE_DISCORD) if(ENABLE_DISCORD)
set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE) set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE)

View File

@ -1,52 +1,84 @@
# Create the CPR library # Create the CPR library
add_library(CPR STATIC add_library(CPR STATIC
# Source files # 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/error.cpp
cpr/file.cpp
cpr/interceptor.cpp
cpr/multipart.cpp cpr/multipart.cpp
cpr/multiperform.cpp
cpr/parameters.cpp cpr/parameters.cpp
cpr/payload.cpp cpr/payload.cpp
cpr/proxies.cpp cpr/proxies.cpp
cpr/proxyauth.cpp cpr/proxyauth.cpp
cpr/redirect.cpp cpr/redirect.cpp
cpr/response.cpp
cpr/session.cpp cpr/session.cpp
cpr/ssl_ctx.cpp
cpr/threadpool.cpp
cpr/timeout.cpp cpr/timeout.cpp
cpr/unix_socket.cpp cpr/unix_socket.cpp
cpr/util.cpp cpr/util.cpp
cpr/response.cpp cpr/accept_encoding.cpp
# Header files cpr/async.cpp
include/cpr/api.h cpr/auth.cpp
include/cpr/auth.h 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/bearer.h
include/cpr/body.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/cookies.h
include/cpr/cpr.h include/cpr/cpr.h
include/cpr/cprtypes.h include/cpr/cprtypes.h
include/cpr/curl_container.h
include/cpr/curlholder.h include/cpr/curlholder.h
include/cpr/curlholder.h include/cpr/curlmultiholder.h
include/cpr/digest.h
include/cpr/error.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/interface.h
include/cpr/limit_rate.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/multipart.h
include/cpr/ntlm.h include/cpr/multiperform.h
include/cpr/parameters.h include/cpr/parameters.h
include/cpr/payload.h include/cpr/payload.h
include/cpr/proxies.h include/cpr/proxies.h
include/cpr/proxyauth.h include/cpr/proxyauth.h
include/cpr/range.h
include/cpr/redirect.h include/cpr/redirect.h
include/cpr/reserve_size.h
include/cpr/resolve.h
include/cpr/response.h include/cpr/response.h
include/cpr/session.h include/cpr/session.h
include/cpr/singleton.h
include/cpr/ssl_ctx.h
include/cpr/ssl_options.h include/cpr/ssl_options.h
include/cpr/status_codes.h
include/cpr/threadpool.h
include/cpr/timeout.h include/cpr/timeout.h
include/cpr/unix_socket.h include/cpr/unix_socket.h
include/cpr/user_agent.h
include/cpr/util.h include/cpr/util.h
include/cpr/verbose.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 # Library includes
target_include_directories(CPR PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cpr) 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) if (NOT MSVC)
target_compile_options(CPR PRIVATE -Wno-deprecated-declarations) target_compile_options(CPR PRIVATE -Wno-deprecated-declarations)
endif() endif()
# Find CURK # Find CURL
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
if (CURL_FOUND) if (CURL_FOUND)
set(SSL_ENABLED ON CACHE INTERNAL "" FORCE) set(SSL_ENABLED ON CACHE INTERNAL "" FORCE)

37
vendor/CPR/cpr/accept_encoding.cpp vendored Normal file
View 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
View File

@ -0,0 +1,8 @@
#include "cpr/async.h"
namespace cpr {
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
CPR_SINGLETON_IMPL(GlobalThreadPool)
} // namespace cpr

View File

@ -1,7 +1,16 @@
#include "cpr/auth.h" #include "cpr/auth.h"
#include "cpr/util.h"
namespace cpr { namespace cpr {
Authentication::~Authentication() noexcept {
util::secureStringClear(auth_string_);
}
const char* Authentication::GetAuthString() const noexcept { const char* Authentication::GetAuthString() const noexcept {
return auth_string_.c_str(); return auth_string_.c_str();
} }
AuthMode Authentication::GetAuthMode() const noexcept {
return auth_mode_;
}
} // namespace cpr } // namespace cpr

View File

@ -1,9 +1,14 @@
#include "cpr/bearer.h" #include "cpr/bearer.h"
#include "cpr/util.h"
namespace cpr { namespace cpr {
// Only supported with libcurl >= 7.61.0. // Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually. // As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00 #if LIBCURL_VERSION_NUM >= 0x073D00
Bearer::~Bearer() noexcept {
util::secureStringClear(token_string_);
}
const char* Bearer::GetToken() const noexcept { const char* Bearer::GetToken() const noexcept {
return token_string_.c_str(); return token_string_.c_str();
} }

14
vendor/CPR/cpr/callback.cpp vendored Normal file
View 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
View 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

View File

@ -1,51 +1,106 @@
#include "cpr/cookies.h" #include "cpr/cookies.h"
#include <ctime>
#include <iomanip>
namespace cpr { 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; 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 // 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 // special case version 1 cookies, which can be distinguished by
// beginning and trailing quotes // beginning and trailing quotes
if (!item.second.empty() && item.second.front() == '"' && item.second.back() == '"') { if (!item.GetValue().empty() && item.GetValue().front() == '"' && item.GetValue().back() == '"') {
stream << item.second; stream << item.GetValue();
} else { } else {
// Depending on if encoding is set to "true", we will URL-encode cookies // 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 << "; "; stream << "; ";
} }
return stream.str(); return stream.str();
} }
std::string& Cookies::operator[](const std::string& key) { cpr::Cookie& Cookies::operator[](size_t pos) {
return map_[key]; return cookies_[pos];
} }
Cookies::iterator Cookies::begin() { Cookies::iterator Cookies::begin() {
return map_.begin(); return cookies_.begin();
} }
Cookies::iterator Cookies::end() { Cookies::iterator Cookies::end() {
return map_.end(); return cookies_.end();
} }
Cookies::const_iterator Cookies::begin() const { Cookies::const_iterator Cookies::begin() const {
return map_.begin(); return cookies_.begin();
} }
Cookies::const_iterator Cookies::end() const { Cookies::const_iterator Cookies::end() const {
return map_.end(); return cookies_.end();
} }
Cookies::const_iterator Cookies::cbegin() const { Cookies::const_iterator Cookies::cbegin() const {
return map_.cbegin(); return cookies_.cbegin();
} }
Cookies::const_iterator Cookies::cend() const { 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 } // namespace cpr

View File

@ -5,8 +5,6 @@
namespace cpr { namespace cpr {
bool CaseInsensitiveCompare::operator()(const std::string& a, const std::string& b) const noexcept { bool CaseInsensitiveCompare::operator()(const std::string& a, const std::string& b) const noexcept {
return std::lexicographical_compare( 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); });
a.begin(), a.end(), b.begin(), b.end(),
[](unsigned char ac, unsigned char bc) { return std::tolower(ac) < std::tolower(bc); });
} }
} // namespace cpr } // namespace cpr

View File

@ -1,16 +1,15 @@
#include "cpr/curl_container.h" #include "cpr/curl_container.h"
#include <algorithm>
#include <iterator>
namespace cpr { namespace cpr {
template <class T> template <class T>
CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList) CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList) : containerList_(containerList) {}
: containerList_(containerList) {}
template <class T> template <class T>
void CurlContainer<T>::Add(const std::initializer_list<T>& containerList) { void CurlContainer<T>::Add(const std::initializer_list<T>& containerList) {
for (const T& element : containerList) { std::transform(containerList.begin(), containerList.end(), std::back_inserter(containerList_), [](const T& elem) { return std::move(elem); });
containerList_.push_back(std::move(element));
}
} }
template <class T> template <class T>
@ -26,15 +25,15 @@ const std::string CurlContainer<Parameter>::GetContent(const CurlHolder& holder)
content += "&"; 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()) { if (parameter.value.empty()) {
content += escapedKey; content += escapedKey;
} else { } 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 += escapedKey + "=";
content += escapedValue; content += escapedValue;
} }
}; }
return content; return content;
} }
@ -46,7 +45,7 @@ const std::string CurlContainer<Pair>::GetContent(const CurlHolder& holder) cons
if (!content.empty()) { if (!content.empty()) {
content += "&"; 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; content += element.key + "=" + escaped;
} }

View File

@ -2,10 +2,6 @@
#include <cassert> #include <cassert>
namespace cpr { 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() { CurlHolder::CurlHolder() {
/** /**
* Allow multithreaded access to CPR by locking curl_easy_init(). * 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/curl_easy_init.html
* https://curl.haxx.se/libcurl/c/threadsafe.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(); handle = curl_easy_init();
curl_easy_init_mutex_.unlock(); curl_easy_init_mutex_().unlock();
assert(handle); assert(handle);
} // namespace cpr } // namespace cpr
CurlHolder::~CurlHolder() { CurlHolder::~CurlHolder() {
curl_slist_free_all(chunk); curl_slist_free_all(chunk);
curl_formfree(formpost); curl_slist_free_all(resolveCurlList);
curl_mime_free(multipart);
curl_easy_cleanup(handle); curl_easy_cleanup(handle);
} }
std::string CurlHolder::urlEncode(const std::string& s) const { std::string CurlHolder::urlEncode(const std::string& s) const {
assert(handle); 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) { if (output) {
std::string result = output; std::string result = output;
curl_free(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 { std::string CurlHolder::urlDecode(const std::string& s) const {
assert(handle); 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) { if (output) {
std::string result = output; std::string result = output;
curl_free(output); curl_free(output);

15
vendor/CPR/cpr/curlmultiholder.cpp vendored Normal file
View 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

View File

@ -59,7 +59,7 @@ ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) {
case CURLE_SSL_ISSUER_ERROR: case CURLE_SSL_ISSUER_ERROR:
return ErrorCode::SSL_CACERT_ERROR; return ErrorCode::SSL_CACERT_ERROR;
case CURLE_TOO_MANY_REDIRECTS: case CURLE_TOO_MANY_REDIRECTS:
return ErrorCode::OK; return ErrorCode::TOO_MANY_REDIRECTS;
default: default:
return ErrorCode::INTERNAL_ERROR; return ErrorCode::INTERNAL_ERROR;
} }

60
vendor/CPR/cpr/file.cpp vendored Normal file
View 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
View 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

View File

@ -2,4 +2,6 @@
namespace cpr { namespace cpr {
Multipart::Multipart(const std::initializer_list<Part>& p_parts) : parts{p_parts} {} 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 } // namespace cpr

323
vendor/CPR/cpr/multiperform.cpp vendored Normal file
View 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(), [&current_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

View File

@ -1,10 +1,4 @@
#include "cpr/parameters.h" #include "cpr/parameters.h"
#include <initializer_list>
#include <string>
#include "cpr/util.h"
namespace cpr { namespace cpr {
Parameters::Parameters(const std::initializer_list<Parameter>& parameters) : CurlContainer<Parameter>(parameters) {}
} // namespace cpr } // namespace cpr

View File

@ -1,10 +1,4 @@
#include "cpr/payload.h" #include "cpr/payload.h"
#include <initializer_list>
#include <string>
#include "cpr/util.h"
namespace cpr { namespace cpr {
Payload::Payload(const std::initializer_list<Pair>& pairs) : CurlContainer<Pair>(pairs) {}
} // namespace cpr } // namespace cpr

View File

@ -7,8 +7,8 @@
namespace cpr { namespace cpr {
Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts) Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts) : hosts_{hosts} {}
: hosts_{hosts} {} Proxies::Proxies(const std::map<std::string, std::string>& hosts) : hosts_{hosts} {}
bool Proxies::has(const std::string& protocol) const { bool Proxies::has(const std::string& protocol) const {
return hosts_.count(protocol) > 0; return hosts_.count(protocol) > 0;

View File

@ -1,16 +1,30 @@
#include "cpr/proxyauth.h" #include "cpr/proxyauth.h"
#include "cpr/util.h"
namespace cpr { namespace cpr {
const char* EncodedAuthentication::GetAuthString() const noexcept { EncodedAuthentication::~EncodedAuthentication() noexcept {
return auth_string_.c_str(); 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 { bool ProxyAuthentication::has(const std::string& protocol) const {
return proxyAuth_.count(protocol) > 0; return proxyAuth_.count(protocol) > 0;
} }
const char* ProxyAuthentication::operator[](const std::string& protocol) { const char* ProxyAuthentication::GetUsername(const std::string& protocol) {
return proxyAuth_[protocol].GetAuthString(); return proxyAuth_[protocol].username.c_str();
}
const char* ProxyAuthentication::GetPassword(const std::string& protocol) {
return proxyAuth_[protocol].password.c_str();
} }
} // namespace cpr } // namespace cpr

View File

@ -19,7 +19,7 @@ PostRedirectFlags operator~(PostRedirectFlags flag) {
PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs) { PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(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); lhs = static_cast<PostRedirectFlags>(tmp);
return lhs; return lhs;
} }

View File

@ -1,12 +1,9 @@
#include "cpr/response.h" #include "cpr/response.h"
namespace cpr { namespace cpr {
Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
std::string&& p_header_string, Cookies&& p_cookies = Cookies{}, 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)) {
Error&& p_error = Error{}) header = cpr::util::parseHeader(raw_header, &status_line, &reason);
: 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);
assert(curl_); assert(curl_);
assert(curl_->handle); assert(curl_->handle);
curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code); 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}; char* url_string{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string); curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string);
url = 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_DOWNLOAD_T, &downloaded_bytes);
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes); curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes);
#else #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); 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_);
assert(curl_->handle); assert(curl_->handle);
curl_certinfo* ci{nullptr}; curl_certinfo* ci{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci); curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci);
std::vector<std::string> info; std::vector<CertInfo> cert_infos;
info.resize(ci->num_of_certs);
for (int i = 0; i < ci->num_of_certs; i++) { for (int i = 0; i < ci->num_of_certs; i++) {
// No way around here. CertInfo cert_info;
// NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) // 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 } // namespace cpr

File diff suppressed because it is too large Load Diff

70
vendor/CPR/cpr/ssl_ctx.cpp vendored Normal file
View 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
View 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

View File

@ -14,12 +14,12 @@ long Timeout::Milliseconds() const {
// No way around since curl uses a long here. // No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int) // 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."); throw std::overflow_error("cpr::Timeout: timeout value overflow: " + std::to_string(ms.count()) + " ms.");
} }
// No way around since curl uses a long here. // No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int) // 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."); throw std::underflow_error("cpr::Timeout: timeout value underflow: " + std::to_string(ms.count()) + " ms.");
} }

View File

@ -3,23 +3,64 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
#include <chrono>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <ios>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
namespace cpr { #if defined(_Win32)
namespace util { #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) { Cookies parseCookies(curl_slist* raw_cookies) {
const int CURL_HTTP_COOKIE_SIZE = static_cast<int>(CurlHTTPCookieField::Value) + 1;
Cookies cookies; Cookies cookies;
for (curl_slist* nc = raw_cookies; nc; nc = nc->next) { for (curl_slist* nc = raw_cookies; nc; nc = nc->next) {
std::vector<std::string> tokens = cpr::util::split(nc->data, '\t'); std::vector<std::string> tokens = cpr::util::split(nc->data, '\t');
std::string value = tokens.back(); while (tokens.size() < CURL_HTTP_COOKIE_SIZE) {
tokens.pop_back(); tokens.emplace_back("");
cookies[tokens.back()] = value; }
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; return cookies;
} }
@ -36,7 +77,6 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
} }
for (std::string& line : lines) { for (std::string& line : lines) {
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
if (line.substr(0, 5) == "HTTP/") { if (line.substr(0, 5) == "HTTP/") {
// set the status_line if it was given // set the status_line if it was given
if ((status_line != nullptr) || (reason != nullptr)) { 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 // set the reason if it was given
if (reason != nullptr) { 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; size_t pos2 = std::string::npos;
if (pos1 != std::string::npos) { if (pos1 != std::string::npos) {
pos2 = line.find_first_of("\t ", pos1 + 1); 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) { if (line.length() > 0) {
size_t found = line.find(':'); const size_t found = line.find(':');
if (found != std::string::npos) { if (found != std::string::npos) {
std::string value = line.substr(found + 1); std::string value = line.substr(found + 1);
value.erase(0, value.find_first_not_of("\t ")); 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_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file) {
size *= nmemb; size *= nmemb;
file->write(ptr, size); file->write(ptr, static_cast<std::streamsize>(size));
return 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; return (*write)({ptr, size}) ? size : 0;
} }
#if LIBCURL_VERSION_NUM < 0x072000 int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size, const DebugCallback* debug) {
int progressUserFunction(const ProgressCallback* progress, double dltotal, double dlnow, (*debug)(static_cast<DebugCallback::InfoType>(type), std::string(data, size));
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));
return 0; 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 result = holder.urlEncode(input);
**/ **/
std::string urlEncode(const std::string& s) { 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); return holder.urlEncode(s);
} }
@ -156,9 +185,54 @@ std::string urlEncode(const std::string& s) {
* std::string result = holder.urlDecode(input); * std::string result = holder.urlDecode(input);
**/ **/
std::string urlDecode(const std::string& s) { 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); return holder.urlDecode(s);
} }
} // namespace util #if defined(__STDC_LIB_EXT1__)
} // namespace cpr 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

View 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

View File

@ -7,27 +7,108 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "cpr/async.h"
#include "cpr/async_wrapper.h"
#include "cpr/auth.h" #include "cpr/auth.h"
#include "cpr/bearer.h" #include "cpr/bearer.h"
#include "cpr/cprtypes.h" #include "cpr/cprtypes.h"
#include "cpr/digest.h"
#include "cpr/multipart.h" #include "cpr/multipart.h"
#include "cpr/ntlm.h" #include "cpr/multiperform.h"
#include "cpr/payload.h" #include "cpr/payload.h"
#include "cpr/response.h" #include "cpr/response.h"
#include "cpr/session.h" #include "cpr/session.h"
#include <utility> #include <cpr/filesystem.h>
namespace cpr { namespace cpr {
using AsyncResponse = std::future<Response>; using AsyncResponse = AsyncWrapper<Response>;
namespace priv { 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> template <typename... Ts>
void set_option(Session& session, Ts&&... ts) { void set_option(Session& session, Ts&&... ts) {
std::initializer_list<int> ignore = { (session.SetOption(std::forward<Ts>(ts)), 0)... }; set_option_internal<false, Ts...>(session, std::forward<Ts>(ts)...);
(void)ignore; }
// 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 } // namespace priv
@ -43,17 +124,14 @@ Response Get(Ts&&... ts) {
// Get async methods // Get async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse GetAsync(Ts... ts) { AsyncResponse GetAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
} }
// Get callback methods // Get callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto GetCallback(Then then, Ts... ts) -> std::future<decltype(then(Get(std::move(ts)...)))> { auto GetCallback(Then then, Ts... ts) {
return std::async( return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); },
std::move(then), std::move(ts)...);
} }
// Post methods // Post methods
@ -67,17 +145,14 @@ Response Post(Ts&&... ts) {
// Post async methods // Post async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse PostAsync(Ts... ts) { AsyncResponse PostAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
} }
// Post callback methods // Post callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto PostCallback(Then then, Ts... ts) -> std::future<decltype(then(Post(std::move(ts)...)))> { auto PostCallback(Then then, Ts... ts) {
return std::async( return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); },
std::move(then), std::move(ts)...);
} }
// Put methods // Put methods
@ -91,17 +166,14 @@ Response Put(Ts&&... ts) {
// Put async methods // Put async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse PutAsync(Ts... ts) { AsyncResponse PutAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
} }
// Put callback methods // Put callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto PutCallback(Then then, Ts... ts) -> std::future<decltype(then(Put(std::move(ts)...)))> { auto PutCallback(Then then, Ts... ts) {
return std::async( return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); },
std::move(then), std::move(ts)...);
} }
// Head methods // Head methods
@ -115,17 +187,14 @@ Response Head(Ts&&... ts) {
// Head async methods // Head async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse HeadAsync(Ts... ts) { AsyncResponse HeadAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
} }
// Head callback methods // Head callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto HeadCallback(Then then, Ts... ts) -> std::future<decltype(then(Head(std::move(ts)...)))> { auto HeadCallback(Then then, Ts... ts) {
return std::async( return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); },
std::move(then), std::move(ts)...);
} }
// Delete methods // Delete methods
@ -139,18 +208,14 @@ Response Delete(Ts&&... ts) {
// Delete async methods // Delete async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse DeleteAsync(Ts... ts) { AsyncResponse DeleteAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Delete(std::move(ts_inner)...); },
std::move(ts)...);
} }
// Delete callback methods // Delete callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto DeleteCallback(Then then, Ts... ts) -> std::future<decltype(then(Delete(std::move(ts)...)))> { auto DeleteCallback(Then then, Ts... ts) {
return std::async( return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); },
std::move(then), std::move(ts)...);
} }
// Options methods // Options methods
@ -164,19 +229,14 @@ Response Options(Ts&&... ts) {
// Options async methods // Options async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse OptionsAsync(Ts... ts) { AsyncResponse OptionsAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Options(std::move(ts_inner)...); },
std::move(ts)...);
} }
// Options callback methods // Options callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto OptionsCallback(Then then, Ts... ts) auto OptionsCallback(Then then, Ts... ts) {
-> std::future<decltype(then(Options(std::move(ts)...)))> { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, std::move(then), 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)...);
} }
// Patch methods // Patch methods
@ -190,17 +250,14 @@ Response Patch(Ts&&... ts) {
// Patch async methods // Patch async methods
template <typename... Ts> template <typename... Ts>
AsyncResponse PatchAsync(Ts... ts) { AsyncResponse PatchAsync(Ts... ts) {
return std::async( return cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
std::launch::async, [](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
} }
// Patch callback methods // Patch callback methods
template <typename Then, typename... Ts> template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return) // NOLINTNEXTLINE(fuchsia-trailing-return)
auto PatchCallback(Then then, Ts... ts) -> std::future<decltype(then(Patch(std::move(ts)...)))> { auto PatchCallback(Then then, Ts... ts) {
return std::async( return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
std::launch::async, [](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); },
std::move(then), std::move(ts)...);
} }
// Download methods // Download methods
@ -211,6 +268,18 @@ Response Download(std::ofstream& file, Ts&&... ts) {
return session.Download(file); 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 // Download with user callback
template <typename... Ts> template <typename... Ts>
Response Download(const WriteCallback& write, Ts&&... ts) { Response Download(const WriteCallback& write, Ts&&... ts) {
@ -219,6 +288,105 @@ Response Download(const WriteCallback& write, Ts&&... ts) {
return session.Download(write); 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 } // namespace cpr
#endif #endif

50
vendor/CPR/include/cpr/async.h vendored Normal file
View 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
View 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

View File

@ -7,23 +7,24 @@
namespace cpr { namespace cpr {
enum class AuthMode { BASIC, DIGEST, NTLM };
class Authentication { class Authentication {
public: public:
Authentication(const std::string& username, const std::string& 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)} {}
: auth_string_{username + ":" + password} {}
Authentication(std::string&& username, std::string&& password)
: auth_string_{std::move(username) + ":" + std::move(password)} {}
Authentication(const Authentication& other) = default; Authentication(const Authentication& other) = default;
Authentication(Authentication&& old) noexcept = default; Authentication(Authentication&& old) noexcept = default;
virtual ~Authentication() noexcept = default; ~Authentication() noexcept;
Authentication& operator=(Authentication&& old) noexcept = default; Authentication& operator=(Authentication&& old) noexcept = default;
Authentication& operator=(const Authentication& other) = 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_; std::string auth_string_;
AuthMode auth_mode_;
}; };
} // namespace cpr } // namespace cpr

View File

@ -1,8 +1,8 @@
#ifndef CPR_BEARER_H #ifndef CPR_BEARER_H
#define CPR_BEARER_H #define CPR_BEARER_H
#include <string>
#include <curl/curlver.h> #include <curl/curlver.h>
#include <string>
#include <utility> #include <utility>
@ -14,12 +14,10 @@ namespace cpr {
class Bearer { class Bearer {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Bearer(const std::string& token) : token_string_{token} {} Bearer(std::string token) : token_string_{std::move(token)} {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Bearer(std::string&& token) : token_string_{std::move(token)} {}
Bearer(const Bearer& other) = default; Bearer(const Bearer& other) = default;
Bearer(Bearer&& old) noexcept = default; Bearer(Bearer&& old) noexcept = default;
virtual ~Bearer() noexcept = default; virtual ~Bearer() noexcept;
Bearer& operator=(Bearer&& old) noexcept = default; Bearer& operator=(Bearer&& old) noexcept = default;
Bearer& operator=(const Bearer& other) = default; Bearer& operator=(const Bearer& other) = default;

View File

@ -1,24 +1,46 @@
#ifndef CPR_BODY_H #ifndef CPR_BODY_H
#define CPR_BODY_H #define CPR_BODY_H
#include <exception>
#include <fstream>
#include <initializer_list> #include <initializer_list>
#include <string> #include <string>
#include <vector>
#include "cpr/buffer.h"
#include "cpr/cprtypes.h" #include "cpr/cprtypes.h"
#include "cpr/file.h"
namespace cpr { namespace cpr {
class Body : public StringHolder<Body> { class Body : public StringHolder<Body> {
public: public:
Body() : StringHolder<Body>() {} Body() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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) // 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) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Body(const char* body) : StringHolder<Body>(body) {} Body(const char* body) : StringHolder<Body>(body) {}
Body(const char* str, size_t len) : StringHolder<Body>(str, len) {} Body(const char* str, size_t len) : StringHolder<Body>(str, len) {}
Body(const std::initializer_list<std::string> args) : StringHolder<Body>(args) {} 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(const Body& other) = default;
Body(Body&& old) noexcept = default; Body(Body&& old) noexcept = default;
~Body() override = default; ~Body() override = default;

33
vendor/CPR/include/cpr/buffer.h vendored Normal file
View 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

View File

@ -3,7 +3,9 @@
#include "cprtypes.h" #include "cprtypes.h"
#include <atomic>
#include <functional> #include <functional>
#include <optional>
#include <utility> #include <utility>
namespace cpr { namespace cpr {
@ -14,11 +16,11 @@ class ReadCallback {
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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(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)} {} 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 { bool operator()(char* buffer, size_t& buffer_size) const {
return callback(buffer, size, userdata); return callback(buffer, buffer_size, userdata);
} }
intptr_t userdata; intptr_t userdata{};
cpr_off_t size{}; cpr_off_t size{};
std::function<bool(char* buffer, size_t& size, intptr_t userdata)> callback; std::function<bool(char* buffer, size_t& size, intptr_t userdata)> callback;
}; };
@ -32,7 +34,7 @@ class HeaderCallback {
return callback(std::move(header), userdata); return callback(std::move(header), userdata);
} }
intptr_t userdata; intptr_t userdata{};
std::function<bool(std::string header, intptr_t userdata)> callback; std::function<bool(std::string header, intptr_t userdata)> callback;
}; };
@ -45,7 +47,7 @@ class WriteCallback {
return callback(std::move(data), userdata); return callback(std::move(data), userdata);
} }
intptr_t userdata; intptr_t userdata{};
std::function<bool(std::string data, intptr_t userdata)> callback; std::function<bool(std::string data, intptr_t userdata)> callback;
}; };
@ -53,13 +55,13 @@ class ProgressCallback {
public: public:
ProgressCallback() = default; ProgressCallback() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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)) {} 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_off_t downloadTotal, cpr_off_t downloadNow, cpr_off_t uploadTotal, cpr_off_t uploadNow) const { 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); return callback(downloadTotal, downloadNow, uploadTotal, uploadNow, userdata);
} }
intptr_t userdata; intptr_t userdata{};
std::function<bool(size_t downloadTotal, size_t downloadNow, size_t uploadTotal, size_t uploadNow, intptr_t userdata)> callback; 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 { class DebugCallback {
@ -80,10 +82,30 @@ class DebugCallback {
callback(type, std::move(data), userdata); callback(type, std::move(data), userdata);
} }
intptr_t userdata; intptr_t userdata{};
std::function<void(InfoType type, std::string data, intptr_t userdata)> callback; 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 } // namespace cpr
#endif #endif

37
vendor/CPR/include/cpr/cert_info.h vendored Normal file
View 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

View File

@ -2,12 +2,49 @@
#define CPR_COOKIES_H #define CPR_COOKIES_H
#include "cpr/curlholder.h" #include "cpr/curlholder.h"
#include <chrono>
#include <initializer_list> #include <initializer_list>
#include <map>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
namespace cpr { 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 { class Cookies {
public: public:
@ -25,19 +62,16 @@ class Cookies {
bool encode{true}; bool encode{true};
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Cookies(bool p_encode = true) : encode(p_encode) {} Cookies(bool p_encode = true) : encode{p_encode} {}
Cookies(const std::initializer_list<std::pair<const std::string, std::string>>& pairs, Cookies(const std::initializer_list<cpr::Cookie>& cookies, bool p_encode = true) : encode{p_encode}, cookies_{cookies} {}
bool p_encode = true)
: encode(p_encode), map_{pairs} {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Cookies(const std::map<std::string, std::string>& map, bool p_encode = true) Cookies(const cpr::Cookie& cookie, bool p_encode = true) : encode{p_encode}, cookies_{cookie} {}
: encode(p_encode), map_{map} {}
std::string& operator[](const std::string& key); cpr::Cookie& operator[](size_t pos);
std::string GetEncoded(const CurlHolder& holder) const; const std::string GetEncoded(const CurlHolder& holder) const;
using iterator = std::map<std::string, std::string>::iterator; using iterator = std::vector<cpr::Cookie>::iterator;
using const_iterator = std::map<std::string, std::string>::const_iterator; using const_iterator = std::vector<cpr::Cookie>::const_iterator;
iterator begin(); iterator begin();
iterator end(); iterator end();
@ -45,9 +79,12 @@ class Cookies {
const_iterator end() const; const_iterator end() const;
const_iterator cbegin() const; const_iterator cbegin() const;
const_iterator cend() const; const_iterator cend() const;
void emplace_back(const Cookie& str);
void push_back(const Cookie& str);
void pop_back();
protected: protected:
std::map<std::string, std::string> map_; std::vector<cpr::Cookie> cookies_;
}; };
} // namespace cpr } // namespace cpr

View File

@ -3,12 +3,43 @@
#include "cpr/api.h" #include "cpr/api.h"
#include "cpr/auth.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/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/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/redirect.h"
#include "cpr/reserve_size.h"
#include "cpr/resolve.h"
#include "cpr/response.h" #include "cpr/response.h"
#include "cpr/session.h" #include "cpr/session.h"
#include "cpr/ssl_ctx.h"
#include "cpr/ssl_options.h"
#include "cpr/status_codes.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 #define CPR_LIBCURL_VERSION_NUM LIBCURL_VERSION_NUM

View File

@ -2,11 +2,13 @@
#define CPR_CPR_TYPES_H #define CPR_CPR_TYPES_H
#include <curl/curl.h> #include <curl/curl.h>
#include <curl/system.h>
#include <initializer_list> #include <initializer_list>
#include <map> #include <map>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
#include <string> #include <string>
#include <string_view>
namespace cpr { namespace cpr {
@ -15,12 +17,21 @@ namespace cpr {
**/ **/
using cpr_off_t = curl_off_t; 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> template <class T>
class StringHolder { class StringHolder {
public: public:
StringHolder() = default; 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) {} explicit StringHolder(const char* str) : str_(str) {}
StringHolder(const char* str, size_t len) : str_(str, len) {} StringHolder(const char* str, size_t len) : str_(str, len) {}
StringHolder(const std::initializer_list<std::string> args) { StringHolder(const std::initializer_list<std::string> args) {
@ -107,9 +118,9 @@ class Url : public StringHolder<Url> {
public: public:
Url() = default; Url() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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) // 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) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Url(const char* url) : StringHolder<Url>(url) {} Url(const char* url) : StringHolder<Url>(url) {}
Url(const char* str, size_t len) : StringHolder<Url>(std::string(str, len)) {} Url(const char* str, size_t len) : StringHolder<Url>(std::string(str, len)) {}

30
vendor/CPR/include/cpr/cprver.h vendored Normal file
View 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

View File

@ -12,18 +12,14 @@
namespace cpr { namespace cpr {
struct Parameter { 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 key;
std::string value; std::string value;
}; };
struct Pair { 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 key;
std::string value; std::string value;

View File

@ -17,14 +17,18 @@ struct CurlHolder {
* https://curl.haxx.se/libcurl/c/curl_easy_init.html * https://curl.haxx.se/libcurl/c/curl_easy_init.html
* https://curl.haxx.se/libcurl/c/threadsafe.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) // Avoids initalization order problems in a static build
static std::mutex& curl_easy_init_mutex_() {
static std::mutex curl_easy_init_mutex_; static std::mutex curl_easy_init_mutex_;
return curl_easy_init_mutex_;
}
public: public:
CURL* handle{nullptr}; CURL* handle{nullptr};
struct curl_slist* chunk{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{}; std::array<char, CURL_ERROR_SIZE> error{};
CurlHolder(); CurlHolder();

View 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

View File

@ -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

View File

@ -27,6 +27,7 @@ enum class ErrorCode {
GENERIC_SSL_ERROR, GENERIC_SSL_ERROR,
UNSUPPORTED_PROTOCOL, UNSUPPORTED_PROTOCOL,
REQUEST_CANCELLED, REQUEST_CANCELLED,
TOO_MANY_REDIRECTS,
UNKNOWN_ERROR = 1000, UNKNOWN_ERROR = 1000,
}; };
@ -37,9 +38,7 @@ class Error {
Error() = default; Error() = default;
Error(const std::int32_t& curl_code, std::string&& 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)) {}
: code{getErrorCodeForCurlError(curl_code)},
message(std::move(p_error_message)) {}
explicit operator bool() const { explicit operator bool() const {
return code != ErrorCode::OK; return code != ErrorCode::OK;

59
vendor/CPR/include/cpr/file.h vendored Normal file
View 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
View 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
View 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
View 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

View File

@ -10,11 +10,11 @@ namespace cpr {
class Interface : public StringHolder<Interface> { class Interface : public StringHolder<Interface> {
public: public:
Interface() : StringHolder<Interface>() {} Interface() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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) // 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) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Interface(const char* iface) : StringHolder<Interface>(iface) {} Interface(const char* iface) : StringHolder<Interface>(iface) {}
Interface(const char* str, size_t len) : StringHolder<Interface>(str, len) {} Interface(const char* str, size_t len) : StringHolder<Interface>(str, len) {}

View File

@ -7,8 +7,7 @@ namespace cpr {
class LimitRate { class LimitRate {
public: public:
LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate) LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate) : downrate(p_downrate), uprate(p_uprate) {}
: downrate(p_downrate), uprate(p_uprate) {}
std::int64_t downrate = 0; std::int64_t downrate = 0;
std::int64_t uprate = 0; std::int64_t uprate = 0;

23
vendor/CPR/include/cpr/local_port.h vendored Normal file
View 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

View 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

View File

@ -7,69 +7,35 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include "buffer.h"
#include "file.h"
namespace cpr { 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 { struct Part {
Part(const std::string& p_name, const std::string& p_value, const std::string& p_content_type = {}) 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} {}
: name{p_name}, value{p_value}, 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} {}
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, const std::int32_t& p_value, const std::string& p_content_type = {}) 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} {}
: name{p_name}, value{std::to_string(p_value)}, 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} {}
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} {}
std::string name; std::string name;
// We don't use fs::path here, as this leads to problems using windows
std::string value; std::string value;
std::string content_type; std::string content_type;
Buffer::data_t data{nullptr}; Buffer::data_t data{nullptr};
// Ignored here since libcurl reqires a long: size_t datalen{0};
// NOLINTNEXTLINE(google-runtime-int)
long datalen{0};
bool is_file; bool is_file;
bool is_buffer; bool is_buffer;
Files files;
}; };
class Multipart { class Multipart {
public: public:
Multipart(const std::initializer_list<Part>& parts); Multipart(const std::initializer_list<Part>& parts);
Multipart(const std::vector<Part>& parts);
Multipart(const std::vector<Part>&& parts);
std::vector<Part> parts; std::vector<Part> parts;
}; };

137
vendor/CPR/include/cpr/multiperform.h vendored Normal file
View 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

View File

@ -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

View File

@ -10,7 +10,7 @@ namespace cpr {
class Parameters : public CurlContainer<Parameter> { class Parameters : public CurlContainer<Parameter> {
public: public:
Parameters() = default; Parameters() = default;
Parameters(const std::initializer_list<Parameter>& parameters); Parameters(const std::initializer_list<Parameter>& parameters) : CurlContainer<Parameter>(parameters) {}
}; };
} // namespace cpr } // namespace cpr

View File

@ -15,7 +15,7 @@ class Payload : public CurlContainer<Pair> {
Add(*pair); Add(*pair);
} }
} }
Payload(const std::initializer_list<Pair>& pairs); Payload(const std::initializer_list<Pair>& pairs) : CurlContainer<Pair>(pairs) {}
}; };
} // namespace cpr } // namespace cpr

View File

@ -10,6 +10,7 @@ class Proxies {
public: public:
Proxies() = default; Proxies() = default;
Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts); 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; bool has(const std::string& protocol) const;
const std::string& operator[](const std::string& protocol); const std::string& operator[](const std::string& protocol);

View File

@ -3,36 +3,44 @@
#include <initializer_list> #include <initializer_list>
#include <map> #include <map>
#include <string>
#include "cpr/auth.h" #include "cpr/auth.h"
#include "cpr/util.h" #include "cpr/util.h"
namespace cpr { namespace cpr {
class ProxyAuthentication;
class EncodedAuthentication { class EncodedAuthentication {
friend ProxyAuthentication;
public: public:
EncodedAuthentication() : auth_string_{""} {} EncodedAuthentication() = default;
EncodedAuthentication(const std::string& username, const std::string& password) : auth_string_{cpr::util::urlEncode(username) + ":" + cpr::util::urlEncode(password)} {} EncodedAuthentication(const std::string& p_username, const std::string& p_password) : username(util::urlEncode(p_username)), password(util::urlEncode(p_password)) {}
EncodedAuthentication(std::string&& username, std::string&& password) : auth_string_{cpr::util::urlEncode(std::move(username)) + ":" + cpr::util::urlEncode(std::move(password))} {}
EncodedAuthentication(const EncodedAuthentication& other) = default; EncodedAuthentication(const EncodedAuthentication& other) = default;
EncodedAuthentication(EncodedAuthentication&& old) noexcept = default; EncodedAuthentication(EncodedAuthentication&& old) noexcept = default;
virtual ~EncodedAuthentication() noexcept = default; virtual ~EncodedAuthentication() noexcept;
EncodedAuthentication& operator=(EncodedAuthentication&& old) noexcept = default; EncodedAuthentication& operator=(EncodedAuthentication&& old) noexcept = default;
EncodedAuthentication& operator=(const EncodedAuthentication& other) = 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: private:
std::string auth_string_; std::string username;
std::string password;
}; };
class ProxyAuthentication { class ProxyAuthentication {
public: public:
ProxyAuthentication() = default; ProxyAuthentication() = default;
ProxyAuthentication(const std::initializer_list<std::pair<const std::string, EncodedAuthentication>>& auths) : proxyAuth_{auths} {} 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; [[nodiscard]] bool has(const std::string& protocol) const;
const char* operator[](const std::string& protocol); const char* GetUsername(const std::string& protocol);
const char* GetPassword(const std::string& protocol);
private: private:
std::map<std::string, EncodedAuthentication> proxyAuth_; std::map<std::string, EncodedAuthentication> proxyAuth_;

44
vendor/CPR/include/cpr/range.h vendored Normal file
View 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

View File

@ -50,7 +50,7 @@ class Redirect {
* Default: 50 * Default: 50
* https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html * https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html
**/ **/
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers, google-runtime-int) // NOLINTNEXTLINE (google-runtime-int)
long maximum{50L}; long maximum{50L};
/** /**
* Follow 3xx redirects. * Follow 3xx redirects.
@ -58,6 +58,12 @@ class Redirect {
* https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html * https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html
**/ **/
bool follow{true}; 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. * Flags to control how to act after a redirect for a post request.
* Default: POST_ALL * Default: POST_ALL
@ -66,11 +72,12 @@ class Redirect {
Redirect() = default; Redirect() = default;
// NOLINTNEXTLINE (google-runtime-int) // 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) // NOLINTNEXTLINE (google-runtime-int)
explicit Redirect(long p_maximum) : maximum(p_maximum){}; explicit Redirect(long p_maximum) : maximum(p_maximum){}
explicit Redirect(bool p_follow) : follow(p_follow){}; explicit Redirect(bool p_follow) : follow(p_follow){}
explicit Redirect(PostRedirectFlags p_post_flags) : post_flags(p_post_flags){}; 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 } // namespace cpr

17
vendor/CPR/include/cpr/reserve_size.h vendored Normal file
View 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
View 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

View File

@ -3,12 +3,12 @@
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <curl/curl.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "cpr/cert_info.h"
#include "cpr/cookies.h" #include "cpr/cookies.h"
#include "cpr/cprtypes.h" #include "cpr/cprtypes.h"
#include "cpr/error.h" #include "cpr/error.h"
@ -17,8 +17,11 @@
namespace cpr { namespace cpr {
class MultiPerform;
class Response { class Response {
protected: protected:
friend MultiPerform;
std::shared_ptr<CurlHolder> curl_{nullptr}; std::shared_ptr<CurlHolder> curl_{nullptr};
public: public:
@ -41,9 +44,8 @@ class Response {
long redirect_count{}; long redirect_count{};
Response() = default; Response() = default;
Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string, Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string, Cookies&& p_cookies, Error&& p_error);
Cookies&& p_cookies, Error&& p_error); std::vector<CertInfo> GetCertInfos();
std::vector<std::string> GetCertInfo();
Response(const Response& other) = default; Response(const Response& other) = default;
Response(Response&& old) noexcept = default; Response(Response&& old) noexcept = default;
~Response() noexcept = default; ~Response() noexcept = default;

View File

@ -3,8 +3,13 @@
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <functional>
#include <future>
#include <memory> #include <memory>
#include <queue>
#include "cpr/accept_encoding.h"
#include "cpr/async_wrapper.h"
#include "cpr/auth.h" #include "cpr/auth.h"
#include "cpr/bearer.h" #include "cpr/bearer.h"
#include "cpr/body.h" #include "cpr/body.h"
@ -13,35 +18,45 @@
#include "cpr/cookies.h" #include "cpr/cookies.h"
#include "cpr/cprtypes.h" #include "cpr/cprtypes.h"
#include "cpr/curlholder.h" #include "cpr/curlholder.h"
#include "cpr/digest.h" #include "cpr/http_version.h"
#include "cpr/interface.h" #include "cpr/interface.h"
#include "cpr/limit_rate.h" #include "cpr/limit_rate.h"
#include "cpr/local_port.h"
#include "cpr/local_port_range.h"
#include "cpr/low_speed.h" #include "cpr/low_speed.h"
#include "cpr/multipart.h" #include "cpr/multipart.h"
#include "cpr/ntlm.h"
#include "cpr/parameters.h" #include "cpr/parameters.h"
#include "cpr/payload.h" #include "cpr/payload.h"
#include "cpr/proxies.h" #include "cpr/proxies.h"
#include "cpr/proxyauth.h" #include "cpr/proxyauth.h"
#include "cpr/range.h"
#include "cpr/redirect.h" #include "cpr/redirect.h"
#include "cpr/reserve_size.h"
#include "cpr/resolve.h"
#include "cpr/response.h" #include "cpr/response.h"
#include "cpr/ssl_options.h" #include "cpr/ssl_options.h"
#include "cpr/timeout.h" #include "cpr/timeout.h"
#include "cpr/unix_socket.h" #include "cpr/unix_socket.h"
#include "cpr/user_agent.h" #include "cpr/user_agent.h"
#include "cpr/util.h"
#include "cpr/verbose.h" #include "cpr/verbose.h"
namespace cpr { namespace cpr {
class Session { using AsyncResponse = AsyncWrapper<Response>;
class Interceptor;
class MultiPerform;
class Session : public std::enable_shared_from_this<Session> {
public: public:
Session(); Session();
Session(Session&& old) noexcept;
Session(const Session& other) = delete; 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; Session& operator=(const Session& other) = delete;
void SetUrl(const Url& url); void SetUrl(const Url& url);
@ -52,7 +67,11 @@ class Session {
void SetTimeout(const Timeout& timeout); void SetTimeout(const Timeout& timeout);
void SetConnectTimeout(const ConnectTimeout& timeout); void SetConnectTimeout(const ConnectTimeout& timeout);
void SetAuth(const Authentication& auth); 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 SetUserAgent(const UserAgent& ua);
void SetPayload(Payload&& payload); void SetPayload(Payload&& payload);
void SetPayload(const Payload& payload); void SetPayload(const Payload& payload);
@ -62,7 +81,6 @@ class Session {
void SetProxyAuth(const ProxyAuthentication& proxy_auth); void SetProxyAuth(const ProxyAuthentication& proxy_auth);
void SetMultipart(Multipart&& multipart); void SetMultipart(Multipart&& multipart);
void SetMultipart(const Multipart& multipart); void SetMultipart(const Multipart& multipart);
void SetNTLM(const NTLM& auth);
void SetRedirect(const Redirect& redirect); void SetRedirect(const Redirect& redirect);
void SetCookies(const Cookies& cookies); void SetCookies(const Cookies& cookies);
void SetBody(Body&& body); void SetBody(Body&& body);
@ -78,6 +96,20 @@ class Session {
void SetDebugCallback(const DebugCallback& debug); void SetDebugCallback(const DebugCallback& debug);
void SetVerbose(const Verbose& verbose); void SetVerbose(const Verbose& verbose);
void SetInterface(const Interface& iface); 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 // Used in templated functions
void SetOption(const Url& url); void SetOption(const Url& url);
@ -92,7 +124,6 @@ class Session {
#if LIBCURL_VERSION_NUM >= 0x073D00 #if LIBCURL_VERSION_NUM >= 0x073D00
void SetOption(const Bearer& auth); void SetOption(const Bearer& auth);
#endif #endif
void SetOption(const Digest& auth);
void SetOption(const UserAgent& ua); void SetOption(const UserAgent& ua);
void SetOption(Payload&& payload); void SetOption(Payload&& payload);
void SetOption(const Payload& payload); void SetOption(const Payload& payload);
@ -103,7 +134,6 @@ class Session {
void SetOption(const ProxyAuthentication& proxy_auth); void SetOption(const ProxyAuthentication& proxy_auth);
void SetOption(Multipart&& multipart); void SetOption(Multipart&& multipart);
void SetOption(const Multipart& multipart); void SetOption(const Multipart& multipart);
void SetOption(const NTLM& auth);
void SetOption(const Redirect& redirect); void SetOption(const Redirect& redirect);
void SetOption(const Cookies& cookies); void SetOption(const Cookies& cookies);
void SetOption(Body&& body); void SetOption(Body&& body);
@ -119,8 +149,29 @@ class Session {
void SetOption(const UnixSocket& unix_socket); void SetOption(const UnixSocket& unix_socket);
void SetOption(const SslOptions& options); void SetOption(const SslOptions& options);
void SetOption(const Interface& iface); 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(); 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 Delete();
Response Download(const WriteCallback& write); Response Download(const WriteCallback& write);
Response Download(std::ofstream& file); Response Download(std::ofstream& file);
@ -131,7 +182,33 @@ class Session {
Response Post(); Response Post();
Response Put(); 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::shared_ptr<CurlHolder> GetCurlHolder();
std::string GetFullRequestUrl();
void PrepareDelete(); void PrepareDelete();
void PrepareGet(); void PrepareGet();
@ -140,13 +217,92 @@ class Session {
void PreparePatch(); void PreparePatch();
void PreparePost(); void PreparePost();
void PreparePut(); void PreparePut();
void PrepareDownload(const WriteCallback& write);
void PrepareDownload(std::ofstream& file);
Response Complete(CURLcode curl_error); Response Complete(CURLcode curl_error);
Response CompleteDownload(CURLcode curl_error);
protected: void AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor);
class Impl;
std::unique_ptr<Impl> pimpl_; 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 } // namespace cpr
#endif #endif

47
vendor/CPR/include/cpr/singleton.h vendored Normal file
View 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
View 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

View File

@ -1,67 +1,70 @@
#ifndef CPR_SSLOPTIONS_H #ifndef CPR_SSLOPTIONS_H
#define CPR_SSLOPTIONS_H #define CPR_SSLOPTIONS_H
#include <memory>
#include <string> #include <string>
#include <vector>
#include <cpr/filesystem.h>
#include <curl/curl.h> #include <curl/curl.h>
#include "cpr/util.h"
#include <utility> #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 #ifndef SUPPORT_ALPN
#define SUPPORT_ALPN __LIBCURL_VERSION_GTE(7, 36) #define SUPPORT_ALPN LIBCURL_VERSION_NUM >= 0x072400 // 7.36.0
#endif #endif
#ifndef SUPPORT_NPN #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 #endif
#ifndef SUPPORT_SSLv2 #ifndef SUPPORT_SSLv2
#define SUPPORT_SSLv2 __LIBCURL_VERSION_LT(7, 19) #define SUPPORT_SSLv2 LIBCURL_VERSION_NUM <= 0x071300 // 7.19.0
#endif #endif
#ifndef SUPPORT_SSLv3 #ifndef SUPPORT_SSLv3
#define SUPPORT_SSLv3 __LIBCURL_VERSION_LT(7, 39) #define SUPPORT_SSLv3 LIBCURL_VERSION_NUM <= 0x072700 // 7.39.0
#endif #endif
#ifndef SUPPORT_TLSv1_0 #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 #endif
#ifndef SUPPORT_TLSv1_1 #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 #endif
#ifndef SUPPORT_TLSv1_2 #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 #endif
#ifndef SUPPORT_TLSv1_3 #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 #endif
#ifndef SUPPORT_MAX_TLS_VERSION #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 #endif
#ifndef SUPPORT_MAX_TLSv1_1 #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 #endif
#ifndef SUPPORT_MAX_TLSv1_2 #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 #endif
#ifndef SUPPORT_MAX_TLSv1_3 #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 #endif
#ifndef SUPPORT_TLSv13_CIPHERS #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 #endif
#ifndef SUPPORT_SESSIONID_CACHE #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 #endif
#ifndef SUPPORT_SSL_FALSESTART #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 #endif
#ifndef SUPPORT_SSL_NO_REVOKE #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 #endif
namespace cpr { namespace cpr {
@ -85,9 +88,11 @@ namespace ssl {
class CertFile { class CertFile {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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 { virtual const char* GetCertType() const {
return "PEM"; return "PEM";
@ -99,7 +104,9 @@ using PemCert = CertFile;
class DerCert : public CertFile { class DerCert : public CertFile {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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 { const char* GetCertType() const override {
return "DER"; return "DER";
@ -110,13 +117,16 @@ class DerCert : public CertFile {
class KeyFile { class KeyFile {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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> template <typename FileType, typename PassType>
KeyFile(FileType&& p_filename, PassType p_password) KeyFile(FileType&& p_filename, PassType p_password) : filename(std::forward<FileType>(p_filename)), password(std::move(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; std::string password;
virtual const char* GetKeyType() const { 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; using PemKey = KeyFile;
class DerKey : public KeyFile { class DerKey : public KeyFile {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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> template <typename FileType, typename PassType>
DerKey(FileType&& p_filename, PassType p_password) DerKey(FileType&& p_filename, PassType p_password) : KeyFile(std::forward<FileType>(p_filename), std::move(p_password)) {}
: KeyFile(std::forward<FileType>(p_filename), std::move(p_password)) {}
~DerKey() override = default;
const char* GetKeyType() const override { const char* GetKeyType() const override {
return "DER"; return "DER";
@ -277,27 +310,37 @@ struct MaxTLSv1_3 {};
class CaInfo { class CaInfo {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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 // specify directory holding CA certificates
class CaPath { class CaPath {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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 // specify a Certificate Revocation List file
class Crl { class Crl {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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 // specify ciphers to use for TLS
@ -367,9 +410,14 @@ public:
} // namespace ssl } // namespace ssl
struct SslOptions { struct SslOptions {
// We don't use fs::path here, as this leads to problems using windows
std::string cert_file; std::string cert_file;
std::string cert_type; std::string cert_type;
// We don't use fs::path here, as this leads to problems using windows
std::string key_file; std::string key_file;
#if SUPPORT_CURLOPT_SSLKEY_BLOB
std::string key_blob;
#endif
std::string key_type; std::string key_type;
std::string key_pass; std::string key_pass;
std::string pinned_public_key; std::string pinned_public_key;
@ -389,8 +437,14 @@ struct SslOptions {
#if SUPPORT_MAX_TLS_VERSION #if SUPPORT_MAX_TLS_VERSION
int max_version = CURL_SSLVERSION_MAX_DEFAULT; int max_version = CURL_SSLVERSION_MAX_DEFAULT;
#endif #endif
// We don't use fs::path here, as this leads to problems using windows
std::string ca_info; std::string ca_info;
// We don't use fs::path here, as this leads to problems using windows
std::string ca_path; 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 crl_file;
std::string ciphers; std::string ciphers;
#if SUPPORT_TLSv13_CIPHERS #if SUPPORT_TLSv13_CIPHERS
@ -400,15 +454,29 @@ struct SslOptions {
bool session_id_cache = true; bool session_id_cache = true;
#endif #endif
~SslOptions() noexcept {
#if SUPPORT_CURLOPT_SSLKEY_BLOB
util::secureStringClear(key_blob);
#endif
util::secureStringClear(key_pass);
}
void SetOption(const ssl::CertFile& opt) { void SetOption(const ssl::CertFile& opt) {
cert_file = opt.filename; cert_file = opt.filename.string();
cert_type = opt.GetCertType(); cert_type = opt.GetCertType();
} }
void SetOption(const ssl::KeyFile& opt) { void SetOption(const ssl::KeyFile& opt) {
key_file = opt.filename; key_file = opt.filename.string();
key_type = opt.GetKeyType(); key_type = opt.GetKeyType();
key_pass = opt.password; 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) { void SetOption(const ssl::PinnedPublicKey& opt) {
pinned_public_key = opt.pinned_public_key; pinned_public_key = opt.pinned_public_key;
} }
@ -496,13 +564,18 @@ struct SslOptions {
} }
#endif #endif
void SetOption(const ssl::CaInfo& opt) { void SetOption(const ssl::CaInfo& opt) {
ca_info = opt.filename; ca_info = opt.filename.string();
} }
void SetOption(const ssl::CaPath& opt) { 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) { void SetOption(const ssl::Crl& opt) {
crl_file = opt.filename; crl_file = opt.filename.string();
} }
void SetOption(const ssl::Ciphers& opt) { void SetOption(const ssl::Ciphers& opt) {
ciphers = opt.ciphers; ciphers = opt.ciphers;

View File

@ -1,5 +1,5 @@
#ifndef _CPR_STATUS_CODES #ifndef CPR_STATUS_CODES
#define _CPR_STATUS_CODES #define CPR_STATUS_CODES
#include <cstdint> #include <cstdint>
namespace cpr { namespace cpr {
namespace status { namespace status {

122
vendor/CPR/include/cpr/threadpool.h vendored Normal file
View 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

View File

@ -12,6 +12,8 @@ class Timeout {
Timeout(const std::chrono::milliseconds& duration) : ms{duration} {} Timeout(const std::chrono::milliseconds& duration) : ms{duration} {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Timeout(const std::int32_t& milliseconds) : Timeout{std::chrono::milliseconds(milliseconds)} {} 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. // No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int) // NOLINTNEXTLINE(google-runtime-int)

View File

@ -8,7 +8,7 @@ namespace cpr {
class UnixSocket { class UnixSocket {
public: public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // 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; const char* GetUnixSocketString() const noexcept;

Some files were not shown because too many files have changed in this diff Show More