Merge branch 'feature/new-rpc-ws-clients' into feature/son-for-ethereum

This commit is contained in:
serkixenos 2022-07-07 19:08:59 +02:00
commit 73163d2722
2 changed files with 85 additions and 38 deletions

View file

@ -1,10 +1,15 @@
#include <graphene/peerplays_sidechain/common/rpc_client.hpp> #include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <regex>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <boost/asio/buffers_iterator.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <curl/curl.h> #include <curl/curl.h>
@ -18,6 +23,35 @@ rpc_client::rpc_client(std::string _url, std::string _user, std::string _passwor
password(_password), password(_password),
debug_rpc_calls(_debug_rpc_calls), debug_rpc_calls(_debug_rpc_calls),
request_id(0) { request_id(0) {
std::string reg_expr = "^((?P<Protocol>https|http):\\/\\/)?(?P<Host>[a-zA-Z0-9\\-\\.]+)(:(?P<Port>\\d{1,5}))?(?P<Target>\\/.+)?";
boost::xpressive::sregex sr = boost::xpressive::sregex::compile(reg_expr);
boost::xpressive::smatch sm;
if (boost::xpressive::regex_search(url, sm, sr)) {
protocol = sm["Protocol"];
if (protocol.empty()) {
protocol = "http";
}
host = sm["Host"];
if (host.empty()) {
host + "localhost";
}
port = sm["Port"];
if (port.empty()) {
port = "80";
}
target = sm["Target"];
if (target.empty()) {
target = "/";
}
} else {
elog("Invalid URL: ${url}", ("url", url));
}
} }
std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) {
@ -98,57 +132,65 @@ std::string rpc_client::send_post_request(std::string method, std::string params
return ""; return "";
} }
static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) {
size_t retval = 0;
if (reply != nullptr) {
reply->body.append(ptr, size * nmemb);
retval = size * nmemb;
}
return retval;
}
rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { rpc_reply rpc_client::send_post_request(std::string body, bool show_log) {
struct curl_slist *headers = nullptr; // The io_context is required for all I/O
headers = curl_slist_append(headers, "Accept: application/json"); boost::beast::net::io_context ioc;
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charset: utf-8");
CURL *curl = curl_easy_init(); // These objects perform our I/O
boost::beast::net::ip::tcp::resolver resolver(ioc);
boost::beast::tcp_stream stream(ioc);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // Look up the domain name
if (url.find("https://", 0) == 0) { auto const results = resolver.resolve(host, port);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
if (!user.empty()) { // Make the connection on the IP address we get from a lookup
curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); stream.connect(results);
curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Set up an HTTP GET request message
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); boost::beast::http::request<boost::beast::http::string_body> req{boost::beast::http::verb::post, target, 11};
req.set(boost::beast::http::field::host, host + ":" + port);
req.set(boost::beast::http::field::accept, "application/json");
req.set(boost::beast::http::field::content_type, "application/json");
req.set(boost::beast::http::field::content_encoding, "utf-8");
req.set(boost::beast::http::field::content_length, body.length());
req.body() = body;
//curl_easy_setopt(curl, CURLOPT_VERBOSE, true); // Send the HTTP request to the remote host
boost::beast::http::write(stream, req);
// This buffer is used for reading and must be persisted
boost::beast::flat_buffer buffer;
// Declare a container to hold the response
boost::beast::http::response<boost::beast::http::dynamic_body> res;
// Receive the HTTP response
boost::beast::http::read(stream, buffer, res);
//// Write the message to standard out
//std::cout << res << std::endl;
// Gracefully close the socket
boost::beast::error_code ec;
stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
// not_connected happens sometimes
// so don't bother reporting it.
//
if (ec && ec != boost::beast::errc::not_connected)
throw boost::beast::system_error{ec};
std::string rbody{boost::asio::buffers_begin(res.body().data()),
boost::asio::buffers_end(res.body().data())};
rpc_reply reply; rpc_reply reply;
reply.status = 200;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); reply.body = rbody;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply);
curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status);
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
if (show_log) { if (show_log) {
ilog("### Request URL: ${url}", ("url", url)); ilog("### Request URL: ${url}", ("url", url));
ilog("### Request: ${body}", ("body", body)); ilog("### Request: ${body}", ("body", body));
std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); ilog("### Response: ${rbody}", ("rbody", rbody));
ilog("### Response: ${ss}", ("ss", ss.str()));
} }
return reply; return reply;

View file

@ -20,6 +20,11 @@ protected:
std::string send_post_request(std::string method, std::string params, bool show_log); std::string send_post_request(std::string method, std::string params, bool show_log);
std::string url; std::string url;
std::string protocol;
std::string host;
std::string port;
std::string target;
std::string user; std::string user;
std::string password; std::string password;
bool debug_rpc_calls; bool debug_rpc_calls;