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