diff --git a/include/fc/rpc/api_connection.hpp b/include/fc/rpc/api_connection.hpp index aece532..1f1c6f5 100644 --- a/include/fc/rpc/api_connection.hpp +++ b/include/fc/rpc/api_connection.hpp @@ -67,101 +67,102 @@ namespace fc { }; } - class generic_api - { - public: - template - generic_api( const Api& a, const std::shared_ptr& c ); - - generic_api( const generic_api& cpy ) = delete; - - variant call( const string& name, const variants& args ) - { - auto itr = _by_name.find(name); - FC_ASSERT( itr != _by_name.end() ); - return call( itr->second, args ); - } - - variant call( uint32_t method_id, const variants& args ) - { - FC_ASSERT( method_id < _methods.size() ); - return _methods[method_id](args); - } - - fc::api_connection& get_connection(){ return *_api_connection; } - - - private: - friend struct api_visitor; - - template - std::function bind_first_arg( const std::function& f, Arg0 a0 )const - { - return [=]( Args... args ) { return f( a0, args... ); }; - } - - template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e )const - { - return f(); - } - - template - R call_generic( const std::function,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) - { - FC_ASSERT( a0 != e ); - callback_functor arg0( *this, a0->as() ); - return call_generic( this->bind_first_arg,Args...>( f, std::function(arg0) ), a0+1, e ); - } - template - R call_generic( const std::function&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) - { - FC_ASSERT( a0 != e ); - callback_functor arg0( get_connection(), a0->as() ); - return call_generic( this->bind_first_arg&,Args...>( f, arg0 ), a0+1, e ); - } - - template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e ) - { - FC_ASSERT( a0 != e ); - return call_generic( this->bind_first_arg( f, a0->as< typename std::decay::type >() ), a0+1, e ); - } - - struct api_visitor - { - api_visitor( generic_api& a, const std::shared_ptr& s ):api(a),_api_con(s){ } - - template - std::function to_generic( const std::function(Args...)>& f )const; - - template - std::function to_generic( const std::function>(Args...)>& f )const; - - template - std::function to_generic( const std::function& f )const; - - template - std::function to_generic( const std::function& f )const; - - template - void operator()( const char* name, std::function& memb )const { - api._methods.emplace_back( to_generic( memb ) ); - api._by_name[name] = api._methods.size() - 1; - } - - generic_api& api; - const std::shared_ptr& _api_con; - }; - - - std::shared_ptr _api_connection; - fc::any _api; - std::map< std::string, uint32_t > _by_name; - std::vector< std::function > _methods; - }; // class generic_api } // namespace detail + class generic_api + { + public: + template + generic_api( const Api& a, const std::shared_ptr& c ); + + generic_api( const generic_api& cpy ) = delete; + + variant call( const string& name, const variants& args ) + { + auto itr = _by_name.find(name); + FC_ASSERT( itr != _by_name.end() ); + return call( itr->second, args ); + } + + variant call( uint32_t method_id, const variants& args ) + { + FC_ASSERT( method_id < _methods.size() ); + return _methods[method_id](args); + } + + fc::api_connection& get_connection(){ return *_api_connection; } + + + private: + friend struct api_visitor; + + template + std::function bind_first_arg( const std::function& f, Arg0 a0 )const + { + return [=]( Args... args ) { return f( a0, args... ); }; + } + + template + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e )const + { + return f(); + } + + template + R call_generic( const std::function,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) + { + FC_ASSERT( a0 != e ); + detail::callback_functor arg0( *this, a0->as() ); + return call_generic( this->bind_first_arg,Args...>( f, std::function(arg0) ), a0+1, e ); + } + template + R call_generic( const std::function&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) + { + FC_ASSERT( a0 != e ); + detail::callback_functor arg0( get_connection(), a0->as() ); + return call_generic( this->bind_first_arg&,Args...>( f, arg0 ), a0+1, e ); + } + + template + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e ) + { + FC_ASSERT( a0 != e ); + return call_generic( this->bind_first_arg( f, a0->as< typename std::decay::type >() ), a0+1, e ); + } + + struct api_visitor + { + api_visitor( generic_api& a, const std::shared_ptr& s ):api(a),_api_con(s){ } + + template + std::function to_generic( const std::function(Args...)>& f )const; + + template + std::function to_generic( const std::function>(Args...)>& f )const; + + template + std::function to_generic( const std::function& f )const; + + template + std::function to_generic( const std::function& f )const; + + template + void operator()( const char* name, std::function& memb )const { + api._methods.emplace_back( to_generic( memb ) ); + api._by_name[name] = api._methods.size() - 1; + } + + generic_api& api; + const std::shared_ptr& _api_con; + }; + + + std::shared_ptr _api_connection; + fc::any _api; + std::map< std::string, uint32_t > _by_name; + std::vector< std::function > _methods; + }; // class generic_api + class api_connection : public std::enable_shared_from_this @@ -207,7 +208,7 @@ namespace fc { auto itr = _handle_to_id.find(handle); if( itr != _handle_to_id.end() ) return itr->second; - _local_apis.push_back( std::unique_ptr( new detail::generic_api(a, shared_from_this() ) ) ); + _local_apis.push_back( std::unique_ptr( new generic_api(a, shared_from_this() ) ) ); _handle_to_id[handle] = _local_apis.size() - 1; return _local_apis.size() - 1; } @@ -220,7 +221,7 @@ namespace fc { } private: - std::vector< std::unique_ptr > _local_apis; + std::vector< std::unique_ptr > _local_apis; std::map< uint64_t, api_id_type > _handle_to_id; std::vector< std::function > _local_callbacks; @@ -319,14 +320,14 @@ namespace fc { }; template - detail::generic_api::generic_api( const Api& a, const std::shared_ptr& c ) + generic_api::generic_api( const Api& a, const std::shared_ptr& c ) :_api_connection(c),_api(a) { boost::any_cast(a)->visit( api_visitor( *this, _api_connection ) ); } template - std::function detail::generic_api::api_visitor::to_generic( + std::function generic_api::api_visitor::to_generic( const std::function(Args...)>& f )const { auto api_con = _api_con; @@ -337,7 +338,7 @@ namespace fc { }; } template - std::function detail::generic_api::api_visitor::to_generic( + std::function generic_api::api_visitor::to_generic( const std::function>(Args...)>& f )const { auto api_con = _api_con; @@ -350,7 +351,7 @@ namespace fc { }; } template - std::function detail::generic_api::api_visitor::to_generic( const std::function& f )const + std::function generic_api::api_visitor::to_generic( const std::function& f )const { generic_api* gapi = &api; return [f,gapi]( const variants& args ) { @@ -359,7 +360,7 @@ namespace fc { } template - std::function detail::generic_api::api_visitor::to_generic( const std::function& f )const + std::function generic_api::api_visitor::to_generic( const std::function& f )const { generic_api* gapi = &api; return [f,gapi]( const variants& args ) { diff --git a/include/fc/rpc/state.hpp b/include/fc/rpc/state.hpp index f870750..3c36bcf 100644 --- a/include/fc/rpc/state.hpp +++ b/include/fc/rpc/state.hpp @@ -45,10 +45,13 @@ namespace fc { namespace rpc { void close(); + void on_unhandled( const std::function& unhandled ); + private: uint64_t _next_id = 1; std::unordered_map::ptr> _awaiting; std::unordered_map _methods; + std::function _unhandled; }; } } // namespace fc::rpc diff --git a/include/fc/rpc/websocket_api.hpp b/include/fc/rpc/websocket_api.hpp index 833c0e1..fa0158b 100644 --- a/include/fc/rpc/websocket_api.hpp +++ b/include/fc/rpc/websocket_api.hpp @@ -19,16 +19,23 @@ namespace fc { namespace rpc { args[1].as_string(), args[2].get_array() ); }); + _rpc_state.add_method( "notice", [this]( const variants& args ) -> variant { FC_ASSERT( args.size() == 2 && args[1].is_array() ); this->receive_notice( args[0].as_uint64(), args[1].get_array() ); return variant(); }); + _rpc_state.add_method( "callback", [this]( const variants& args ) -> variant { FC_ASSERT( args.size() == 2 && args[1].is_array() ); this->receive_callback( args[0].as_uint64(), args[1].get_array() ); return variant(); }); + + _rpc_state.on_unhandled( [&]( const std::string& method_name, const variants& args ){ + return this->receive_call( 0, method_name, args ); + }); + _connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg); } ); } diff --git a/src/rpc/state.cpp b/src/rpc/state.cpp index eec8584..b5cb95f 100644 --- a/src/rpc/state.cpp +++ b/src/rpc/state.cpp @@ -21,6 +21,8 @@ void state::remove_method( const fc::string& name ) variant state::local_call( const string& method_name, const variants& args ) { auto method_itr = _methods.find(method_name); + if( method_itr == _methods.end() && _unhandled ) + return _unhandled( method_name, args ); FC_ASSERT( method_itr != _methods.end(), "Unknown Method: ${name}", ("name",method_name) ); return method_itr->second(args); } @@ -58,5 +60,9 @@ void state::close() item.second->set_exception( fc::exception_ptr(new FC_EXCEPTION( eof_exception, "connection closed" )) ); _awaiting.clear(); } +void state::on_unhandled( const std::function& unhandled ) +{ + _unhandled = unhandled; +} } } // namespace fc::rpc