libkazv
Loading...
Searching...
No Matches
basejob.hpp
Go to the documentation of this file.
1/*
2 * This file is part of libkazv.
3 * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
4 * SPDX-License-Identifier: AGPL-3.0-or-later
5 */
6
7
8#pragma once
9#include "libkazv-config.hpp"
10
11#include <optional>
12#include <variant>
13#include <tuple>
14#include <functional>
15#include <string>
16#include <map>
17#include <future>
18#include <immer/map.hpp>
19#include <immer/array.hpp>
20#include <immer/box.hpp>
21
22#include "types.hpp"
23#include "copy-helper.hpp"
24#include "file-desc.hpp"
25
26namespace Kazv
27{
28 using Header = immer::box<std::map<std::string, std::string>>;
29
33 struct EmptyBody {
34 friend bool operator==(EmptyBody, EmptyBody) = default;
35 };
36 using Body = std::variant<EmptyBody, JsonBody, BytesBody, FileBody>;
37
38 inline bool isBodyJson(Body body) {
39 return std::holds_alternative<JsonBody>(body);
40 };
41
47
48 struct Response
49 {
50 using StatusCode = int;
55 std::string errorCode() const;
56 std::string errorMessage() const;
57 JsonWrap jsonBody() const;
58 constexpr bool success() const {
59 return statusCode < 400;
60 }
61 json dataJson(const std::string &key) const;
62 std::string dataStr(const std::string &key) const;
63 std::string jobId() const;
64 friend bool operator==(const Response &a, const Response &b) = default;
65 };
66
67 class BaseJob
68 {
69 public:
70 struct Get
71 {
72 friend bool operator==(BaseJob::Get, BaseJob::Get) = default;
73 };
74 struct Post
75 {
76 friend bool operator==(BaseJob::Post, BaseJob::Post) = default;
77 };
78 struct Put
79 {
80 friend bool operator==(BaseJob::Put, BaseJob::Put) = default;
81 };
82 struct Delete
83 {
85 };
86 using Method = std::variant<Get, Post, Put, Delete>;
87
88 static Get GET;
89 static Post POST;
90 static Put PUT;
91 static Delete DELETE;
92
93 class Query : public std::vector<std::pair<std::string, std::string>>
94 {
95 using BaseT = std::vector<std::pair<std::string, std::string>>;
96 public:
97 using BaseT::BaseT;
98 void add(std::string k, std::string v) {
99 push_back({k, v});
100 }
101 };
102
109
113 };
114
115 BaseJob(std::string serverUrl,
116 std::string requestUrl,
117 Method method,
118 std::string jobId,
119 std::string token = {},
121 Body body = EmptyBody{},
122 Query query = {},
123 Header header = {},
124 std::optional<FileDesc> responseFile = std::nullopt);
125
126 KAZV_DECLARE_COPYABLE(BaseJob)
127
129
130 bool shouldReturnJson() const;
131
132 std::string url() const;
133
134 Body requestBody() const;
135
136 Header requestHeader() const;
137
138 ReturnType returnType() const;
139
141 Query requestQuery() const;
142
143 Method requestMethod() const;
144
145 static bool contentTypeMatches(immer::array<std::string> expected, std::string actual);
146
148
150 BaseJob withData(JsonWrap j) const &;
151
152 BaseJob withQueue(std::string id, JobQueuePolicy policy = AlwaysContinue) &&;
153 BaseJob withQueue(std::string id, JobQueuePolicy policy = AlwaysContinue) const &;
154
155 json dataJson(const std::string &key) const;
156 std::string dataStr(const std::string &key) const;
157 std::string jobId() const;
158 std::optional<std::string> queueId() const;
160
161 std::optional<FileDesc> responseFile() const;
162
163 protected:
164 void attachData(JsonWrap data);
165
166 private:
167 friend bool operator==(const BaseJob &a, const BaseJob &b);
168 friend bool operator!=(const BaseJob &a, const BaseJob &b);
169 struct Private;
170 std::unique_ptr<Private> m_d;
171 };
172
173 namespace detail
174 {
175 template<class T>
176 struct AddToQueryT
177 {
178 template<class U>
179 static void call(BaseJob::Query &q, std::string name, U &&arg) {
180 q.add(name, std::to_string(std::forward<U>(arg)));
181 }
182 };
183
184 template<>
185 struct AddToQueryT<std::string>
186 {
187 template<class U>
188 static void call(BaseJob::Query &q, std::string name, U &&arg) {
189 q.add(name, std::forward<U>(arg));
190 }
191 };
192
193 template<>
194 struct AddToQueryT<bool>
195 {
196 template<class U>
197 static void call(BaseJob::Query &q, std::string name, U &&arg) {
198 q.add(name, std::forward<U>(arg) ? "true"s : "false"s);
199 }
200 };
201
202 template<class T>
203 struct AddToQueryT<immer::array<T>>
204 {
205 template<class U>
206 static void call(BaseJob::Query &q, std::string name, U &&arg) {
207 for (auto v : std::forward<U>(arg)) {
208 q.add(name, v);
209 }
210 }
211 };
212
213 template<>
214 struct AddToQueryT<json>
215 {
216 // https://github.com/nlohmann/json/issues/2040
217 static void call(BaseJob::Query &q, std::string /* name */, const json &arg) {
218 // assume v is string type
219 for (auto [k, v] : arg.items()) {
220 q.add(k, v);
221 }
222 }
223 };
224 }
225
226 template<class T>
227 inline void addToQuery(BaseJob::Query &q, std::string name, T &&arg)
228 {
229 detail::AddToQueryT<std::decay_t<T>>::call(q, name, std::forward<T>(arg));
230 }
231
232 namespace detail
233 {
234 template<class T>
235 struct AddToQueryIfNeededT
236 {
237 template<class U>
238 static void call(BaseJob::Query &q, std::string name, U &&arg) {
239 using ArgT = std::decay_t<U>;
240 if constexpr (detail::hasEmptyMethod(boost::hana::type_c<ArgT>)) {
241 if (! arg.empty()) {
242 addToQuery(q, name, std::forward<U>(arg));
243 }
244 } else {
245 addToQuery(q, name, std::forward<U>(arg));
246 }
247 }
248 };
249
250 template<class T>
251 struct AddToQueryIfNeededT<std::optional<T>>
252 {
253 template<class U>
254 static void call(BaseJob::Query &q, std::string name, U &&arg) {
255 if (arg.has_value()) {
256 addToQuery(q, name, std::forward<U>(arg).value());
257 }
258 }
259 };
260 }
261
262 template<class T>
263 inline void addToQueryIfNeeded(BaseJob::Query &q, std::string name, T &&arg)
264 {
265 detail::AddToQueryIfNeededT<std::decay_t<T>>::call(q, name, std::forward<T>(arg));
266 }
267
268}
Definition basejob.hpp:94
void add(std::string k, std::string v)
Definition basejob.hpp:98
Definition basejob.hpp:68
static bool contentTypeMatches(immer::array< std::string > expected, std::string actual)
Definition basejob.cpp:162
friend bool operator==(const BaseJob &a, const BaseJob &b)
Definition basejob.cpp:282
std::optional< std::string > queueId() const
Definition basejob.cpp:240
static Post POST
Definition basejob.hpp:89
Method requestMethod() const
Definition basejob.cpp:136
std::variant< Get, Post, Put, Delete > Method
Definition basejob.hpp:86
json dataJson(const std::string &key) const
Definition basejob.cpp:225
BaseJob withData(JsonWrap j) &&
Definition basejob.cpp:195
std::string url() const
Definition basejob.cpp:111
Header requestHeader() const
Definition basejob.cpp:121
std::optional< FileDesc > responseFile() const
Definition basejob.cpp:250
void attachData(JsonWrap data)
Definition basejob.cpp:190
JobQueuePolicy queuePolicy() const
Definition basejob.cpp:245
BaseJob withQueue(std::string id, JobQueuePolicy policy=AlwaysContinue) &&
Definition basejob.cpp:209
static Delete DELETE
Definition basejob.hpp:91
::Kazv::BytesBody BytesBody
Definition basejob.hpp:104
std::string jobId() const
Definition basejob.cpp:235
::Kazv::Header Header
Definition basejob.hpp:107
::Kazv::EmptyBody EmptyBody
Definition basejob.hpp:106
Body requestBody() const
Definition basejob.cpp:116
bool shouldReturnJson() const
Definition basejob.cpp:106
friend bool operator!=(const BaseJob &a, const BaseJob &b)
Definition basejob.cpp:290
Query requestQuery() const
returns the non-encoded query as an array of pairs
Definition basejob.cpp:131
static Put PUT
Definition basejob.hpp:90
::Kazv::Body Body
Definition basejob.hpp:103
static Get GET
Definition basejob.hpp:88
ReturnType
Definition basejob.hpp:110
@ Json
Definition basejob.hpp:111
@ File
Definition basejob.hpp:112
Response genResponse(Response r) const
Definition basejob.cpp:182
ReturnType returnType() const
Definition basejob.cpp:126
std::string dataStr(const std::string &key) const
Definition basejob.cpp:230
Definition file-desc.hpp:225
Definition jsonwrap.hpp:23
#define KAZV_DECLARE_COPYABLE(typeName)
Definition copy-helper.hpp:10
constexpr auto hasEmptyMethod
Definition types.hpp:37
Definition location.hpp:10
Bytes BytesBody
Definition basejob.hpp:30
void addToQueryIfNeeded(BaseJob::Query &q, std::string name, T &&arg)
Definition basejob.hpp:263
std::variant< EmptyBody, JsonBody, BytesBody, FileBody > Body
Definition basejob.hpp:36
bool isBodyJson(Body body)
Definition basejob.hpp:38
nlohmann::json json
Definition jsonwrap.hpp:20
std::string Bytes
Definition types.hpp:27
JobQueuePolicy
Definition basejob.hpp:43
@ CancelFutureIfFailed
Definition basejob.hpp:45
@ AlwaysContinue
Definition basejob.hpp:44
void addToQuery(BaseJob::Query &q, std::string name, T &&arg)
Definition basejob.hpp:227
JsonWrap JsonBody
Definition basejob.hpp:31
immer::box< std::map< std::string, std::string > > Header
Definition basejob.hpp:28
Definition clientutil.hpp:140
Definition basejob.hpp:83
friend bool operator==(BaseJob::Delete, BaseJob::Delete)=default
Definition basejob.hpp:71
friend bool operator==(BaseJob::Get, BaseJob::Get)=default
Definition basejob.hpp:75
friend bool operator==(BaseJob::Post, BaseJob::Post)=default
Definition basejob.cpp:24
Definition basejob.hpp:79
friend bool operator==(BaseJob::Put, BaseJob::Put)=default
Definition basejob.hpp:33
friend bool operator==(EmptyBody, EmptyBody)=default
Definition basejob.hpp:49
Header header
Definition basejob.hpp:53
std::string errorCode() const
Definition basejob.cpp:255
std::string jobId() const
Definition basejob.cpp:156
JsonWrap extraData
Definition basejob.hpp:54
int StatusCode
Definition basejob.hpp:50
constexpr bool success() const
Definition basejob.hpp:58
JsonWrap jsonBody() const
Definition basejob.cpp:141
std::string dataStr(const std::string &key) const
Definition basejob.cpp:151
StatusCode statusCode
Definition basejob.hpp:51
Body body
Definition basejob.hpp:52
json dataJson(const std::string &key) const
Definition basejob.cpp:146
friend bool operator==(const Response &a, const Response &b)=default
std::string errorMessage() const
Definition basejob.cpp:270