rippled
Loading...
Searching...
No Matches
JSONRPCClient.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2016 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx/JSONRPCClient.h>
21#include <xrpl/json/json_reader.h>
22#include <xrpl/json/to_string.h>
23#include <xrpl/protocol/jss.h>
24#include <xrpl/server/Port.h>
25
26#include <boost/asio.hpp>
27#include <boost/beast/http/dynamic_body.hpp>
28#include <boost/beast/http/message.hpp>
29#include <boost/beast/http/read.hpp>
30#include <boost/beast/http/string_body.hpp>
31#include <boost/beast/http/write.hpp>
32
33#include <string>
34
35namespace ripple {
36namespace test {
37
39{
40 static boost::asio::ip::tcp::endpoint
42 {
43 auto& log = std::cerr;
44 ParsedPort common;
45 parse_Port(common, cfg["server"], log);
46 for (auto const& name : cfg.section("server").values())
47 {
48 if (!cfg.exists(name))
49 continue;
50 ParsedPort pp;
51 parse_Port(pp, cfg[name], log);
52 if (pp.protocol.count("http") == 0)
53 continue;
54 using namespace boost::asio::ip;
55 if (pp.ip && pp.ip->is_unspecified())
56 *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()}
57 : address{address_v4::loopback()};
58
59 if (!pp.port)
60 Throw<std::runtime_error>("Use fixConfigPorts with auto ports");
61
62 return {*pp.ip, *pp.port};
63 }
64 Throw<std::runtime_error>("Missing HTTP port");
65 return {}; // Silence compiler control paths return value warning
66 }
67
68 template <class ConstBufferSequence>
69 static std::string
70 buffer_string(ConstBufferSequence const& b)
71 {
72 using namespace boost::asio;
74 s.resize(buffer_size(b));
75 buffer_copy(buffer(&s[0], s.size()), b);
76 return s;
77 }
78
79 boost::asio::ip::tcp::endpoint ep_;
80 boost::asio::io_service ios_;
81 boost::asio::ip::tcp::socket stream_;
82 boost::beast::multi_buffer bin_;
83 boost::beast::multi_buffer bout_;
84 unsigned rpc_version_;
85
86public:
87 explicit JSONRPCClient(Config const& cfg, unsigned rpc_version)
88 : ep_(getEndpoint(cfg)), stream_(ios_), rpc_version_(rpc_version)
89 {
90 stream_.connect(ep_);
91 }
92
93 ~JSONRPCClient() override
94 {
95 // stream_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
96 // stream_.close();
97 }
98
99 /*
100 Return value is an Object type with up to three keys:
101 status
102 error
103 result
104 */
106 invoke(std::string const& cmd, Json::Value const& params) override
107 {
108 using namespace boost::beast::http;
109 using namespace boost::asio;
110 using namespace std::string_literals;
111
112 request<string_body> req;
113 req.method(boost::beast::http::verb::post);
114 req.target("/");
115 req.version(11);
116 req.insert("Content-Type", "application/json; charset=UTF-8");
117 {
119 ostr << ep_;
120 req.insert("Host", ostr.str());
121 }
122 {
123 Json::Value jr;
124 jr[jss::method] = cmd;
125 if (rpc_version_ == 2)
126 {
127 jr[jss::jsonrpc] = "2.0";
128 jr[jss::ripplerpc] = "2.0";
129 jr[jss::id] = 5;
130 }
131 if (params)
132 {
133 Json::Value& ja = jr[jss::params] = Json::arrayValue;
134 ja.append(params);
135 }
136 req.body() = to_string(jr);
137 }
138 req.prepare_payload();
139 write(stream_, req);
140
141 response<dynamic_body> res;
142 read(stream_, bin_, res);
143
144 Json::Reader jr;
145 Json::Value jv;
146 jr.parse(buffer_string(res.body().data()), jv);
147 if (jv["result"].isMember("error"))
148 jv["error"] = jv["result"]["error"];
149 if (jv["result"].isMember("status"))
150 jv["status"] = jv["result"]["status"];
151 return jv;
152 }
153
154 unsigned
155 version() const override
156 {
157 return rpc_version_;
158 }
159};
160
162makeJSONRPCClient(Config const& cfg, unsigned rpc_version)
163{
164 return std::make_unique<JSONRPCClient>(cfg, rpc_version);
165}
166
167} // namespace test
168} // namespace ripple
Unserialize a JSON document into a Value.
Definition: json_reader.h:39
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:78
Represents a JSON value.
Definition: json_value.h:148
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:897
Holds unparsed configuration information.
Definition: BasicConfig.h:218
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:79
static boost::asio::ip::tcp::endpoint getEndpoint(BasicConfig const &cfg)
unsigned version() const override
Get RPC 1.0 or RPC 2.0.
boost::asio::ip::tcp::socket stream_
boost::asio::ip::tcp::endpoint ep_
boost::beast::multi_buffer bout_
JSONRPCClient(Config const &cfg, unsigned rpc_version)
Json::Value invoke(std::string const &cmd, Json::Value const &params) override
Submit a command synchronously.
static std::string buffer_string(ConstBufferSequence const &b)
boost::asio::io_service ios_
boost::beast::multi_buffer bin_
T count(T... args)
@ arrayValue
array value (ordered list)
Definition: json_value.h:43
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:26
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition: Port.cpp:213
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
T resize(T... args)
T size(T... args)
T str(T... args)
std::optional< std::uint16_t > port
Definition: Port.h:116
std::set< std::string, boost::beast::iless > protocol
Definition: Port.h:102
std::optional< boost::asio::ip::address > ip
Definition: Port.h:115