196 lines
7.4 KiB
C++
196 lines
7.4 KiB
C++
#pragma once
|
|
#include <fc/json_rpc_error_object.hpp>
|
|
#include <fc/json.hpp>
|
|
#include <fc/future.hpp>
|
|
#include <fc/function.hpp>
|
|
#include <fc/ptr.hpp>
|
|
|
|
namespace fc { namespace json {
|
|
class rpc_connection;
|
|
class error_object;
|
|
|
|
struct rpc_server_method : public fc::retainable {
|
|
typedef fc::shared_ptr<rpc_server_method> ptr;
|
|
virtual value call( const value& v ) = 0;
|
|
};
|
|
|
|
namespace detail {
|
|
struct pending_result : virtual public promise_base {
|
|
typedef shared_ptr<pending_result> ptr;
|
|
virtual void handle_result( const fc::value& ) = 0;
|
|
void handle_error( const fc::string& );
|
|
int64_t id;
|
|
pending_result::ptr next;
|
|
protected:
|
|
~pending_result(){}
|
|
};
|
|
template<typename T>
|
|
struct pending_result_impl : virtual public promise<T>, virtual public pending_result {
|
|
virtual void handle_result( const fc::value& s ) {
|
|
this->set_value( value_cast<T>(s) );
|
|
}
|
|
protected:
|
|
~pending_result_impl(){}
|
|
};
|
|
template<>
|
|
struct pending_result_impl<void> : virtual public promise<void>, virtual public pending_result {
|
|
virtual void handle_result( const fc::value& ) {
|
|
set_value();
|
|
}
|
|
protected:
|
|
~pending_result_impl(){}
|
|
};
|
|
|
|
template<typename T>
|
|
struct named_param {
|
|
typedef fc::false_type type;
|
|
static T cast( const value& v ) { return fc::value_cast<T>(v); }
|
|
|
|
template<typename X>
|
|
static value to_value( X&& x ) { return value(fc::forward<X>(x)); }
|
|
};
|
|
|
|
#define FC_JSON_NAMED_PARAMS( T ) \
|
|
namespace fc { namespace json {namespace detail { \
|
|
template<> \
|
|
struct named_param< fc::tuple<T> > { \
|
|
typedef fc::true_type type; \
|
|
static tuple<T> cast( const value& v ) { return make_tuple(fc::value_cast<T>(v)); } \
|
|
template<typename X> \
|
|
static value to_value( X&& x ) { return value( x.a0 ); }\
|
|
}; \
|
|
} } }
|
|
|
|
template<typename R, typename ArgsTuple, typename Signature>
|
|
struct rpc_server_method_impl : public rpc_server_method {
|
|
rpc_server_method_impl( const std::function<Signature>& f ):func(f){}
|
|
virtual value call( const value& v ) {
|
|
return value( fc::call_fused(func, named_param<typename deduce<ArgsTuple>::type>::cast(v) ) );
|
|
}
|
|
std::function<Signature> func;
|
|
};
|
|
template<typename ArgsTuple, typename Signature>
|
|
struct rpc_server_method_impl<void,ArgsTuple,Signature> : public rpc_server_method {
|
|
rpc_server_method_impl( const std::function<Signature>& f ):func(f){}
|
|
virtual value call( const value& v ) {
|
|
fc::call_fused(func, named_param<typename deduce<ArgsTuple>::type>::cast(v) );
|
|
return value();
|
|
}
|
|
std::function<Signature> func;
|
|
};
|
|
|
|
template<typename InterfaceType>
|
|
struct add_method_visitor {
|
|
public:
|
|
add_method_visitor( const fc::ptr<InterfaceType>& p, fc::json::rpc_connection& c ):_ptr(p),_con(c){}
|
|
|
|
template<typename R>
|
|
void operator()( const char* name, std::function<R()>& meth);
|
|
template<typename R, typename A1>
|
|
void operator()( const char* name, std::function<R(A1)>& meth);
|
|
template<typename R, typename A1, typename A2>
|
|
void operator()( const char* name, std::function<R(A1,A2)>& meth);
|
|
template<typename R, typename A1, typename A2, typename A3>
|
|
void operator()( const char* name, std::function<R(A1,A2,A3)>& meth);
|
|
|
|
const fc::ptr<InterfaceType>& _ptr;
|
|
fc::json::rpc_connection& _con;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* This is the base JSON RPC connection that handles the protocol
|
|
* level issues. It does not implement a transport which should
|
|
* be provided separately and use the handle_message and set_send_delegate
|
|
* methods to manage the protocol.
|
|
*/
|
|
class rpc_connection : public fc::retainable {
|
|
public:
|
|
rpc_connection();
|
|
rpc_connection(const rpc_connection&);
|
|
rpc_connection(rpc_connection&&);
|
|
~rpc_connection();
|
|
rpc_connection& operator=(const rpc_connection&);
|
|
rpc_connection& operator=(rpc_connection&&);
|
|
|
|
typedef fc::shared_ptr<rpc_connection> ptr;
|
|
|
|
void cancel_pending_requests();
|
|
|
|
template<typename R, typename Args >
|
|
future<R> invoke( const fc::string& method, Args&& a = nullptr ){
|
|
auto r = new detail::pending_result_impl<R>();
|
|
typename promise<R>::ptr rtn( r, true );
|
|
invoke( detail::pending_result::ptr(r), method,
|
|
value(detail::named_param<typename fc::deduce<Args>::type>::to_value(a)) );
|
|
return rtn;
|
|
}
|
|
|
|
template<typename Args >
|
|
void notice( const fc::string& method, Args&& a = nullptr ){
|
|
send_notice( method,
|
|
value(detail::named_param<typename fc::deduce<Args>::type>::to_value(a)) );
|
|
}
|
|
|
|
template<typename InterfaceType>
|
|
void add_interface( const fc::ptr<InterfaceType>& it ) {
|
|
it->TEMPLATE visit( detail::add_method_visitor<InterfaceType>( it, *this ) );
|
|
}
|
|
|
|
void add_method( const fc::string& name, const fc::json::rpc_server_method::ptr& func );
|
|
|
|
virtual void close(){};
|
|
|
|
protected:
|
|
void handle_message( const value& m );
|
|
virtual void send_notice( const fc::string& m, value&& param ) = 0;
|
|
virtual void send_invoke( uint64_t id, const fc::string& m, value&& param ) = 0;
|
|
virtual void send_error( uint64_t id, const error_object& e ) = 0;
|
|
virtual void send_result( uint64_t id, value&& r ) = 0;
|
|
|
|
|
|
private:
|
|
void invoke( detail::pending_result::ptr&& p, const fc::string& m, value&& param );
|
|
void add_method( const fc::string& name, rpc_server_method::ptr&& m );
|
|
template<typename InterfaceType>
|
|
friend struct detail::add_method_visitor;
|
|
|
|
class impl;
|
|
fc::shared_ptr<class impl> my;
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
template<typename InterfaceType>
|
|
template<typename R, typename A1>
|
|
void add_method_visitor<InterfaceType>::operator()( const char* name,
|
|
std::function<R(A1)>& meth) {
|
|
_con.add_method( name, rpc_server_method::ptr(
|
|
new rpc_server_method_impl<R,tuple<A1>,R(A1) >(meth) ) );
|
|
}
|
|
template<typename InterfaceType>
|
|
template<typename R, typename A1, typename A2>
|
|
void add_method_visitor<InterfaceType>::operator()( const char* name,
|
|
std::function<R(A1,A2)>& meth) {
|
|
_con.add_method( name, rpc_server_method::ptr(
|
|
new rpc_server_method_impl<R,tuple<A1,A2>,R(A1,A2) >(meth) ) );
|
|
}
|
|
template<typename InterfaceType>
|
|
template<typename R, typename A1, typename A2, typename A3>
|
|
void add_method_visitor<InterfaceType>::operator()( const char* name,
|
|
std::function<R(A1,A2,A3)>& meth) {
|
|
_con.add_method( name, rpc_server_method::ptr(
|
|
new rpc_server_method_impl<R,tuple<A1,A2,A3>,R(A1,A2,A3) >(meth) ) );
|
|
}
|
|
template<typename InterfaceType>
|
|
template<typename R>
|
|
void add_method_visitor<InterfaceType>::operator()( const char* name,
|
|
std::function<R()>& meth) {
|
|
_con.add_method( name, rpc_server_method::ptr(
|
|
new rpc_server_method_impl<R,tuple<>,R() >(meth) ) );
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
} } // fc::json
|
|
|