未验证 提交 5d839494 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #2691 from EOSIO/cleos-keos-slim

Cleos launches keos in slim branch
......@@ -77,6 +77,29 @@ namespace eosio { namespace client { namespace http {
return re.str();
}
parsed_url parse_url( const string& server_url ) {
parsed_url res;
//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)) {
res.scheme = match[2];
res.server = match[4];
res.port = match[6];
res.path_prefix = match[7];
}
if(res.scheme != "http" && res.scheme != "https")
FC_THROW("Unrecognized URL scheme (${s}) in URL \"${u}\"", ("s", res.scheme)("u", server_url));
if(res.server.empty())
FC_THROW("No server parsed from URL \"${u}\"", ("u", server_url));
if(res.port.empty())
res.port = res.scheme == "http" ? "8888" : "443";
boost::trim_right_if(res.path_prefix, boost::is_any_of("/"));
return res;
}
fc::variant call( const std::string& server_url,
const std::string& path,
const fc::variant& postdata ) {
......@@ -86,30 +109,12 @@ namespace eosio { namespace client { namespace http {
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("/"));
auto url = parse_url( server_url );
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 << "POST " << url.path_prefix + path << " HTTP/1.0\r\n";
request_stream << "Host: " << url.server << "\r\n";
request_stream << "content-length: " << postjson.size() << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
......@@ -118,9 +123,9 @@ namespace eosio { namespace client { namespace http {
unsigned int status_code;
std::string re;
if(scheme == "http") {
if(url.scheme == "http") {
tcp::socket socket(io_service);
do_connect(socket, server, port);
do_connect(socket, url.server, url.port);
re = do_txrx(socket, request, status_code);
}
else { //https
......@@ -137,7 +142,7 @@ namespace eosio { namespace client { namespace http {
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);
do_connect(socket.next_layer(), url.server, url.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)
......
......@@ -5,6 +5,16 @@
#pragma once
namespace eosio { namespace client { namespace http {
struct parsed_url {
string scheme;
string server;
string port;
string path_prefix;
};
parsed_url parse_url( const string& server_url );
fc::variant call( const std::string& server_url,
const std::string& path,
const fc::variant& postdata = fc::variant() );
......@@ -50,6 +60,7 @@ 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";
const string keosd_stop = "/v1/keosd/stop";
FC_DECLARE_EXCEPTION( connection_exception, 1100000, "Connection Exception" );
}}}
......@@ -69,11 +69,10 @@ Options:
-p,--permission TEXT ... An account and permission level to authorize, as in 'account@permission' (defaults to 'creator@active')
```
*/
#include <string>
#include <vector>
#include <regex>
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <iostream>
#include <fc/crypto/hex.hpp>
#include <fc/variant.hpp>
......@@ -84,12 +83,22 @@ Options:
#include <fc/variant_object.hpp>
#include <eosio/utilities/key_conversion.hpp>
#include <eosio/chain/name.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio/chain/trace.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio/chain/contract_types.hpp>
#pragma push_macro("N")
#undef N
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <boost/dll/runtime_symbol_info.hpp>
#include <boost/filesystem.hpp>
#include <boost/process.hpp>
#include <boost/process/spawn.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/adaptor/transformed.hpp>
......@@ -98,6 +107,8 @@ Options:
#include <boost/range/algorithm/copy.hpp>
#include <boost/algorithm/string/classification.hpp>
#pragma pop_macro("N")
#include <Inline/BasicTypes.h>
#include <IR/Module.h>
#include <IR/Validate.h>
......@@ -633,6 +644,44 @@ struct set_action_permission_subcommand {
}
};
bool port_busy( uint16_t port ) {
using namespace boost::asio;
io_service ios;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port);
boost::asio::ip::tcp::socket socket(ios);
boost::system::error_code ec = error::would_block;
//connecting/failing to connect to localhost should be always fast - don't care about timeouts
socket.async_connect(endpoint, [&](const boost::system::error_code& error) { ec = error; } );
do {
ios.run_one();
} while (ec == error::would_block);
return !ec;
}
void start_keosd( uint16_t wallet_port ) {
auto binPath = boost::dll::program_location();
boost::filesystem::path keosPath = binPath.parent_path().append("keosd"); //cleos and keosd are in the same installation directory
if ( !boost::filesystem::exists(keosPath) ) {
keosPath = binPath.parent_path().parent_path().append("keosd").append("keosd"); //build directory
}
if ( boost::filesystem::exists( keosPath ) ) {
namespace bp = boost::process;
keosPath = boost::filesystem::canonical( keosPath );
::boost::process::child keos( keosPath, "--http-server-address=127.0.0.1:"+std::to_string(wallet_port),
bp::std_in.close(),
bp::std_out > bp::null,
bp::std_err > bp::null);
if (keos.running()) {
std::cerr << keosPath << " launched" << std::endl;
keos.detach();
} else {
std::cerr << "No wallet service listening on 127.0.0.1:" << std::to_string(wallet_port) << ". Failed to launch " << keosPath << std::endl;
}
} else {
std::cerr << "No wallet service listening on 127.0.0.1: " << std::to_string(wallet_port) << ". Cannot automatically start keosd because keosd was not found." << std::endl;
}
}
CLI::callback_t old_host_port = [](CLI::results_t) {
std::cerr << localized("Host and port options (-H, --wallet-host, etc.) have been replaced with -u/--url and --wallet-url\n"
......@@ -1100,11 +1149,6 @@ void get_account( const string& accountName, bool json_format ) {
}
int main( int argc, char** argv ) {
fc::path binPath = argv[0];
if (binPath.is_relative()) {
binPath = relative(binPath, fc::current_path());
}
setlocale(LC_ALL, "");
bindtextdomain(locale_domain, locale_path);
textdomain(locale_domain);
......@@ -1119,6 +1163,15 @@ int main( int argc, char** argv ) {
app.add_option( "-u,--url", url, localized("the http/https URL where nodeos is running"), true );
app.add_option( "--wallet-url", wallet_url, localized("the http/https URL where keosd is running"), true );
auto parsed_url = parse_url( wallet_url );
auto wallet_port_uint = std::stoi(parsed_url.port);
if ( wallet_port_uint < 0 || 65535 < wallet_port_uint ) {
FC_THROW("port is not in valid range");
}
if ( ( parsed_url.server == "localhost" || parsed_url.server == "127.0.0.1" ) && !port_busy( uint16_t(wallet_port_uint) ) ) {
start_keosd( uint16_t(wallet_port_uint) );
}
bool verbose_errors = false;
app.add_flag( "-v,--verbose", verbose_errors, localized("output verbose actions on error"));
......@@ -1688,6 +1741,16 @@ int main( int argc, char** argv ) {
std::cout << fc::json::to_pretty_string(v) << std::endl;
});
auto stopKeosd = wallet->add_subcommand("stop", localized("Stop keosd (doesn't work with nodeos)."), false);
stopKeosd->set_callback([] {
const auto& v = call(wallet_url, keosd_stop);
if ( !v.is_object() || v.get_object().size() != 0 ) { //on success keosd responds with empty object
std::cerr << fc::json::to_pretty_string(v) << std::endl;
} else {
std::cout << "OK" << std::endl;
}
});
// sign subcommand
string trx_json_to_sign;
string str_private_key;
......
......@@ -42,6 +42,8 @@ int main(int argc, char** argv)
app().register_plugin<wallet_api_plugin>();
if(!app().initialize<wallet_plugin, wallet_api_plugin, http_plugin>(argc, argv))
return -1;
auto& http = app().get_plugin<http_plugin>();
http.add_handler("/v1/keosd/stop", [](string, string, url_response_callback cb) { cb(200, "{}"); std::raise(SIGTERM); } );
app().startup();
app().exec();
} catch (const fc::exception& e) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册