#pragma once #include #include #include #include #include namespace fc { namespace json { class rpc_connection; class error_object; struct rpc_server_method : public fc::retainable { typedef fc::shared_ptr ptr; virtual value call( const value& v ) = 0; }; namespace detail { struct pending_result : virtual public promise_base { typedef shared_ptr 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 struct pending_result_impl : virtual public promise, virtual public pending_result { virtual void handle_result( const fc::value& s ) { this->set_value( value_cast(s) ); } protected: ~pending_result_impl(){} }; template<> struct pending_result_impl : virtual public promise, virtual public pending_result { virtual void handle_result( const fc::value& ) { set_value(); } protected: ~pending_result_impl(){} }; template struct named_param { typedef fc::false_type type; static T cast( const value& v ) { return fc::value_cast(v); } template static value to_value( X&& x ) { return value(fc::forward(x)); } }; #define FC_JSON_NAMED_PARAMS( T ) \ namespace fc { namespace json {namespace detail { \ template<> \ struct named_param< fc::tuple > { \ typedef fc::true_type type; \ static tuple cast( const value& v ) { return make_tuple(fc::value_cast(v)); } \ template \ static value to_value( X&& x ) { return value( x.a0 ); }\ }; \ } } } template struct rpc_server_method_impl : public rpc_server_method { rpc_server_method_impl( const std::function& f ):func(f){} virtual value call( const value& v ) { return value( fc::call_fused(func, named_param::type>::cast(v) ) ); } std::function func; }; template struct rpc_server_method_impl : public rpc_server_method { rpc_server_method_impl( const std::function& f ):func(f){} virtual value call( const value& v ) { fc::call_fused(func, named_param::type>::cast(v) ); return value(); } std::function func; }; template struct add_method_visitor { public: add_method_visitor( const fc::ptr& p, fc::json::rpc_connection& c ):_ptr(p),_con(c){} template void operator()( const char* name, std::function& meth); template void operator()( const char* name, std::function& meth); template void operator()( const char* name, std::function& meth); template void operator()( const char* name, std::function& meth); const fc::ptr& _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 ptr; void cancel_pending_requests(); template future invoke( const fc::string& method, Args&& a = nullptr ){ auto r = new detail::pending_result_impl(); typename promise::ptr rtn( r, true ); invoke( detail::pending_result::ptr(r), method, value(detail::named_param::type>::to_value(a)) ); return rtn; } template void notice( const fc::string& method, Args&& a = nullptr ){ send_notice( method, value(detail::named_param::type>::to_value(a)) ); } template void add_interface( const fc::ptr& it ) { it->TEMPLATE visit( detail::add_method_visitor( it, *this ) ); } void add_method( const fc::string& name, const fc::json::rpc_server_method::ptr& func ); 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 friend struct detail::add_method_visitor; class impl; fc::shared_ptr my; }; namespace detail { template template void add_method_visitor::operator()( const char* name, std::function& meth) { _con.add_method( name, rpc_server_method::ptr( new rpc_server_method_impl,R(A1) >(meth) ) ); } template template void add_method_visitor::operator()( const char* name, std::function& meth) { _con.add_method( name, rpc_server_method::ptr( new rpc_server_method_impl,R(A1,A2) >(meth) ) ); } template template void add_method_visitor::operator()( const char* name, std::function& meth) { _con.add_method( name, rpc_server_method::ptr( new rpc_server_method_impl,R(A1,A2,A3) >(meth) ) ); } template template void add_method_visitor::operator()( const char* name, std::function& meth) { _con.add_method( name, rpc_server_method::ptr( new rpc_server_method_impl,R() >(meth) ) ); } } // namespace detail } } // fc::json