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#include <test/jtx/JSONRPCClient.h>
20#include <xrpl/json/json_reader.h>
21#include <xrpl/json/to_string.h>
22#include <xrpl/protocol/jss.h>
23#include <xrpl/server/Port.h>
24#include <boost/asio.hpp>
25#include <boost/beast/http/dynamic_body.hpp>
26#include <boost/beast/http/message.hpp>
27#include <boost/beast/http/read.hpp>
28#include <boost/beast/http/string_body.hpp>
29#include <boost/beast/http/write.hpp>
30#include <string>
31
32namespace ripple {
33namespace test {
34
36{
37 static boost::asio::ip::tcp::endpoint
39 {
40 auto& log = std::cerr;
41 ParsedPort common;
42 parse_Port(common, cfg["server"], log);
43 for (auto const& name : cfg.section("server").values())
44 {
45 if (!cfg.exists(name))
46 continue;
47 ParsedPort pp;
48 parse_Port(pp, cfg[name], log);
49 if (pp.protocol.count("http") == 0)
50 continue;
51 using namespace boost::asio::ip;
52 if (pp.ip && pp.ip->is_unspecified())
53 *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()}
54 : address{address_v4::loopback()};
55
56 if (!pp.port)
57 Throw<std::runtime_error>("Use fixConfigPorts with auto ports");
58
59 return {*pp.ip, *pp.port};
60 }
61 Throw<std::runtime_error>("Missing HTTP port");
62 return {}; // Silence compiler control paths return value warning
63 }
64
65 template <class ConstBufferSequence>
66 static std::string
67 buffer_string(ConstBufferSequence const& b)
68 {
69 using namespace boost::asio;
71 s.resize(buffer_size(b));
72 buffer_copy(buffer(&s[0], s.size()), b);
73 return s;
74 }
75
76 boost::asio::ip::tcp::endpoint ep_;
77 boost::asio::io_service ios_;
78 boost::asio::ip::tcp::socket stream_;
79 boost::beast::multi_buffer bin_;
80 boost::beast::multi_buffer bout_;
81 unsigned rpc_version_;
82
83public:
84 explicit JSONRPCClient(Config const& cfg, unsigned rpc_version)
85 : ep_(getEndpoint(cfg)), stream_(ios_), rpc_version_(rpc_version)
86 {
87 stream_.connect(ep_);
88 }
89
90 ~JSONRPCClient() override
91 {
92 // stream_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
93 // stream_.close();
94 }
95
96 /*
97 Return value is an Object type with up to three keys:
98 status
99 error
100 result
101 */
103 invoke(std::string const& cmd, Json::Value const& params) override
104 {
105 using namespace boost::beast::http;
106 using namespace boost::asio;
107 using namespace std::string_literals;
108
109 request<string_body> req;
110 req.method(boost::beast::http::verb::post);
111 req.target("/");
112 req.version(11);
113 req.insert("Content-Type", "application/json; charset=UTF-8");
114 {
116 ostr << ep_;
117 req.insert("Host", ostr.str());
118 }
119 {
120 Json::Value jr;
121 jr[jss::method] = cmd;
122 if (rpc_version_ == 2)
123 {
124 jr[jss::jsonrpc] = "2.0";
125 jr[jss::ripplerpc] = "2.0";
126 jr[jss::id] = 5;
127 }
128 if (params)
129 {
130 Json::Value& ja = jr[jss::params] = Json::arrayValue;
131 ja.append(params);
132 }
133 req.body() = to_string(jr);
134 }
135 req.prepare_payload();
136 write(stream_, req);
137
138 response<dynamic_body> res;
139 read(stream_, bin_, res);
140
141 Json::Reader jr;
142 Json::Value jv;
143 jr.parse(buffer_string(res.body().data()), jv);
144 if (jv["result"].isMember("error"))
145 jv["error"] = jv["result"]["error"];
146 if (jv["result"].isMember("status"))
147 jv["status"] = jv["result"]["status"];
148 return jv;
149 }
150
151 unsigned
152 version() const override
153 {
154 return rpc_version_;
155 }
156};
157
159makeJSONRPCClient(Config const& cfg, unsigned rpc_version)
160{
161 return std::make_unique<JSONRPCClient>(cfg, rpc_version);
162}
163
164} // namespace test
165} // namespace ripple
Unserialize a JSON document into a Value.
Definition: json_reader.h:37
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:73
Represents a JSON value.
Definition: json_value.h:147
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:891
Holds unparsed configuration information.
Definition: BasicConfig.h:219
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:80
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:42
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:199
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
T resize(T... args)
T size(T... args)
T str(T... args)
std::optional< std::uint16_t > port
Definition: Port.h:115
std::set< std::string, boost::beast::iless > protocol
Definition: Port.h:101
std::optional< boost::asio::ip::address > ip
Definition: Port.h:114