ledger-core
HttpClient.hpp
1 /*
2  *
3  * HttpClient
4  * ledger-core
5  *
6  * Created by Pierre Pollastri on 30/11/2016.
7  *
8  * The MIT License (MIT)
9  *
10  * Copyright (c) 2016 Ledger
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  * copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *
30  */
31 #ifndef LEDGER_CORE_HTTPCLIENT_HPP
32 #define LEDGER_CORE_HTTPCLIENT_HPP
33 
34 #include "../api/HttpClient.hpp"
35 #include "../api/HttpMethod.hpp"
36 #include "../api/HttpRequest.hpp"
37 #include "../api/HttpUrlConnection.hpp"
38 #include "../api/HttpReadBodyResult.hpp"
39 #include "../api/ExecutionContext.hpp"
40 #include "../utils/optional.hpp"
41 #include <unordered_map>
42 #include <memory>
43 #include "../async/Future.hpp"
44 #include "../async/Promise.hpp"
45 #include "../utils/Either.hpp"
46 #include "HttpUrlConnectionInputStream.hpp"
47 
48 #include "../debug/logger.hpp"
49 #include "../utils/Option.hpp"
50 
51 #include <rapidjson/document.h>
52 #include <rapidjson/reader.h>
53 
54 namespace ledger {
55  namespace core {
56 
57  template <typename Success, typename Failure, class Handler>
59 
60  class HttpRequest : public std::enable_shared_from_this<HttpRequest> {
61  public:
62  using JsonResult = std::tuple<std::shared_ptr<api::HttpUrlConnection>, std::shared_ptr<rapidjson::Document>>;
63 
64  HttpRequest(api::HttpMethod method,
65  const std::string& url,
66  const std::unordered_map<std::string, std::string>& headers,
67  const std::experimental::optional<std::vector<uint8_t >> body,
68  const std::shared_ptr<api::HttpClient> &client,
69  const std::shared_ptr<api::ExecutionContext> &context,
70  const Option<std::shared_ptr<spdlog::logger>>& logger);
72 
73  template <typename Success, typename Failure, typename Handler>
74  Future<Either<Failure, std::shared_ptr<Success>>> json(Handler handler) const {
75  return operator()().recover(_context, [] (const Exception& exception) {
76  if (exception.getErrorCode() == api::ErrorCode::HTTP_ERROR && exception.getUserData().nonEmpty()) {
77  return std::static_pointer_cast<api::HttpUrlConnection>(exception.getUserData().getValue());
78  }
79  throw exception;
80  }).template map<Either<Failure, std::shared_ptr<Success>>>(_context, [handler] (const std::shared_ptr<api::HttpUrlConnection>& c) -> Either<Failure, std::shared_ptr<Success>> {
81  Handler h = handler;
82  std::shared_ptr<api::HttpUrlConnection> connection = c;
83  h.attach(connection);
84  HttpUrlConnectionInputStream is(connection);
85  rapidjson::Reader reader;
86  reader.Parse<rapidjson::ParseFlag::kParseNumbersAsStringsFlag>(is, h);
87  return (Either<Failure, std::shared_ptr<Success>>) h.build();
88  });
89  }
90 
91  Future<JsonResult> json(bool parseNumbersAsString = false) const;
92  std::shared_ptr<api::HttpRequest> toApiRequest() const;
93 
94 
95  private:
96  api::HttpMethod _method;
97  std::string _url;
98  std::unordered_map<std::string, std::string> _headers;
100  std::shared_ptr<api::HttpClient> _client;
101  std::shared_ptr<api::ExecutionContext> _context;
103 
104  class ApiRequest : public api::HttpRequest {
105  public:
106  ApiRequest(const std::shared_ptr<const ledger::core::HttpRequest>& self);
107  virtual api::HttpMethod getMethod() override;
108 
109  virtual std::unordered_map<std::string, std::string> getHeaders() override;
110 
111  virtual std::vector<uint8_t> getBody() override;
112 
113  virtual std::string getUrl() override;
114 
115  virtual ~ApiRequest();
116 
117  virtual void complete(const std::shared_ptr<api::HttpUrlConnection> &response,
118  const optional<api::Error> &error) override;
119 
121 
122  private:
123  std::shared_ptr<const ledger::core::HttpRequest> _self;
125  };
126  };
127 
128  class HttpClient {
129  public:
130  HttpClient(const std::string& baseUrl,
131  const std::shared_ptr<api::HttpClient> &client,
132  const std::shared_ptr<api::ExecutionContext> &context
133  );
134  HttpRequest GET(const std::string& path,
135  const std::unordered_map<std::string, std::string>& headers = {},
136  const std::string &baseUrl = "");
137  HttpRequest PUT(const std::string& path, const std::vector<uint8_t> &body, const std::unordered_map<std::string, std::string>& headers = {});
138  HttpRequest DEL(const std::string& path, const std::unordered_map<std::string, std::string>& headers = {});
139  HttpRequest POST(const std::string& path,
140  const std::vector<uint8_t> &body,
141  const std::unordered_map<std::string, std::string>& headers = {},
142  const std::string &baseUrl = "");
143  HttpClient& addHeader(const std::string& key, const std::string& value);
144  HttpClient& removeHeader(const std::string& key);
145  void setLogger(const std::shared_ptr<spdlog::logger>& logger);
146 
147  private:
148  HttpRequest createRequest(api::HttpMethod method,
149  const std::string& path,
150  const std::experimental::optional<std::vector<uint8_t >> body,
151  const std::unordered_map<std::string, std::string>& headers,
152  const std::string &baseUrl = "");
153 
154  private:
155  std::string _baseUrl;
156  std::shared_ptr<api::HttpClient> _client;
157  std::shared_ptr<api::ExecutionContext> _context;
158  std::unordered_map<std::string, std::string> _headers;
160  };
161  }
162 }
163 
164 
165 #endif //LEDGER_CORE_HTTPCLIENT_HPP
Definition: HttpClient.hpp:58
Definition: Either.hpp:43
a class to store JSON values
Definition: json.hpp:231
Definition: Option.hpp:49
Definition: Deffered.hpp:49
Definition: HttpUrlConnectionInputStream.hpp:40
Definition: HttpUrlConnection.hpp:23
Definition: Deffered.hpp:52
Definition: Account.cpp:8
Definition: HttpClient.hpp:128
Definition: HttpRequest.hpp:28
Definition: optional.hpp:177
Definition: Exception.hpp:45
Definition: logger.hpp:44
Definition: HttpClient.hpp:60