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