xrpld
Loading...
Searching...
No Matches
WorkBase.h
1#pragma once
2
3#include <xrpld/app/misc/detail/Work.h>
4
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/protocol/BuildInfo.h>
7
8#include <boost/asio.hpp>
9#include <boost/asio/strand.hpp>
10#include <boost/beast/core/multi_buffer.hpp>
11#include <boost/beast/http/empty_body.hpp>
12#include <boost/beast/http/read.hpp>
13#include <boost/beast/http/write.hpp>
14
15#include <cstddef>
16#include <functional>
17#include <string>
18#include <utility>
19
20namespace xrpl::detail {
21
22template <class Impl>
23class WorkBase : public Work
24{
25protected:
26 using error_code = boost::system::error_code;
27 using endpoint_type = boost::asio::ip::tcp::endpoint;
28
29public:
31 std::function<void(error_code const&, endpoint_type const&, response_type&&)>;
32
33protected:
34 using socket_type = boost::asio::ip::tcp::socket;
35 using resolver_type = boost::asio::ip::tcp::resolver;
36 using results_type = boost::asio::ip::tcp::resolver::results_type;
37 using request_type = boost::beast::http::request<boost::beast::http::empty_body>;
38
43 boost::asio::io_context& ios_;
44 boost::asio::strand<boost::asio::io_context::executor_type> strand_;
49 boost::beast::multi_buffer readBuf_;
52
53private:
55 std::string host,
57 std::string port,
58 boost::asio::io_context& ios,
59 endpoint_type lastEndpoint,
60 bool lastStatus,
61 callback_type cb);
62
63public:
64 ~WorkBase() override;
65
66 Impl&
68 {
69 return *static_cast<Impl*>(this);
70 }
71
72 void
73 run() override;
74
75 void
76 cancel() override;
77
78 void
79 fail(error_code const& ec);
80
81 void
82 onResolve(error_code const& ec, results_type results);
83
84 void
85 onConnect(error_code const& ec, endpoint_type const& endpoint);
86
87 void
89
90 void
92
93 void
95
96private:
97 void
99
100 friend Impl;
101};
102
103//------------------------------------------------------------------------------
104
105template <class Impl>
107 std::string host,
109 std::string port,
110 boost::asio::io_context& ios,
111 endpoint_type lastEndpoint,
112 bool lastStatus,
113 callback_type cb)
114 : host_(std::move(host))
115 , path_(std::move(path))
116 , port_(std::move(port))
117 , cb_(std::move(cb))
118 , ios_(ios)
119 , strand_(boost::asio::make_strand(ios))
120 , resolver_(ios)
121 , socket_(ios)
122 , lastEndpoint_{std::move(lastEndpoint)}
123 , lastStatus_(lastStatus)
124{
125}
126
127template <class Impl>
129{
130 if (cb_)
131 cb_(make_error_code(boost::system::errc::not_a_socket), lastEndpoint_, std::move(res_));
132 close();
133}
134
135template <class Impl>
136void
138{
139 if (!strand_.running_in_this_thread())
140 {
141 return boost::asio::post(
142 ios_, boost::asio::bind_executor(strand_, [self = impl().shared_from_this()] {
143 self->run();
144 }));
145 }
146
147 resolver_.async_resolve(
148 host_,
149 port_,
150 boost::asio::bind_executor(
151 strand_,
152 [self = impl().shared_from_this()](error_code const& ec, results_type results) {
153 self->onResolve(ec, results);
154 }));
155}
156
157template <class Impl>
158void
160{
161 if (!strand_.running_in_this_thread())
162 {
163 return boost::asio::post(
164 ios_,
165
166 boost::asio::bind_executor(
167 strand_, [self = impl().shared_from_this()] { self->cancel(); }));
168 }
169
170 error_code ec;
171 resolver_.cancel();
172 socket_.cancel(ec);
173}
174
175template <class Impl>
176void
178{
179 if (cb_)
180 {
181 cb_(ec, lastEndpoint_, std::move(res_));
182 cb_ = nullptr;
183 }
184}
185
186template <class Impl>
187void
189{
190 if (ec)
191 return fail(ec);
192
193 boost::asio::async_connect(
194 socket_,
195 results,
196 boost::asio::bind_executor(
197 strand_,
198 [self = impl().shared_from_this()](
199 error_code const& ec, endpoint_type const& endpoint) {
200 // Call the base-class overload explicitly: the derived Impl
201 // hides it with its own single-argument onConnect(ec).
202 self->WorkBase::onConnect(ec, endpoint);
203 }));
204}
205
206template <class Impl>
207void
209{
210 lastEndpoint_ = endpoint;
211
212 if (ec)
213 return fail(ec);
214
215 impl().onConnect(ec);
216}
217
218template <class Impl>
219void
221{
222 req_.method(boost::beast::http::verb::get);
223 req_.target(path_.empty() ? "/" : path_);
224 req_.version(11);
225 req_.set("Host", host_ + ":" + port_);
226 req_.set("User-Agent", build_info::getFullVersionString());
227 req_.prepare_payload();
228 boost::beast::http::async_write(
229 impl().stream(),
230 req_,
231 boost::asio::bind_executor(
232 strand_, [self = impl().shared_from_this()](error_code const& ec, std::size_t) {
233 self->onRequest(ec);
234 }));
235}
236
237template <class Impl>
238void
240{
241 if (ec)
242 return fail(ec);
243
244 boost::beast::http::async_read(
245 impl().stream(),
246 readBuf_,
247 res_,
248 boost::asio::bind_executor(
249 strand_, [self = impl().shared_from_this()](error_code const& ec, std::size_t) {
250 self->onResponse(ec);
251 }));
252}
253
254template <class Impl>
255void
257{
258 if (ec)
259 return fail(ec);
260
261 close();
262 XRPL_ASSERT(cb_, "xrpl::detail::WorkBase::onResponse : callback is set");
263 cb_(ec, lastEndpoint_, std::move(res_));
264 cb_ = nullptr;
265}
266
267template <class Impl>
268void
270{
271 if (socket_.is_open())
272 {
273 error_code ec;
274 socket_.shutdown(boost::asio::socket_base::shutdown_send, ec);
275 if (ec)
276 return;
277 socket_.close(ec);
278 }
279}
280
281} // namespace xrpl::detail
void fail(error_code const &ec)
Definition WorkBase.h:177
void cancel() override
Definition WorkBase.h:159
endpoint_type lastEndpoint_
Definition WorkBase.h:50
std::function< void(error_code const &, endpoint_type const &, response_type &&)> callback_type
Definition WorkBase.h:30
boost::beast::http::request< boost::beast::http::empty_body > request_type
Definition WorkBase.h:37
request_type req_
Definition WorkBase.h:47
response_type res_
Definition WorkBase.h:48
void onResolve(error_code const &ec, results_type results)
Definition WorkBase.h:188
std::string port_
Definition WorkBase.h:41
socket_type socket_
Definition WorkBase.h:46
callback_type cb_
Definition WorkBase.h:42
std::string path_
Definition WorkBase.h:40
boost::asio::ip::tcp::endpoint endpoint_type
Definition WorkBase.h:27
boost::system::error_code error_code
Definition WorkBase.h:26
boost::asio::ip::tcp::resolver::results_type results_type
Definition WorkBase.h:36
void onRequest(error_code const &ec)
Definition WorkBase.h:239
boost::asio::ip::tcp::socket socket_type
Definition WorkBase.h:34
void onConnect(error_code const &ec, endpoint_type const &endpoint)
Definition WorkBase.h:208
boost::asio::strand< boost::asio::io_context::executor_type > strand_
Definition WorkBase.h:44
void onResponse(error_code const &ec)
Definition WorkBase.h:256
boost::beast::multi_buffer readBuf_
Definition WorkBase.h:49
resolver_type resolver_
Definition WorkBase.h:45
boost::asio::io_context & ios_
Definition WorkBase.h:43
std::string host_
Definition WorkBase.h:39
void run() override
Definition WorkBase.h:137
boost::asio::ip::tcp::resolver resolver_type
Definition WorkBase.h:35
WorkBase(std::string host, std::string path, std::string port, boost::asio::io_context &ios, endpoint_type lastEndpoint, bool lastStatus, callback_type cb)
Definition WorkBase.h:106
STL namespace.
std::string const & getFullVersionString()
Full server version string.
Definition BuildInfo.cpp:82
boost::beast::http::response< boost::beast::http::string_body > response_type
Definition Work.h:8
std::error_code make_error_code(xrpl::TokenCodecErrc e)