Unity Scopes API
HttpAsyncReader.h
1 /*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of version 3 of the GNU Lesser General Public License as published
6 * by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11 * details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Xavi Garcia <xavi.garcia.mena@canonical.com>
17 */
18 #pragma once
19 
20 #ifndef _ENABLE_QT_EXPERIMENTAL_
21 #error You should define _ENABLE_QT_EXPERIMENTAL_ in order to use this experimental header file.
22 #endif
23 
24 #include <unity/util/DefinesPtrs.h>
25 #include <unity/util/NonCopyable.h>
26 #include <unity/UnityExceptions.h>
27 
28 #include <unity/scopes/ScopeExceptions.h>
29 
30 #include <core/net/http/client.h>
31 #include <core/net/http/request.h>
32 #include <core/net/http/response.h>
33 
34 #include <deque>
35 #include <future>
36 #include <memory>
37 #include <vector>
38 
39 namespace unity
40 {
41 
42 namespace scopes
43 {
44 
45 namespace qt
46 {
47 
56 {
57 public:
59  NONCOPYABLE(HttpAsyncReader);
60  UNITY_DEFINES_PTRS(HttpAsyncReader);
61 
62  // aliases
63  template <typename PARSER>
64  using FactoryFunc = std::function<std::shared_ptr<PARSER>(const std::string&, std::string&)>;
65 
66  template <typename TYPE, typename PARSER>
67  using ParseFunc =
68  std::function<bool(PARSER& root, const std::string&, std::deque<std::shared_ptr<TYPE>>&, std::string&)>;
69 
70  template <typename TYPE>
71  using ResultsList = std::deque<std::shared_ptr<TYPE>>;
72 
73  template <typename TYPE>
74  using ResultsFuture = std::future<ResultsList<TYPE>>;
75 
76  template <typename PARSER>
77  using ParserFuture = std::future<std::shared_ptr<PARSER>>;
78 
80 
81  virtual ~HttpAsyncReader();
83 
108  template <typename BASE, typename TYPE, typename PARSER>
109  ResultsFuture<BASE> async_get(std::string const& uri,
110  std::string const& object_name,
111  FactoryFunc<PARSER> const& create,
112  ParseFunc<BASE, PARSER> const& parse) const;
113 
132  template <typename TYPE, typename PARSER>
133  ResultsFuture<TYPE> async_get(std::string const& uri,
134  std::string const& object_name,
135  FactoryFunc<PARSER> const& create,
136  ParseFunc<TYPE, PARSER> const& parse) const;
137 
148  template <typename PARSER>
149  ParserFuture<PARSER> async_get_parser(std::string const& uri, FactoryFunc<PARSER> const& create) const;
150 
161  template <typename T>
162  static T get_or_throw(std::future<T>& f, int64_t seconds = 10);
163 
168  std::string get_uri(std::string const& host,
169  std::vector<std::pair<std::string, std::string>> const& parameters) const;
170 
171 protected:
173  core::net::http::Request::Progress::Next progress_report(core::net::http::Request::Progress const& progress) const;
174 
175  void async_execute(core::net::http::Request::Handler const& handler, std::string const& uri) const;
176 
177  class Priv;
178  std::shared_ptr<Priv> p_;
180 };
181 
182 template <typename BASE, typename TYPE, typename PARSER>
183 HttpAsyncReader::ResultsFuture<BASE> HttpAsyncReader::async_get(std::string const& uri,
184  std::string const& object_name,
185  FactoryFunc<PARSER> const& create,
186  ParseFunc<BASE, PARSER> const& parse) const
187 {
188  static_assert(std::is_base_of<BASE, TYPE>::value,
189  "Second template parameter type must be a valid base class of the first one.");
190 
191  auto prom = std::make_shared<std::promise<std::deque<std::shared_ptr<BASE>>>>();
192  core::net::http::Request::Handler handler;
193 
194  handler.on_progress(bind(&HttpAsyncReader::progress_report, this, std::placeholders::_1));
195 
196  handler.on_error([prom, uri](core::net::Error const& e)
197  {
198  unity::LogicException logic_exception("AsyncReader::async_get: " + std::string(e.what()) +
199  "( uri = " + uri + " )");
200  prom->set_exception(logic_exception.self());
201  });
202 
203  handler.on_response(
204  [prom, object_name, parse, create, uri](core::net::http::Response const& response)
205  {
206  if (response.status != core::net::http::Status::ok)
207  {
208  unity::LogicException e("AsyncReader::async_get: " + response.body + "( uri = " + uri + " )");
209  prom->set_exception(e.self());
210  }
211  else
212  {
213  std::string error_string;
214  std::shared_ptr<PARSER> reader = create(response.body, error_string);
215  if (!reader)
216  {
217  unity::LogicException e("AsyncReader::async_get: error obtaining parser: " + error_string);
218  prom->set_exception(e.self());
219  }
220  else
221  {
222  std::deque<std::shared_ptr<BASE>> results;
223  std::string error_message;
224  if (!parse(*reader, object_name, results, error_message))
225  {
226  unity::LogicException e("AsyncReader::async_get: error parsing data: " + error_message);
227  prom->set_exception(e.self());
228  }
229  else
230  {
231  prom->set_value(results);
232  }
233  }
234  }
235  });
236 
237  async_execute(handler, uri);
238 
239  return prom->get_future();
240 }
241 
242 template <typename TYPE, typename PARSER>
243 HttpAsyncReader::ResultsFuture<TYPE> HttpAsyncReader::async_get(std::string const& uri,
244  std::string const& object_name,
245  FactoryFunc<PARSER> const& create,
246  ParseFunc<TYPE, PARSER> const& parse) const
247 {
248  return async_get<TYPE, TYPE, PARSER>(uri, object_name, create, parse);
249 }
250 
251 template <typename PARSER>
252 HttpAsyncReader::ParserFuture<PARSER> HttpAsyncReader::async_get_parser(std::string const& uri,
253  FactoryFunc<PARSER> const& create) const
254 {
255  auto prom = std::make_shared<std::promise<std::shared_ptr<PARSER>>>();
256  core::net::http::Request::Handler handler;
257  handler.on_progress(bind(&HttpAsyncReader::progress_report, this, std::placeholders::_1));
258 
259  handler.on_error([prom, uri](core::net::Error const& e)
260  {
261  unity::LogicException logic_exception("AsyncReader::async_get: " + std::string(e.what()) +
262  "( uri = " + uri + " )");
263  prom->set_exception(logic_exception.self());
264  });
265 
266  handler.on_response(
267  [this, prom, create, uri](core::net::http::Response const& response)
268  {
269  if (response.status != core::net::http::Status::ok)
270  {
271  unity::LogicException e("AsyncReader::async_get_parser: " + response.body + "( uri = " + uri + " )");
272  prom->set_exception(e.self());
273  }
274  else
275  {
276  std::string error_string;
277  std::shared_ptr<PARSER> reader = create(response.body, error_string);
278  if (!reader)
279  {
280  unity::LogicException e("AsyncReader::async_get: error obtaining parser: " + error_string);
281  prom->set_exception(e.self());
282  }
283  else
284  {
285  prom->set_value(reader);
286  }
287  }
288  });
289 
290  async_execute(handler, uri);
291 
292  return prom->get_future();
293 }
294 
295 template <typename T>
296 T HttpAsyncReader::get_or_throw(std::future<T>& f, int64_t seconds)
297 {
298  if (f.wait_for(std::chrono::seconds(seconds)) != std::future_status::ready)
299  {
300  throw unity::scopes::TimeoutException("AsyncReader::get_or_throw: Wait for future timeout after " +
301  std::to_string(seconds) + " seconds");
302  }
303  return f.get();
304 }
305 
306 } // namespace qt
307 
308 } // namespace scopes
309 
310 } // namespace unity
Definition: HttpAsyncReader.h:45
ResultsFuture< BASE > async_get(std::string const &uri, std::string const &object_name, FactoryFunc< PARSER > const &create, ParseFunc< BASE, PARSER > const &parse) const
Downloads a HTTP remote file asynchronously and returns a future to a list of results This method dow...
Definition: HttpAsyncReader.h:183
ParserFuture< PARSER > async_get_parser(std::string const &uri, FactoryFunc< PARSER > const &create) const
Downloads a HTTP remote file asynchronously and returns a future to a valid parser containing the dat...
Definition: HttpAsyncReader.h:252
Top-level namespace for all things Unity-related.
Definition: Version.h:49
static T get_or_throw(std::future< T > &f, int64_t seconds=10)
Gets the data of the given future in the gived timeout. If the time given expires and the data in the...
Definition: HttpAsyncReader.h:296
Class that downloads http files asynchronously.
Definition: HttpAsyncReader.h:55
std::string get_uri(std::string const &host, std::vector< std::pair< std::string, std::string >> const &parameters) const
Constructs a URI with the given host and parameters. This is a convenience method that constructs a u...
Definition: HttpAsyncReader.cpp:87
Exception to indicate that a twoway request timed out.
Definition: ScopeExceptions.h:108