rippled
Loading...
Searching...
No Matches
JSONRPCClient.cpp
1#include <test/jtx/JSONRPCClient.h>
2
3#include <xrpl/json/json_reader.h>
4#include <xrpl/json/to_string.h>
5#include <xrpl/protocol/jss.h>
6#include <xrpl/server/Port.h>
7
8#include <boost/asio.hpp>
9#include <boost/beast/http/dynamic_body.hpp>
10#include <boost/beast/http/message.hpp>
11#include <boost/beast/http/read.hpp>
12#include <boost/beast/http/string_body.hpp>
13#include <boost/beast/http/write.hpp>
14
15#include <string>
16
17namespace xrpl {
18namespace test {
19
21{
22 static boost::asio::ip::tcp::endpoint
24 {
25 auto& log = std::cerr;
26 ParsedPort common;
27 parse_Port(common, cfg["server"], log);
28 for (auto const& name : cfg.section("server").values())
29 {
30 if (!cfg.exists(name))
31 continue;
32 ParsedPort pp;
33 parse_Port(pp, cfg[name], log);
34 if (pp.protocol.count("http") == 0)
35 continue;
36 using namespace boost::asio::ip;
37 if (pp.ip && pp.ip->is_unspecified())
38 {
39 *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()}
40 : address{address_v4::loopback()};
41 }
42
43 if (!pp.port)
44 Throw<std::runtime_error>("Use fixConfigPorts with auto ports");
45
46 return {*pp.ip, *pp.port}; // NOLINT(bugprone-unchecked-optional-access)
47 }
48 Throw<std::runtime_error>("Missing HTTP port");
49 return {}; // Silence compiler control paths return value warning
50 }
51
52 template <class ConstBufferSequence>
53 static std::string
54 buffer_string(ConstBufferSequence const& b)
55 {
56 using namespace boost::asio;
58 s.resize(buffer_size(b));
59 buffer_copy(buffer(&s[0], s.size()), b);
60 return s;
61 }
62
63 boost::asio::ip::tcp::endpoint ep_;
64 boost::asio::io_context ios_;
65 boost::asio::ip::tcp::socket stream_;
66 boost::beast::multi_buffer bin_;
67 boost::beast::multi_buffer bout_;
68 unsigned rpc_version_;
69
70public:
71 explicit JSONRPCClient(Config const& cfg, unsigned rpc_version)
72 : ep_(getEndpoint(cfg)), stream_(ios_), rpc_version_(rpc_version)
73 {
74 stream_.connect(ep_);
75 }
76
77 ~JSONRPCClient() override
78 {
79 // stream_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
80 // stream_.close();
81 }
82
83 /*
84 Return value is an Object type with up to three keys:
85 status
86 error
87 result
88 */
90 invoke(std::string const& cmd, Json::Value const& params) override
91 {
92 using namespace boost::beast::http;
93 using namespace boost::asio;
94 using namespace std::string_literals;
95
96 request<string_body> req;
97 req.method(boost::beast::http::verb::post);
98 req.target("/");
99 req.version(11);
100 req.insert("Content-Type", "application/json; charset=UTF-8");
101 {
103 ostr << ep_;
104 req.insert("Host", ostr.str());
105 }
106 {
107 Json::Value jr;
108 jr[jss::method] = cmd;
109 if (rpc_version_ == 2)
110 {
111 jr[jss::jsonrpc] = "2.0";
112 jr[jss::ripplerpc] = "2.0";
113 jr[jss::id] = 5;
114 }
115 if (params)
116 {
117 Json::Value& ja = jr[jss::params] = Json::arrayValue;
118 ja.append(params);
119 }
120 req.body() = to_string(jr);
121 }
122 req.prepare_payload();
123 write(stream_, req);
124
125 response<dynamic_body> res;
126 read(stream_, bin_, res);
127
128 Json::Reader jr;
129 Json::Value jv;
130 jr.parse(buffer_string(res.body().data()), jv);
131 if (jv["result"].isMember("error"))
132 jv["error"] = jv["result"]["error"];
133 if (jv["result"].isMember("status"))
134 jv["status"] = jv["result"]["status"];
135 return jv;
136 }
137
138 unsigned
139 version() const override
140 {
141 return rpc_version_;
142 }
143};
144
146makeJSONRPCClient(Config const& cfg, unsigned rpc_version)
147{
148 return std::make_unique<JSONRPCClient>(cfg, rpc_version);
149}
150
151} // namespace test
152} // namespace xrpl
Unserialize a JSON document into a Value.
Definition json_reader.h:17
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
Holds unparsed configuration information.
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Section & section(std::string const &name)
Returns the section with the given name.
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition BasicConfig.h:58
static std::string buffer_string(ConstBufferSequence const &b)
unsigned version() const override
Get RPC 1.0 or RPC 2.0.
boost::asio::ip::tcp::endpoint ep_
boost::asio::ip::tcp::socket stream_
boost::beast::multi_buffer bout_
JSONRPCClient(Config const &cfg, unsigned rpc_version)
boost::beast::multi_buffer bin_
boost::asio::io_context ios_
static boost::asio::ip::tcp::endpoint getEndpoint(BasicConfig const &cfg)
Json::Value invoke(std::string const &cmd, Json::Value const &params) override
Submit a command synchronously.
T count(T... args)
T is_same_v
@ arrayValue
array value (ordered list)
Definition json_value.h:25
std::unique_ptr< AbstractClient > makeJSONRPCClient(Config const &cfg, unsigned rpc_version)
Returns a client using JSON-RPC over HTTP/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition Port.cpp:194
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
T resize(T... args)
T size(T... args)
T str(T... args)
std::set< std::string, boost::beast::iless > protocol
Definition Port.h:82
std::optional< boost::asio::ip::address > ip
Definition Port.h:95
std::optional< std::uint16_t > port
Definition Port.h:96