1#ifndef CPR_API_H
2#define CPR_API_H
3
4#include <fstream>
5#include <functional>
6#include <future>
7#include <string>
8#include <utility>
9
10#include "cpr/async.h"
11#include "cpr/async_wrapper.h"
12#include "cpr/auth.h"
13#include "cpr/bearer.h"
14#include "cpr/cprtypes.h"
15#include "cpr/multipart.h"
16#include "cpr/multiperform.h"
17#include "cpr/payload.h"
18#include "cpr/response.h"
19#include "cpr/session.h"
20#include <cpr/filesystem.h>
21
22namespace cpr {
23
24using AsyncResponse = AsyncWrapper<Response>;
25
26namespace priv {
27
28template <bool processed_header, typename CurrentType>
29void set_option_internal(Session& session, CurrentType&& current_option) {
30 session.SetOption(std::forward<CurrentType>(current_option));
31}
32
33template <>
34inline void set_option_internal<true, Header>(Session& session, Header&& current_option) {
35 // Header option was already provided -> Update previous header
36 session.UpdateHeader(header: std::forward<Header>(t&: current_option));
37}
38
39template <bool processed_header, typename CurrentType, typename... Ts>
40void set_option_internal(Session& session, CurrentType&& current_option, Ts&&... ts) {
41 set_option_internal<processed_header, CurrentType>(session, std::forward<CurrentType>(current_option));
42
43 if (std::is_same<CurrentType, Header>::value) {
44 set_option_internal<true, Ts...>(session, std::forward<Ts>(ts)...);
45 } else {
46 set_option_internal<processed_header, Ts...>(session, std::forward<Ts>(ts)...);
47 }
48}
49
50template <typename... Ts>
51void set_option(Session& session, Ts&&... ts) {
52 set_option_internal<false, Ts...>(session, std::forward<Ts>(ts)...);
53}
54
55// Idea: https://stackoverflow.com/a/19060157
56template <typename Tuple, std::size_t... I>
57void apply_set_option_internal(Session& session, Tuple&& t, std::index_sequence<I...>) {
58 set_option(session, std::get<I>(std::forward<Tuple>(t))...);
59}
60
61// Idea: https://stackoverflow.com/a/19060157
62template <typename Tuple>
63void apply_set_option(Session& session, Tuple&& t) {
64 using Indices = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
65 apply_set_option_internal(session, std::forward<Tuple>(t), Indices());
66}
67
68template <typename T>
69void setup_multiperform_internal(MultiPerform& multiperform, T&& t) {
70 std::shared_ptr<Session> session = std::make_shared<Session>();
71 apply_set_option(*session, t);
72 multiperform.AddSession(session);
73}
74
75template <typename T, typename... Ts>
76void setup_multiperform_internal(MultiPerform& multiperform, T&& t, Ts&&... ts) {
77 std::shared_ptr<Session> session = std::make_shared<Session>();
78 apply_set_option(*session, t);
79 multiperform.AddSession(session);
80 setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
81}
82
83template <typename... Ts>
84void setup_multiperform(MultiPerform& multiperform, Ts&&... ts) {
85 setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
86}
87
88using session_action_t = cpr::Response (cpr::Session::*)();
89
90template <session_action_t SessionAction, typename T>
91void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& parameters) {
92 std::shared_ptr<std::atomic_bool> cancellation_state = std::make_shared<std::atomic_bool>(args: false);
93
94 std::function<Response(T)> execFn{[cancellation_state](T params) {
95 if (cancellation_state->load()) {
96 return Response{};
97 }
98 cpr::Session s{};
99 s.SetCancellationParam(cancellation_state);
100 apply_set_option(s, std::forward<T>(params));
101 return std::invoke(fn: SessionAction, args&: s);
102 }};
103 responses.emplace_back(GlobalThreadPool::GetInstance()->Submit(std::move(execFn), std::forward<T>(parameters)), std::move(cancellation_state));
104}
105
106template <session_action_t SessionAction, typename T, typename... Ts>
107void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& head, Ts&&... tail) {
108 setup_multiasync<SessionAction>(responses, std::forward<T>(head));
109 if constexpr (sizeof...(Ts) > 0) {
110 setup_multiasync<SessionAction>(responses, std::forward<Ts>(tail)...);
111 }
112}
113
114} // namespace priv
115
116// Get methods
117template <typename... Ts>
118Response Get(Ts&&... ts) {
119 Session session;
120 priv::set_option(session, std::forward<Ts>(ts)...);
121 return session.Get();
122}
123
124// Get async methods
125template <typename... Ts>
126AsyncResponse GetAsync(Ts... ts) {
127 return cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
128}
129
130// Get callback methods
131template <typename Then, typename... Ts>
132// NOLINTNEXTLINE(fuchsia-trailing-return)
133auto GetCallback(Then then, Ts... ts) {
134 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
135}
136
137// Post methods
138template <typename... Ts>
139Response Post(Ts&&... ts) {
140 Session session;
141 priv::set_option(session, std::forward<Ts>(ts)...);
142 return session.Post();
143}
144
145// Post async methods
146template <typename... Ts>
147AsyncResponse PostAsync(Ts... ts) {
148 return cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
149}
150
151// Post callback methods
152template <typename Then, typename... Ts>
153// NOLINTNEXTLINE(fuchsia-trailing-return)
154auto PostCallback(Then then, Ts... ts) {
155 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
156}
157
158// Put methods
159template <typename... Ts>
160Response Put(Ts&&... ts) {
161 Session session;
162 priv::set_option(session, std::forward<Ts>(ts)...);
163 return session.Put();
164}
165
166// Put async methods
167template <typename... Ts>
168AsyncResponse PutAsync(Ts... ts) {
169 return cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
170}
171
172// Put callback methods
173template <typename Then, typename... Ts>
174// NOLINTNEXTLINE(fuchsia-trailing-return)
175auto PutCallback(Then then, Ts... ts) {
176 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
177}
178
179// Head methods
180template <typename... Ts>
181Response Head(Ts&&... ts) {
182 Session session;
183 priv::set_option(session, std::forward<Ts>(ts)...);
184 return session.Head();
185}
186
187// Head async methods
188template <typename... Ts>
189AsyncResponse HeadAsync(Ts... ts) {
190 return cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
191}
192
193// Head callback methods
194template <typename Then, typename... Ts>
195// NOLINTNEXTLINE(fuchsia-trailing-return)
196auto HeadCallback(Then then, Ts... ts) {
197 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
198}
199
200// Delete methods
201template <typename... Ts>
202Response Delete(Ts&&... ts) {
203 Session session;
204 priv::set_option(session, std::forward<Ts>(ts)...);
205 return session.Delete();
206}
207
208// Delete async methods
209template <typename... Ts>
210AsyncResponse DeleteAsync(Ts... ts) {
211 return cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...);
212}
213
214// Delete callback methods
215template <typename Then, typename... Ts>
216// NOLINTNEXTLINE(fuchsia-trailing-return)
217auto DeleteCallback(Then then, Ts... ts) {
218 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
219}
220
221// Options methods
222template <typename... Ts>
223Response Options(Ts&&... ts) {
224 Session session;
225 priv::set_option(session, std::forward<Ts>(ts)...);
226 return session.Options();
227}
228
229// Options async methods
230template <typename... Ts>
231AsyncResponse OptionsAsync(Ts... ts) {
232 return cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...);
233}
234
235// Options callback methods
236template <typename Then, typename... Ts>
237// NOLINTNEXTLINE(fuchsia-trailing-return)
238auto OptionsCallback(Then then, Ts... ts) {
239 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
240}
241
242// Patch methods
243template <typename... Ts>
244Response Patch(Ts&&... ts) {
245 Session session;
246 priv::set_option(session, std::forward<Ts>(ts)...);
247 return session.Patch();
248}
249
250// Patch async methods
251template <typename... Ts>
252AsyncResponse PatchAsync(Ts... ts) {
253 return cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
254}
255
256// Patch callback methods
257template <typename Then, typename... Ts>
258// NOLINTNEXTLINE(fuchsia-trailing-return)
259auto PatchCallback(Then then, Ts... ts) {
260 return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
261}
262
263// Download methods
264template <typename... Ts>
265Response Download(std::ofstream& file, Ts&&... ts) {
266 Session session;
267 priv::set_option(session, std::forward<Ts>(ts)...);
268 return session.Download(file);
269}
270
271// Download async method
272template <typename... Ts>
273AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) {
274 return AsyncWrapper{std::async(
275 std::launch::async,
276 [](fs::path local_path_, Ts... ts_) {
277 std::ofstream f(local_path_.c_str());
278 return Download(f, std::move(ts_)...);
279 },
280 std::move(local_path), std::move(ts)...)};
281}
282
283// Download with user callback
284template <typename... Ts>
285Response Download(const WriteCallback& write, Ts&&... ts) {
286 Session session;
287 priv::set_option(session, std::forward<Ts>(ts)...);
288 return session.Download(write);
289}
290
291// Multi requests
292template <typename... Ts>
293std::vector<Response> MultiGet(Ts&&... ts) {
294 MultiPerform multiperform;
295 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
296 return multiperform.Get();
297}
298
299template <typename... Ts>
300std::vector<Response> MultiDelete(Ts&&... ts) {
301 MultiPerform multiperform;
302 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
303 return multiperform.Delete();
304}
305
306template <typename... Ts>
307std::vector<Response> MultiPut(Ts&&... ts) {
308 MultiPerform multiperform;
309 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
310 return multiperform.Put();
311}
312
313template <typename... Ts>
314std::vector<Response> MultiHead(Ts&&... ts) {
315 MultiPerform multiperform;
316 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
317 return multiperform.Head();
318}
319
320template <typename... Ts>
321std::vector<Response> MultiOptions(Ts&&... ts) {
322 MultiPerform multiperform;
323 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
324 return multiperform.Options();
325}
326
327template <typename... Ts>
328std::vector<Response> MultiPatch(Ts&&... ts) {
329 MultiPerform multiperform;
330 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
331 return multiperform.Patch();
332}
333
334template <typename... Ts>
335std::vector<Response> MultiPost(Ts&&... ts) {
336 MultiPerform multiperform;
337 priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
338 return multiperform.Post();
339}
340
341template <typename... Ts>
342std::vector<AsyncWrapper<Response, true>> MultiGetAsync(Ts&&... ts) {
343 std::vector<AsyncWrapper<Response, true>> ret{};
344 priv::setup_multiasync<&cpr::Session::Get>(ret, std::forward<Ts>(ts)...);
345 return ret;
346}
347
348template <typename... Ts>
349std::vector<AsyncWrapper<Response, true>> MultiDeleteAsync(Ts&&... ts) {
350 std::vector<AsyncWrapper<Response, true>> ret{};
351 priv::setup_multiasync<&cpr::Session::Delete>(ret, std::forward<Ts>(ts)...);
352 return ret;
353}
354
355template <typename... Ts>
356std::vector<AsyncWrapper<Response, true>> MultiHeadAsync(Ts&&... ts) {
357 std::vector<AsyncWrapper<Response, true>> ret{};
358 priv::setup_multiasync<&cpr::Session::Head>(ret, std::forward<Ts>(ts)...);
359 return ret;
360}
361template <typename... Ts>
362std::vector<AsyncWrapper<Response, true>> MultiOptionsAsync(Ts&&... ts) {
363 std::vector<AsyncWrapper<Response, true>> ret{};
364 priv::setup_multiasync<&cpr::Session::Options>(ret, std::forward<Ts>(ts)...);
365 return ret;
366}
367
368template <typename... Ts>
369std::vector<AsyncWrapper<Response, true>> MultiPatchAsync(Ts&&... ts) {
370 std::vector<AsyncWrapper<Response, true>> ret{};
371 priv::setup_multiasync<&cpr::Session::Patch>(ret, std::forward<Ts>(ts)...);
372 return ret;
373}
374
375template <typename... Ts>
376std::vector<AsyncWrapper<Response, true>> MultiPostAsync(Ts&&... ts) {
377 std::vector<AsyncWrapper<Response, true>> ret{};
378 priv::setup_multiasync<&cpr::Session::Post>(ret, std::forward<Ts>(ts)...);
379 return ret;
380}
381
382template <typename... Ts>
383std::vector<AsyncWrapper<Response, true>> MultiPutAsync(Ts&&... ts) {
384 std::vector<AsyncWrapper<Response, true>> ret{};
385 priv::setup_multiasync<&cpr::Session::Put>(ret, std::forward<Ts>(ts)...);
386 return ret;
387}
388
389
390} // namespace cpr
391
392#endif
393