393 lines
13 KiB
C
393 lines
13 KiB
C
|
#ifndef CPR_API_H
|
||
|
#define CPR_API_H
|
||
|
|
||
|
#include <fstream>
|
||
|
#include <functional>
|
||
|
#include <future>
|
||
|
#include <string>
|
||
|
#include <utility>
|
||
|
|
||
|
#include "cpr/async.h"
|
||
|
#include "cpr/async_wrapper.h"
|
||
|
#include "cpr/auth.h"
|
||
|
#include "cpr/bearer.h"
|
||
|
#include "cpr/cprtypes.h"
|
||
|
#include "cpr/multipart.h"
|
||
|
#include "cpr/multiperform.h"
|
||
|
#include "cpr/payload.h"
|
||
|
#include "cpr/response.h"
|
||
|
#include "cpr/session.h"
|
||
|
#include <cpr/filesystem.h>
|
||
|
|
||
|
namespace cpr {
|
||
|
|
||
|
using AsyncResponse = AsyncWrapper<Response>;
|
||
|
|
||
|
namespace priv {
|
||
|
|
||
|
template <bool processed_header, typename CurrentType>
|
||
|
void set_option_internal(Session& session, CurrentType&& current_option) {
|
||
|
session.SetOption(std::forward<CurrentType>(current_option));
|
||
|
}
|
||
|
|
||
|
template <>
|
||
|
inline void set_option_internal<true, Header>(Session& session, Header&& current_option) {
|
||
|
// Header option was already provided -> Update previous header
|
||
|
session.UpdateHeader(std::forward<Header>(current_option));
|
||
|
}
|
||
|
|
||
|
template <bool processed_header, typename CurrentType, typename... Ts>
|
||
|
void set_option_internal(Session& session, CurrentType&& current_option, Ts&&... ts) {
|
||
|
set_option_internal<processed_header, CurrentType>(session, std::forward<CurrentType>(current_option));
|
||
|
|
||
|
if (std::is_same<CurrentType, Header>::value) {
|
||
|
set_option_internal<true, Ts...>(session, std::forward<Ts>(ts)...);
|
||
|
} else {
|
||
|
set_option_internal<processed_header, Ts...>(session, std::forward<Ts>(ts)...);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
void set_option(Session& session, Ts&&... ts) {
|
||
|
set_option_internal<false, Ts...>(session, std::forward<Ts>(ts)...);
|
||
|
}
|
||
|
|
||
|
// Idea: https://stackoverflow.com/a/19060157
|
||
|
template <typename Tuple, std::size_t... I>
|
||
|
void apply_set_option_internal(Session& session, Tuple&& t, std::index_sequence<I...>) {
|
||
|
set_option(session, std::get<I>(std::forward<Tuple>(t))...);
|
||
|
}
|
||
|
|
||
|
// Idea: https://stackoverflow.com/a/19060157
|
||
|
template <typename Tuple>
|
||
|
void apply_set_option(Session& session, Tuple&& t) {
|
||
|
using Indices = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
|
||
|
apply_set_option_internal(session, std::forward<Tuple>(t), Indices());
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
void setup_multiperform_internal(MultiPerform& multiperform, T&& t) {
|
||
|
std::shared_ptr<Session> session = std::make_shared<Session>();
|
||
|
apply_set_option(*session, t);
|
||
|
multiperform.AddSession(session);
|
||
|
}
|
||
|
|
||
|
template <typename T, typename... Ts>
|
||
|
void setup_multiperform_internal(MultiPerform& multiperform, T&& t, Ts&&... ts) {
|
||
|
std::shared_ptr<Session> session = std::make_shared<Session>();
|
||
|
apply_set_option(*session, t);
|
||
|
multiperform.AddSession(session);
|
||
|
setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
void setup_multiperform(MultiPerform& multiperform, Ts&&... ts) {
|
||
|
setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
}
|
||
|
|
||
|
using session_action_t = cpr::Response (cpr::Session::*)();
|
||
|
|
||
|
template <session_action_t SessionAction, typename T>
|
||
|
void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& parameters) {
|
||
|
std::shared_ptr<std::atomic_bool> cancellation_state = std::make_shared<std::atomic_bool>(false);
|
||
|
|
||
|
std::function<Response(T)> execFn{[cancellation_state](T params) {
|
||
|
if (cancellation_state->load()) {
|
||
|
return Response{};
|
||
|
}
|
||
|
cpr::Session s{};
|
||
|
s.SetCancellationParam(cancellation_state);
|
||
|
apply_set_option(s, std::forward<T>(params));
|
||
|
return std::invoke(SessionAction, s);
|
||
|
}};
|
||
|
responses.emplace_back(GlobalThreadPool::GetInstance()->Submit(std::move(execFn), std::forward<T>(parameters)), std::move(cancellation_state));
|
||
|
}
|
||
|
|
||
|
template <session_action_t SessionAction, typename T, typename... Ts>
|
||
|
void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& head, Ts&&... tail) {
|
||
|
setup_multiasync<SessionAction>(responses, std::forward<T>(head));
|
||
|
if constexpr (sizeof...(Ts) > 0) {
|
||
|
setup_multiasync<SessionAction>(responses, std::forward<Ts>(tail)...);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace priv
|
||
|
|
||
|
// Get methods
|
||
|
template <typename... Ts>
|
||
|
Response Get(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Get();
|
||
|
}
|
||
|
|
||
|
// Get async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse GetAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Get callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto GetCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Post methods
|
||
|
template <typename... Ts>
|
||
|
Response Post(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Post();
|
||
|
}
|
||
|
|
||
|
// Post async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse PostAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Post callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto PostCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Put methods
|
||
|
template <typename... Ts>
|
||
|
Response Put(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Put();
|
||
|
}
|
||
|
|
||
|
// Put async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse PutAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Put callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto PutCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Head methods
|
||
|
template <typename... Ts>
|
||
|
Response Head(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Head();
|
||
|
}
|
||
|
|
||
|
// Head async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse HeadAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Head callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto HeadCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Delete methods
|
||
|
template <typename... Ts>
|
||
|
Response Delete(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Delete();
|
||
|
}
|
||
|
|
||
|
// Delete async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse DeleteAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Delete callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto DeleteCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Options methods
|
||
|
template <typename... Ts>
|
||
|
Response Options(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Options();
|
||
|
}
|
||
|
|
||
|
// Options async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse OptionsAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Options callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto OptionsCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Patch methods
|
||
|
template <typename... Ts>
|
||
|
Response Patch(Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Patch();
|
||
|
}
|
||
|
|
||
|
// Patch async methods
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse PatchAsync(Ts... ts) {
|
||
|
return cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Patch callback methods
|
||
|
template <typename Then, typename... Ts>
|
||
|
// NOLINTNEXTLINE(fuchsia-trailing-return)
|
||
|
auto PatchCallback(Then then, Ts... ts) {
|
||
|
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
|
||
|
}
|
||
|
|
||
|
// Download methods
|
||
|
template <typename... Ts>
|
||
|
Response Download(std::ofstream& file, Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Download(file);
|
||
|
}
|
||
|
|
||
|
// Download async method
|
||
|
template <typename... Ts>
|
||
|
AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) {
|
||
|
return AsyncWrapper{std::async(
|
||
|
std::launch::async,
|
||
|
[](fs::path local_path_, Ts... ts_) {
|
||
|
std::ofstream f(local_path_.c_str());
|
||
|
return Download(f, std::move(ts_)...);
|
||
|
},
|
||
|
std::move(local_path), std::move(ts)...)};
|
||
|
}
|
||
|
|
||
|
// Download with user callback
|
||
|
template <typename... Ts>
|
||
|
Response Download(const WriteCallback& write, Ts&&... ts) {
|
||
|
Session session;
|
||
|
priv::set_option(session, std::forward<Ts>(ts)...);
|
||
|
return session.Download(write);
|
||
|
}
|
||
|
|
||
|
// Multi requests
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiGet(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Get();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiDelete(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Delete();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiPut(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Put();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiHead(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Head();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiOptions(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Options();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiPatch(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Patch();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<Response> MultiPost(Ts&&... ts) {
|
||
|
MultiPerform multiperform;
|
||
|
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
|
||
|
return multiperform.Post();
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiGetAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Get>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiDeleteAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Delete>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiHeadAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Head>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiOptionsAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Options>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiPatchAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Patch>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiPostAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Post>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
template <typename... Ts>
|
||
|
std::vector<AsyncWrapper<Response, true>> MultiPutAsync(Ts&&... ts) {
|
||
|
std::vector<AsyncWrapper<Response, true>> ret{};
|
||
|
priv::setup_multiasync<&cpr::Session::Put>(ret, std::forward<Ts>(ts)...);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
} // namespace cpr
|
||
|
|
||
|
#endif
|