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  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 
43  {
46  };
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  {
84  friend bool operator==(BaseJob::Delete, BaseJob::Delete) = default;
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 
110  enum ReturnType {
113  };
114 
115  BaseJob(std::string serverUrl,
116  std::string requestUrl,
117  Method method,
118  std::string jobId,
119  std::string token = {},
120  ReturnType returnType = ReturnType::Json,
121  Body body = EmptyBody{},
122  Query query = {},
123  Header header = {},
124  std::optional<FileDesc> responseFile = std::nullopt);
125 
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 
147  Response genResponse(Response r) const;
148 
149  BaseJob withData(JsonWrap j) &&;
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;
159  JobQueuePolicy queuePolicy() 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
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:87
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:213
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