1#ifndef CPR_MULTIPERFORM_H
2#define CPR_MULTIPERFORM_H
3
4#include "cpr/curlmultiholder.h"
5#include "cpr/response.h"
6#include "cpr/session.h"
7#include <functional>
8#include <memory>
9#include <queue>
10#include <stdexcept>
11#include <vector>
12
13namespace cpr {
14
15class InterceptorMulti;
16
17class MultiPerform {
18 public:
19 enum class HttpMethod {
20 UNDEFINED = 0,
21 GET_REQUEST,
22 POST_REQUEST,
23 PUT_REQUEST,
24 DELETE_REQUEST,
25 PATCH_REQUEST,
26 HEAD_REQUEST,
27 OPTIONS_REQUEST,
28 DOWNLOAD_REQUEST,
29 };
30
31 MultiPerform();
32 MultiPerform(const MultiPerform& other) = delete;
33 MultiPerform(MultiPerform&& old) = default;
34 ~MultiPerform();
35
36 MultiPerform& operator=(const MultiPerform& other) = delete;
37 MultiPerform& operator=(MultiPerform&& old) noexcept = default;
38
39 std::vector<Response> Get();
40 std::vector<Response> Delete();
41 template <typename... DownloadArgTypes>
42 std::vector<Response> Download(DownloadArgTypes... args);
43 std::vector<Response> Put();
44 std::vector<Response> Head();
45 std::vector<Response> Options();
46 std::vector<Response> Patch();
47 std::vector<Response> Post();
48
49 std::vector<Response> Perform();
50 template <typename... DownloadArgTypes>
51 std::vector<Response> PerformDownload(DownloadArgTypes... args);
52
53 void AddSession(std::shared_ptr<Session>& session, HttpMethod method = HttpMethod::UNDEFINED);
54 void RemoveSession(const std::shared_ptr<Session>& session);
55 std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>>& GetSessions();
56 [[nodiscard]] const std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>>& GetSessions() const;
57
58 void AddInterceptor(const std::shared_ptr<InterceptorMulti>& pinterceptor);
59
60 private:
61 // Interceptors should be able to call the private proceed() and PrepareDownloadSessions() functions
62 friend InterceptorMulti;
63
64 void SetHttpMethod(HttpMethod method);
65
66 void PrepareSessions();
67 template <typename CurrentDownloadArgType, typename... DownloadArgTypes>
68 void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args);
69 template <typename CurrentDownloadArgType>
70 void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg);
71 void PrepareDownloadSession(size_t sessions_index, std::ofstream& file);
72 void PrepareDownloadSession(size_t sessions_index, const WriteCallback& write);
73
74 void PrepareGet();
75 void PrepareDelete();
76 void PreparePut();
77 void PreparePatch();
78 void PrepareHead();
79 void PrepareOptions();
80 void PreparePost();
81 template <typename... DownloadArgTypes>
82 void PrepareDownload(DownloadArgTypes... args);
83
84 std::vector<Response> intercept();
85 std::vector<Response> proceed();
86 std::vector<Response> MakeRequest();
87 std::vector<Response> MakeDownloadRequest();
88
89 void DoMultiPerform();
90 std::vector<Response> ReadMultiInfo(std::function<Response(Session&, CURLcode)>&& complete_function);
91
92 std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>> sessions_;
93 std::unique_ptr<CurlMultiHolder> multicurl_;
94 bool is_download_multi_perform{false};
95
96 std::queue<std::shared_ptr<InterceptorMulti>> interceptors_;
97};
98
99template <typename CurrentDownloadArgType>
100void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg) {
101 PrepareDownloadSession(sessions_index, current_arg);
102}
103
104template <typename CurrentDownloadArgType, typename... DownloadArgTypes>
105void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args) {
106 PrepareDownloadSession(sessions_index, current_arg);
107 PrepareDownloadSessions<DownloadArgTypes...>(sessions_index + 1, args...);
108}
109
110
111template <typename... DownloadArgTypes>
112void MultiPerform::PrepareDownload(DownloadArgTypes... args) {
113 SetHttpMethod(HttpMethod::DOWNLOAD_REQUEST);
114 PrepareDownloadSessions<DownloadArgTypes...>(0, args...);
115}
116
117template <typename... DownloadArgTypes>
118std::vector<Response> MultiPerform::Download(DownloadArgTypes... args) {
119 if (sizeof...(args) != sessions_.size()) {
120 throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!");
121 }
122 PrepareDownload(args...);
123 return MakeDownloadRequest();
124}
125
126template <typename... DownloadArgTypes>
127std::vector<Response> MultiPerform::PerformDownload(DownloadArgTypes... args) {
128 if (sizeof...(args) != sessions_.size()) {
129 throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!");
130 }
131 PrepareDownloadSessions<DownloadArgTypes...>(0, args...);
132 return MakeDownloadRequest();
133}
134
135} // namespace cpr
136
137#endif