#pragma once #include #include #include #include #include namespace fc { namespace json { class rpc_connection; struct rpc_server_function : 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 rpc_server_function_impl : public rpc_server_function { rpc_server_function_impl( const fc::function& f ):func(f){} virtual value call( const value& v ) { return value( func( fc::value_cast( v ) ) ); } fc::function func; }; template struct add_method_visitor { public: add_method_visitor( const fc::ptr& p, fc::json::rpc_connection& c ):_ptr(p){} template void operator()( const char* name, fc::function& meth, Type ); const fc::ptr& _ptr; fc::json::rpc_connection& _con; }; } /** * This class can be used to communicate via json-rpc over a pair of * streams. * * @note rpc_connection has reference semantics and all 'copies' will * refer to the same underlying stream. */ class rpc_connection { public: rpc_connection(); /** note the life of i and o must be longer than rpc_connection's life */ rpc_connection( istream& i, ostream& o ); rpc_connection( rpc_connection&& c ); rpc_connection( const rpc_connection& c ); ~rpc_connection(); rpc_connection& operator=(rpc_connection&& m); rpc_connection& operator=(const rpc_connection& m); /** note the life of i and o must be longer than rpc_connection's life */ void init( istream& i, ostream& o ); template future invoke( const fc::string& method, Args&& a = nullptr )const { auto r = new detail::pending_result_impl(); typename promise::ptr rtn( r, true ); invoke( detail::pending_result::ptr(r), method, value(fc::forward(a)) ); return rtn; } 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_function::ptr& func ); private: void invoke( detail::pending_result::ptr&& p, const fc::string& m, const value& param )const; class impl; fc::shared_ptr my; }; namespace detail { template template void add_method_visitor::operator()( const char* name, fc::function& meth, Type ) { _con.add_method( name, rpc_server_function::ptr( new rpc_server_function_impl(meth) ) ); } } // namespace detail } } // fc::json