提交 16bc1706 编写于 作者: D Daniel Larimer

cleos builds again

上级 a5c4b49d
Subproject commit 3bfd8b5fdf8df9774f116fb2014770053df73a35
Subproject commit 31a02293a303782a97963a2e67815703f1123914
......@@ -1190,7 +1190,7 @@ using App_p = std::unique_ptr<App>;
/** To use, create a new `Program()` instance with `argc`, `argv`, and a help description. The templated
* add_option methods make it easy to prepare options. Remember to call `.start` before starting your
* program, so that the options can be evaluated and the help option doesn't accidentally run your program. */
class App {
class App final {
friend Option;
friend detail::AppFriend;
......
......@@ -105,7 +105,7 @@ const char* error_advice_3010004 = "Most likely, the given contract doesnt' exi
const char* error_advice_3030000 = "Ensure that your transaction satisfy the contract's constraint!";
const char* error_advice_3030001 = R"=====(Ensure that you have the related authority inside your transaction!;
If you are currently using 'cleos push action' command, try to add the relevant authority using -p option.)=====";
const char* error_advice_3030002 = "Ensure that you have the related private keys inside your wallet and you wallet is unlocked.";
const char* error_advice_3030002 = "Ensure that you have the related private keys inside your wallet and your wallet is unlocked.";
const char* error_advice_3030003 = "Please remove the unnecessary authority from your action!";
const char* error_advice_3030004 = "Please remove the unnecessary signature from your transaction!";
const char* error_advice_3030011 = "You can try embedding eosio nonce action inside your transaction to ensure uniqueness.";
......@@ -214,15 +214,16 @@ e.g.
const char* error_advice_3130001 = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration!";
const char* error_advice_3130002 = "Ensure that you have \033[2meosio::wallet_api_plugin\033[0m\033[32m added to your node's configuration!\n"\
"Otherwise specify your wallet location with \033[2m--wallet-host\033[0m\033[32m and \033[2m--wallet_port\033[0m\033[32m arguments!";
"Otherwise specify your wallet location with \033[2m--wallet-host\033[0m\033[32m and \033[2m--wallet-port\033[0m\033[32m arguments!";
const char* error_advice_3130003 = "Ensure that you have \033[2meosio::account_history_api_plugin\033[0m\033[32m added to your node's configuration!";
const char* error_advice_3130004 = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration!";
const char* error_advice_3140001 = "Try to use different wallet name.";
const char* error_advice_3140002 = "Are you sure you typed the name correctly?";
const char* error_advice_3140002 = "Are you sure you typed the wallet name correctly?";
const char* error_advice_3140003 = "Ensure that your wallet is unlocked before using it!";
const char* error_advice_3140004 = "Ensure that you have the relevant private key imported!";
const char* error_advice_3140005 = "Are you sure you are using the right password?";
const char* error_advice_3140006 = "Ensure that you have created a wallet and have it open";
const std::map<int64_t, std::string> error_advice = {
......@@ -264,7 +265,8 @@ const std::map<int64_t, std::string> error_advice = {
{ 3140002, error_advice_3140002 },
{ 3140003, error_advice_3140003 },
{ 3140004, error_advice_3140004 },
{ 3140005, error_advice_3140005 }
{ 3140005, error_advice_3140005 },
{ 3140006, error_advice_3140006 }
};
......
......@@ -12,7 +12,9 @@
#include <istream>
#include <ostream>
#include <string>
#include <regex>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <fc/variant.hpp>
#include <fc/io/json.hpp>
#include <eosio/chain/exceptions.hpp>
......@@ -22,126 +24,155 @@
using boost::asio::ip::tcp;
namespace eosio { namespace client { namespace http {
fc::variant call( const std::string& server, uint16_t port,
const std::string& path,
const fc::variant& postdata ) {
try {
std::string postjson;
if( !postdata.is_null() )
postjson = fc::json::to_string( postdata );
void do_connect(tcp::socket& sock, const std::string& server, const std::string& port) {
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(sock.get_io_service());
tcp::resolver::query query(server, port);
boost::asio::connect(sock, resolver.resolve(query));
}
boost::asio::io_service io_service;
template<class T>
std::string do_txrx(T& socket, boost::asio::streambuf& request_buff, unsigned int& status_code) {
// Send the request.
boost::asio::write(socket, request_buff);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
FC_ASSERT( !(!response_stream || http_version.substr(0, 5) != "HTTP/"), "Invalid Response" );
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
int response_content_length = -1;
std::regex clregex(R"xx(^content-length:\s+(\d+))xx", std::regex_constants::icase);
while (std::getline(response_stream, header) && header != "\r") {
std::smatch match;
if(std::regex_search(header, match, clregex))
response_content_length = std::stoi(match[1]);
}
FC_ASSERT(response_content_length >= 0, "Invalid content-length response");
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query(server, std::to_string(port) );
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
while( endpoint_iterator != end ) {
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
try {
boost::asio::connect(socket, endpoint_iterator);
endpoint_iterator = end;
} catch( std::exception& e ) {
++endpoint_iterator;
if( endpoint_iterator != end )
continue;
else throw;
}
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "POST " << path << " HTTP/1.0\r\n";
request_stream << "Host: " << server << "\r\n";
request_stream << "content-length: " << postjson.size() << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
request_stream << postjson;
// Send the request.
boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
FC_ASSERT( !(!response_stream || http_version.substr(0, 5) != "HTTP/"), "Invalid Response" );
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
{
// std::cout << header << "\n";
}
// std::cout << "\n";
std::stringstream re;
// Write whatever content we already have to output.
if (response.size() > 0)
// std::cout << &response;
re << &response;
// Read until EOF, writing data to output as we go.
boost::system::error_code error;
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error))
re << &response;
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);
// std::cout << re.str() <<"\n";
const auto response_result = fc::json::from_string(re.str());
if( status_code == 200 || status_code == 201 || status_code == 202 ) {
return response_result;
} else if( status_code == 404 ) {
// Unknown endpoint
if (path.compare(0, chain_func_base.size(), chain_func_base) == 0) {
throw chain::missing_chain_api_plugin_exception(FC_LOG_MESSAGE(error, "Chain API plugin is not enabled"));
} else if (path.compare(0, wallet_func_base.size(), wallet_func_base) == 0) {
throw chain::missing_wallet_api_plugin_exception(FC_LOG_MESSAGE(error, "Wallet is not available"));
} else if (path.compare(0, account_history_func_base.size(), account_history_func_base) == 0) {
throw chain::missing_account_history_api_plugin_exception(FC_LOG_MESSAGE(error, "Account History API plugin is not enabled"));
} else if (path.compare(0, net_func_base.size(), net_func_base) == 0) {
throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled"));
}
} else {
auto &&error_info = response_result.as<eosio::error_results>().error;
// Construct fc exception from error
const auto &error_details = error_info.details;
fc::log_messages logs;
for (auto itr = error_details.begin(); itr != error_details.end(); itr++) {
const auto& context = fc::log_context(fc::log_level::error, itr->file.data(), itr->line_number, itr->method.data());
logs.emplace_back(fc::log_message(context, itr->message));
}
throw fc::exception(logs, error_info.code, error_info.name, error_info.what);
}
FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re.str()) );
std::stringstream re;
// Write whatever content we already have to output.
response_content_length -= response.size();
if (response.size() > 0)
re << &response;
boost::asio::read(socket, response, boost::asio::transfer_exactly(response_content_length));
re << &response;
return re.str();
}
fc::variant call( const std::string& server_url,
const std::string& path,
const fc::variant& postdata ) {
std::string postjson;
if( !postdata.is_null() )
postjson = fc::json::to_string( postdata );
boost::asio::io_service io_service;
string scheme, server, port, path_prefix;
//via rfc3986 and modified a bit to suck out the port number
//Sadly this doesn't work for ipv6 addresses
std::regex rgx(R"xx(^(([^:/?#]+):)?(//([^:/?#]*)(:(\d+))?)?([^?#]*)(\?([^#]*))?(#(.*))?)xx");
std::smatch match;
if(std::regex_search(server_url.begin(), server_url.end(), match, rgx)) {
scheme = match[2];
server = match[4];
port = match[6];
path_prefix = match[7];
}
if(scheme != "http" && scheme != "https")
FC_THROW("Unrecognized URL scheme (${s}) in URL \"${u}\"", ("s", scheme)("u", server_url));
if(server.empty())
FC_THROW("No server parsed from URL \"${u}\"", ("u", server_url));
if(port.empty())
port = scheme == "http" ? "8888" : "443";
boost::trim_right_if(path_prefix, boost::is_any_of("/"));
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "POST " << path_prefix + path << " HTTP/1.0\r\n";
request_stream << "Host: " << server << "\r\n";
request_stream << "content-length: " << postjson.size() << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
request_stream << postjson;
unsigned int status_code;
std::string re;
if(scheme == "http") {
tcp::socket socket(io_service);
do_connect(socket, server, port);
re = do_txrx(socket, request, status_code);
}
else { //https
boost::asio::ssl::context ssl_context(boost::asio::ssl::context::sslv23_client);
#if defined( __APPLE__ )
//TODO: this is undocumented/not supported; fix with keychain based approach
ssl_context.load_verify_file("/private/etc/ssl/cert.pem");
#elif defined( _WIN32 )
FC_THROW("HTTPS on Windows not supported");
#else
ssl_context.set_default_verify_paths();
#endif
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(io_service, ssl_context);
socket.set_verify_mode(boost::asio::ssl::verify_peer);
do_connect(socket.next_layer(), server, port);
socket.handshake(boost::asio::ssl::stream_base::client);
re = do_txrx(socket, request, status_code);
//try and do a clean shutdown; but swallow if this fails (other side could have already gave TCP the ax)
try {socket.shutdown();} catch(...) {}
}
const auto response_result = fc::json::from_string(re);
if( status_code == 200 || status_code == 201 || status_code == 202 ) {
return response_result;
} else if( status_code == 404 ) {
// Unknown endpoint
if (path.compare(0, chain_func_base.size(), chain_func_base) == 0) {
throw chain::missing_chain_api_plugin_exception(FC_LOG_MESSAGE(error, "Chain API plugin is not enabled"));
} else if (path.compare(0, wallet_func_base.size(), wallet_func_base) == 0) {
throw chain::missing_wallet_api_plugin_exception(FC_LOG_MESSAGE(error, "Wallet is not available"));
} else if (path.compare(0, account_history_func_base.size(), account_history_func_base) == 0) {
throw chain::missing_account_history_api_plugin_exception(FC_LOG_MESSAGE(error, "Account History API plugin is not enabled"));
} else if (path.compare(0, net_func_base.size(), net_func_base) == 0) {
throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled"));
}
} else {
auto &&error_info = response_result.as<eosio::error_results>().error;
// Construct fc exception from error
const auto &error_details = error_info.details;
fc::log_messages logs;
for (auto itr = error_details.begin(); itr != error_details.end(); itr++) {
const auto& context = fc::log_context(fc::log_level::error, itr->file.data(), itr->line_number, itr->method.data());
logs.emplace_back(fc::log_message(context, itr->message));
}
FC_ASSERT( !"unable to connect" );
} FC_CAPTURE_AND_RETHROW() // error, "Request Path: ${server}:${port}${path}\nRequest Post Data: ${postdata}" ,
// ("server", server)("port", port)("path", path)("postdata", postdata) )
throw fc::exception(logs, error_info.code, error_info.name, error_info.what);
}
FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re) );
return response_result;
}
}}}
......@@ -5,7 +5,7 @@
#pragma once
namespace eosio { namespace client { namespace http {
fc::variant call( const std::string& server, uint16_t port,
fc::variant call( const std::string& server_url,
const std::string& path,
const fc::variant& postdata = fc::variant() );
......@@ -46,4 +46,6 @@ namespace eosio { namespace client { namespace http {
const string wallet_unlock = wallet_func_base + "/unlock";
const string wallet_import_key = wallet_func_base + "/import_key";
const string wallet_sign_trx = wallet_func_base + "/sign_transaction";
FC_DECLARE_EXCEPTION( connection_exception, 1100000, "Connection Exception" );
}}}
\ No newline at end of file
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册