FC Updates from BitShares and myself #21
10 changed files with 197 additions and 83 deletions
|
|
@ -1,8 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <boost/asio/signal_set.hpp>
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
/// handler will be called from ASIO thread
|
/// Set a handler to process an IPC (inter process communication) signal.
|
||||||
void set_signal_handler( std::function<void(int)> handler, int signal_num );
|
/// Handler will be called from ASIO thread.
|
||||||
|
/// @return shared pointer to the signal_set that holds the handler
|
||||||
|
std::shared_ptr<boost::asio::signal_set> set_signal_handler( std::function<void(int)> handler, int signal_num );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ namespace fc { namespace rpc {
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
void cancel();
|
||||||
void wait();
|
void wait();
|
||||||
void format_result( const string& method, std::function<string(variant,const variants&)> formatter);
|
void format_result( const string& method, std::function<string(variant,const variants&)> formatter);
|
||||||
|
|
||||||
|
|
@ -40,5 +41,6 @@ namespace fc { namespace rpc {
|
||||||
std::string _prompt = ">>>";
|
std::string _prompt = ">>>";
|
||||||
std::map<string,std::function<string(variant,const variants&)> > _result_formatters;
|
std::map<string,std::function<string(variant,const variants&)> > _result_formatters;
|
||||||
fc::future<void> _run_complete;
|
fc::future<void> _run_complete;
|
||||||
|
fc::thread* _getline_thread = nullptr; ///< Wait for user input in this thread
|
||||||
};
|
};
|
||||||
} }
|
} }
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ namespace fc { namespace rpc {
|
||||||
class websocket_api_connection : public api_connection
|
class websocket_api_connection : public api_connection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_conversion_depth );
|
websocket_api_connection( const std::shared_ptr<fc::http::websocket_connection> &c,
|
||||||
|
uint32_t max_conversion_depth );
|
||||||
~websocket_api_connection();
|
~websocket_api_connection();
|
||||||
|
|
||||||
virtual variant send_call(
|
virtual variant send_call(
|
||||||
|
|
@ -29,8 +30,8 @@ namespace fc { namespace rpc {
|
||||||
const std::string& message,
|
const std::string& message,
|
||||||
bool send_message = true );
|
bool send_message = true );
|
||||||
|
|
||||||
fc::http::websocket_connection& _connection;
|
std::shared_ptr<fc::http::websocket_connection> _connection;
|
||||||
fc::rpc::state _rpc_state;
|
fc::rpc::state _rpc_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace fc::rpc
|
} } // namespace fc::rpc
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,11 @@ namespace fc {
|
||||||
* @todo make quit non-blocking of the calling thread by eliminating the call to <code>boost::thread::join</code>
|
* @todo make quit non-blocking of the calling thread by eliminating the call to <code>boost::thread::join</code>
|
||||||
*/
|
*/
|
||||||
void quit();
|
void quit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send signal to underlying native thread. Only for Linux and macOS
|
||||||
|
*/
|
||||||
|
void signal(int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true unless quit() has been called.
|
* @return true unless quit() has been called.
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,16 @@
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
void set_signal_handler( std::function<void(int)> handler, int signal_num )
|
std::shared_ptr<boost::asio::signal_set> set_signal_handler( std::function<void(int)> handler, int signal_num )
|
||||||
{
|
{
|
||||||
std::shared_ptr<boost::asio::signal_set> sig_set(new boost::asio::signal_set(fc::asio::default_io_service(), signal_num));
|
std::shared_ptr<boost::asio::signal_set> sig_set( new boost::asio::signal_set( fc::asio::default_io_service(),
|
||||||
sig_set->async_wait(
|
signal_num) );
|
||||||
[sig_set,handler]( const boost::system::error_code& err, int num )
|
sig_set->async_wait( [sig_set,handler]( const boost::system::error_code& err, int num )
|
||||||
{
|
{
|
||||||
handler( num );
|
if( err != boost::asio::error::operation_aborted )
|
||||||
sig_set->cancel();
|
handler( num );
|
||||||
// set_signal_handler( handler, signal_num );
|
sig_set->cancel();
|
||||||
} );
|
} );
|
||||||
}
|
return sig_set;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
161
src/rpc/cli.cpp
161
src/rpc/cli.cpp
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#ifdef HAVE_EDITLINE
|
#ifdef HAVE_EDITLINE
|
||||||
# include "editline.h"
|
# include "editline.h"
|
||||||
|
# include <signal.h>
|
||||||
# ifdef WIN32
|
# ifdef WIN32
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
# endif
|
# endif
|
||||||
|
|
@ -53,18 +54,24 @@ void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ )
|
||||||
FC_ASSERT(false);
|
FC_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cli::start()
|
|
||||||
{
|
|
||||||
cli_commands() = get_method_names(0);
|
|
||||||
_run_complete = fc::async( [&](){ run(); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
void cli::stop()
|
void cli::stop()
|
||||||
{
|
{
|
||||||
_run_complete.cancel();
|
cancel();
|
||||||
_run_complete.wait();
|
_run_complete.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cli::cancel()
|
||||||
|
{
|
||||||
|
_run_complete.cancel();
|
||||||
|
#ifdef HAVE_EDITLINE
|
||||||
|
if( _getline_thread )
|
||||||
|
{
|
||||||
|
_getline_thread->signal(SIGINT);
|
||||||
|
_getline_thread = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void cli::wait()
|
void cli::wait()
|
||||||
{
|
{
|
||||||
_run_complete.wait();
|
_run_complete.wait();
|
||||||
|
|
@ -98,6 +105,12 @@ void cli::run()
|
||||||
}
|
}
|
||||||
catch ( const fc::eof_exception& e )
|
catch ( const fc::eof_exception& e )
|
||||||
{
|
{
|
||||||
|
_getline_thread = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch ( const fc::canceled_exception& e )
|
||||||
|
{
|
||||||
|
_getline_thread = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,12 +132,12 @@ void cli::run()
|
||||||
}
|
}
|
||||||
catch ( const fc::exception& e )
|
catch ( const fc::exception& e )
|
||||||
{
|
{
|
||||||
std::cout << e.to_detail_string() << "\n";
|
|
||||||
|
|
||||||
if (e.code() == fc::canceled_exception_code)
|
if (e.code() == fc::canceled_exception_code)
|
||||||
{
|
{
|
||||||
|
_getline_thread = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
std::cout << e.to_detail_string() << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,36 +150,52 @@ void cli::run()
|
||||||
*/
|
*/
|
||||||
static char *my_rl_complete(char *token, int *match)
|
static char *my_rl_complete(char *token, int *match)
|
||||||
{
|
{
|
||||||
bool have_one = false;
|
const auto& cmds = cli_commands();
|
||||||
std::string method_name;
|
|
||||||
|
|
||||||
auto& cmd = cli_commands();
|
|
||||||
const size_t partlen = strlen (token); /* Part of token */
|
const size_t partlen = strlen (token); /* Part of token */
|
||||||
|
|
||||||
for (const std::string& it : cmd)
|
std::vector<std::reference_wrapper<const std::string>> matched_cmds;
|
||||||
|
for( const std::string& it : cmds )
|
||||||
{
|
{
|
||||||
if (it.compare(0, partlen, token) == 0)
|
if( it.compare(0, partlen, token) == 0 )
|
||||||
{
|
{
|
||||||
if (have_one) {
|
matched_cmds.push_back( it );
|
||||||
// we can only have 1, but we found a second
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
method_name = it;
|
|
||||||
have_one = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_one)
|
if( matched_cmds.size() == 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const std::string& first_matched_cmd = matched_cmds[0];
|
||||||
|
if( matched_cmds.size() == 1 )
|
||||||
{
|
{
|
||||||
*match = 1;
|
*match = 1;
|
||||||
method_name += " ";
|
std::string matched_cmd = first_matched_cmd + " ";
|
||||||
return strdup (method_name.c_str() + partlen);
|
return strdup( matched_cmd.c_str() + partlen );
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
size_t first_cmd_len = first_matched_cmd.size();
|
||||||
|
size_t matched_len = partlen;
|
||||||
|
for( ; matched_len < first_cmd_len; ++matched_len )
|
||||||
|
{
|
||||||
|
char next_char = first_matched_cmd[matched_len];
|
||||||
|
bool end = false;
|
||||||
|
for( const std::string& s : matched_cmds )
|
||||||
|
{
|
||||||
|
if( s.size() <= matched_len || s[matched_len] != next_char )
|
||||||
|
{
|
||||||
|
end = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( end )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( matched_len == partlen )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
std::string matched_cmd_part = first_matched_cmd.substr( partlen, matched_len - partlen );
|
||||||
|
return strdup( matched_cmd_part.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
@ -216,6 +245,53 @@ static int cli_check_secret(const char *source)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Indicates whether CLI is quitting after got a SIGINT signal.
|
||||||
|
* In order to be used by editline which is C-style, this is a global variable.
|
||||||
|
*/
|
||||||
|
static int cli_quitting = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get next character from stdin, or EOF if got a SIGINT signal
|
||||||
|
*/
|
||||||
|
static int interruptible_getc(void)
|
||||||
|
{
|
||||||
|
if( cli_quitting )
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
int r;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
r = read(0, &c, 1); // read from stdin, will return -1 on SIGINT
|
||||||
|
|
||||||
|
if( r == -1 && errno == EINTR )
|
||||||
|
cli_quitting = true;
|
||||||
|
|
||||||
|
return r == 1 ? c : EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli::start()
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef HAVE_EDITLINE
|
||||||
|
el_hist_size = 256;
|
||||||
|
|
||||||
|
rl_set_complete_func(my_rl_complete);
|
||||||
|
rl_set_list_possib_func(cli_completion);
|
||||||
|
//rl_set_check_secret_func(cli_check_secret);
|
||||||
|
rl_set_getc_func(interruptible_getc);
|
||||||
|
|
||||||
|
static fc::thread getline_thread("getline");
|
||||||
|
_getline_thread = &getline_thread;
|
||||||
|
|
||||||
|
cli_quitting = false;
|
||||||
|
|
||||||
|
cli_commands() = get_method_names(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_run_complete = fc::async( [this](){ run(); } );
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @brief Read input from the user
|
* @brief Read input from the user
|
||||||
* @param prompt the prompt to display
|
* @param prompt the prompt to display
|
||||||
|
|
@ -237,21 +313,19 @@ void cli::getline( const std::string& prompt, std::string& line)
|
||||||
if( _isatty( _fileno( stdin ) ) )
|
if( _isatty( _fileno( stdin ) ) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
rl_set_complete_func(my_rl_complete);
|
if( _getline_thread )
|
||||||
rl_set_list_possib_func(cli_completion);
|
{
|
||||||
rl_set_check_secret_func(cli_check_secret);
|
_getline_thread->async( [&prompt,&line](){
|
||||||
|
char* line_read = nullptr;
|
||||||
static fc::thread getline_thread("getline");
|
std::cout.flush(); //readline doesn't use cin, so we must manually flush _out
|
||||||
getline_thread.async( [&](){
|
line_read = readline(prompt.c_str());
|
||||||
char* line_read = nullptr;
|
if( line_read == nullptr )
|
||||||
std::cout.flush(); //readline doesn't use cin, so we must manually flush _out
|
FC_THROW_EXCEPTION( fc::eof_exception, "" );
|
||||||
line_read = readline(prompt.c_str());
|
line = line_read;
|
||||||
if( line_read == nullptr )
|
// we don't need here to add line in editline's history, cause it will be doubled
|
||||||
FC_THROW_EXCEPTION( fc::eof_exception, "" );
|
free(line_read);
|
||||||
line = line_read;
|
}).wait();
|
||||||
// we don't need here to add line in editline's history, cause it will be doubled
|
}
|
||||||
free(line_read);
|
|
||||||
}).wait();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -259,7 +333,6 @@ void cli::getline( const std::string& prompt, std::string& line)
|
||||||
std::cout << prompt;
|
std::cout << prompt;
|
||||||
// sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline");
|
// sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline");
|
||||||
fc::getline( fc::cin, line );
|
fc::getline( fc::cin, line );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ websocket_api_connection::~websocket_api_connection()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_depth )
|
websocket_api_connection::websocket_api_connection( const std::shared_ptr<fc::http::websocket_connection>& c,
|
||||||
|
uint32_t max_depth )
|
||||||
: api_connection(max_depth),_connection(c)
|
: api_connection(max_depth),_connection(c)
|
||||||
{
|
{
|
||||||
|
FC_ASSERT( _connection, "A valid websocket connection is required" );
|
||||||
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
|
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
|
||||||
{
|
{
|
||||||
FC_ASSERT( args.size() == 3 && args[2].is_array() );
|
FC_ASSERT( args.size() == 3 && args[2].is_array() );
|
||||||
|
|
@ -47,9 +49,9 @@ websocket_api_connection::websocket_api_connection( fc::http::websocket_connecti
|
||||||
return this->receive_call( 0, method_name, args );
|
return this->receive_call( 0, method_name, args );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
_connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg,true); } );
|
_connection->on_message_handler( [this]( const std::string& msg ){ on_message(msg,true); } );
|
||||||
_connection.on_http_handler( [&]( const std::string& msg ){ return on_message(msg,false); } );
|
_connection->on_http_handler( [this]( const std::string& msg ){ return on_message(msg,false); } );
|
||||||
_connection.closed.connect( [this](){ closed(); } );
|
_connection->closed.connect( [this](){ closed(); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
variant websocket_api_connection::send_call(
|
variant websocket_api_connection::send_call(
|
||||||
|
|
@ -57,9 +59,13 @@ variant websocket_api_connection::send_call(
|
||||||
string method_name,
|
string method_name,
|
||||||
variants args /* = variants() */ )
|
variants args /* = variants() */ )
|
||||||
{
|
{
|
||||||
auto request = _rpc_state.start_remote_call( "call", {api_id, std::move(method_name), std::move(args) } );
|
if( !_connection ) // defensive check
|
||||||
_connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth),
|
return variant(); // TODO return an error?
|
||||||
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) );
|
|
||||||
|
auto request = _rpc_state.start_remote_call( "call", { api_id, std::move(method_name), std::move(args) } );
|
||||||
|
_connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ),
|
||||||
|
fc::json::stringify_large_ints_and_doubles,
|
||||||
|
_max_conversion_depth ) );
|
||||||
return _rpc_state.wait_for_response( *request.id );
|
return _rpc_state.wait_for_response( *request.id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,9 +73,13 @@ variant websocket_api_connection::send_callback(
|
||||||
uint64_t callback_id,
|
uint64_t callback_id,
|
||||||
variants args /* = variants() */ )
|
variants args /* = variants() */ )
|
||||||
{
|
{
|
||||||
auto request = _rpc_state.start_remote_call( "callback", {callback_id, std::move(args) } );
|
if( !_connection ) // defensive check
|
||||||
_connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth),
|
return variant(); // TODO return an error?
|
||||||
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) );
|
|
||||||
|
auto request = _rpc_state.start_remote_call( "callback", { callback_id, std::move(args) } );
|
||||||
|
_connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ),
|
||||||
|
fc::json::stringify_large_ints_and_doubles,
|
||||||
|
_max_conversion_depth ) );
|
||||||
return _rpc_state.wait_for_response( *request.id );
|
return _rpc_state.wait_for_response( *request.id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,9 +87,13 @@ void websocket_api_connection::send_notice(
|
||||||
uint64_t callback_id,
|
uint64_t callback_id,
|
||||||
variants args /* = variants() */ )
|
variants args /* = variants() */ )
|
||||||
{
|
{
|
||||||
fc::rpc::request req{ optional<uint64_t>(), "notice", {callback_id, std::move(args)}};
|
if( !_connection ) // defensive check
|
||||||
_connection.send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth),
|
return;
|
||||||
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) );
|
|
||||||
|
fc::rpc::request req{ optional<uint64_t>(), "notice", { callback_id, std::move(args) } };
|
||||||
|
_connection->send_message( fc::json::to_string( fc::variant( req, _max_conversion_depth ),
|
||||||
|
fc::json::stringify_large_ints_and_doubles,
|
||||||
|
_max_conversion_depth ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string websocket_api_connection::on_message(
|
std::string websocket_api_connection::on_message(
|
||||||
|
|
@ -109,16 +123,20 @@ std::string websocket_api_connection::on_message(
|
||||||
auto end = time_point::now();
|
auto end = time_point::now();
|
||||||
|
|
||||||
if( end - start > fc::milliseconds( LOG_LONG_API_MAX_MS ) )
|
if( end - start > fc::milliseconds( LOG_LONG_API_MAX_MS ) )
|
||||||
elog( "API call execution time limit exceeded. method: ${m} params: ${p} time: ${t}", ("m",call.method)("p",call.params)("t", end - start) );
|
elog( "API call execution time limit exceeded. method: ${m} params: ${p} time: ${t}",
|
||||||
|
("m",call.method)("p",call.params)("t", end - start) );
|
||||||
else if( end - start > fc::milliseconds( LOG_LONG_API_WARN_MS ) )
|
else if( end - start > fc::milliseconds( LOG_LONG_API_WARN_MS ) )
|
||||||
wlog( "API call execution time nearing limit. method: ${m} params: ${p} time: ${t}", ("m",call.method)("p",call.params)("t", end - start) );
|
wlog( "API call execution time nearing limit. method: ${m} params: ${p} time: ${t}",
|
||||||
|
("m",call.method)("p",call.params)("t", end - start) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( call.id )
|
if( call.id )
|
||||||
{
|
{
|
||||||
auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
|
auto reply = fc::json::to_string( response( *call.id, result, "2.0" ),
|
||||||
if( send_message )
|
fc::json::stringify_large_ints_and_doubles,
|
||||||
_connection.send_message( reply );
|
_max_conversion_depth );
|
||||||
|
if( send_message && _connection )
|
||||||
|
_connection->send_message( reply );
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,8 +153,8 @@ std::string websocket_api_connection::on_message(
|
||||||
|
|
||||||
auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ),
|
auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ),
|
||||||
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
|
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
|
||||||
if( send_message )
|
if( send_message && _connection )
|
||||||
_connection.send_message( reply );
|
_connection->send_message( reply );
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,17 @@ namespace fc {
|
||||||
|
|
||||||
void thread::debug( const std::string& d ) { /*my->debug(d);*/ }
|
void thread::debug( const std::string& d ) { /*my->debug(d);*/ }
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void thread::signal(int sig)
|
||||||
|
{
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
pthread_kill( my->boost_thread->native_handle(), sig );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void thread::quit()
|
void thread::quit()
|
||||||
{
|
{
|
||||||
//if quitting from a different thread, start quit task on thread.
|
//if quitting from a different thread, start quit task on thread.
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ int main( int argc, char** argv )
|
||||||
|
|
||||||
fc::http::websocket_server server;
|
fc::http::websocket_server server;
|
||||||
server.on_connection([&]( const websocket_connection_ptr& c ){
|
server.on_connection([&]( const websocket_connection_ptr& c ){
|
||||||
auto wsc = std::make_shared<websocket_api_connection>(*c, MAX_DEPTH);
|
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
||||||
auto login = std::make_shared<login_api>();
|
auto login = std::make_shared<login_api>();
|
||||||
login->calc = calc_api;
|
login->calc = calc_api;
|
||||||
wsc->register_api(fc::api<login_api>(login));
|
wsc->register_api(fc::api<login_api>(login));
|
||||||
|
|
@ -76,7 +76,7 @@ int main( int argc, char** argv )
|
||||||
try {
|
try {
|
||||||
fc::http::websocket_client client;
|
fc::http::websocket_client client;
|
||||||
auto con = client.connect( "ws://localhost:8090" );
|
auto con = client.connect( "ws://localhost:8090" );
|
||||||
auto apic = std::make_shared<websocket_api_connection>(*con, MAX_DEPTH);
|
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
||||||
auto remote_login_api = apic->get_remote_api<login_api>();
|
auto remote_login_api = apic->get_remote_api<login_api>();
|
||||||
auto remote_calc = remote_login_api->get_calc();
|
auto remote_calc = remote_login_api->get_calc();
|
||||||
remote_calc->on_result( []( uint32_t r ) { elog( "callback result ${r}", ("r",r) ); } );
|
remote_calc->on_result( []( uint32_t r ) { elog( "callback result ${r}", ("r",r) ); } );
|
||||||
|
|
|
||||||
2
vendor/editline
vendored
2
vendor/editline
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit fbb1f8800adbb70264fa3893dc221f524e25708c
|
Subproject commit 13f8d5f69c3a048e0b6bdb979d617940eed32ef0
|
||||||
Loading…
Reference in a new issue