added support for unhandled extension and mapping the first registered API to global namespace

This commit is contained in:
Daniel Larimer 2015-03-31 17:45:01 -04:00
parent 1fb31737a7
commit 55ee57040a
4 changed files with 117 additions and 100 deletions

View file

@ -67,6 +67,8 @@ namespace fc {
}; };
} }
} // namespace detail
class generic_api class generic_api
{ {
public: public:
@ -110,14 +112,14 @@ namespace fc {
R call_generic( const std::function<R(std::function<Signature>,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) R call_generic( const std::function<R(std::function<Signature>,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
{ {
FC_ASSERT( a0 != e ); FC_ASSERT( a0 != e );
callback_functor<Signature> arg0( *this, a0->as<uint64_t>() ); detail::callback_functor<Signature> arg0( *this, a0->as<uint64_t>() );
return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f, std::function<Signature>(arg0) ), a0+1, e ); return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f, std::function<Signature>(arg0) ), a0+1, e );
} }
template<typename R, typename Signature, typename ... Args> template<typename R, typename Signature, typename ... Args>
R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
{ {
FC_ASSERT( a0 != e ); FC_ASSERT( a0 != e );
callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>() ); detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>() );
return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f, arg0 ), a0+1, e ); return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f, arg0 ), a0+1, e );
} }
@ -160,7 +162,6 @@ namespace fc {
std::map< std::string, uint32_t > _by_name; std::map< std::string, uint32_t > _by_name;
std::vector< std::function<variant(const variants&)> > _methods; std::vector< std::function<variant(const variants&)> > _methods;
}; // class generic_api }; // class generic_api
} // namespace detail
@ -207,7 +208,7 @@ namespace fc {
auto itr = _handle_to_id.find(handle); auto itr = _handle_to_id.find(handle);
if( itr != _handle_to_id.end() ) return itr->second; if( itr != _handle_to_id.end() ) return itr->second;
_local_apis.push_back( std::unique_ptr<detail::generic_api>( new detail::generic_api(a, shared_from_this() ) ) ); _local_apis.push_back( std::unique_ptr<generic_api>( new generic_api(a, shared_from_this() ) ) );
_handle_to_id[handle] = _local_apis.size() - 1; _handle_to_id[handle] = _local_apis.size() - 1;
return _local_apis.size() - 1; return _local_apis.size() - 1;
} }
@ -220,7 +221,7 @@ namespace fc {
} }
private: private:
std::vector< std::unique_ptr<detail::generic_api> > _local_apis; std::vector< std::unique_ptr<generic_api> > _local_apis;
std::map< uint64_t, api_id_type > _handle_to_id; std::map< uint64_t, api_id_type > _handle_to_id;
std::vector< std::function<variant(const variants&)> > _local_callbacks; std::vector< std::function<variant(const variants&)> > _local_callbacks;
@ -319,14 +320,14 @@ namespace fc {
}; };
template<typename Api> template<typename Api>
detail::generic_api::generic_api( const Api& a, const std::shared_ptr<fc::api_connection>& c ) generic_api::generic_api( const Api& a, const std::shared_ptr<fc::api_connection>& c )
:_api_connection(c),_api(a) :_api_connection(c),_api(a)
{ {
boost::any_cast<const Api&>(a)->visit( api_visitor( *this, _api_connection ) ); boost::any_cast<const Api&>(a)->visit( api_visitor( *this, _api_connection ) );
} }
template<typename Interface, typename Adaptor, typename ... Args> template<typename Interface, typename Adaptor, typename ... Args>
std::function<variant(const fc::variants&)> detail::generic_api::api_visitor::to_generic( std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const
{ {
auto api_con = _api_con; auto api_con = _api_con;
@ -337,7 +338,7 @@ namespace fc {
}; };
} }
template<typename Interface, typename Adaptor, typename ... Args> template<typename Interface, typename Adaptor, typename ... Args>
std::function<variant(const fc::variants&)> detail::generic_api::api_visitor::to_generic( std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
const std::function<fc::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const const std::function<fc::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const
{ {
auto api_con = _api_con; auto api_con = _api_con;
@ -350,7 +351,7 @@ namespace fc {
}; };
} }
template<typename R, typename ... Args> template<typename R, typename ... Args>
std::function<variant(const fc::variants&)> detail::generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
{ {
generic_api* gapi = &api; generic_api* gapi = &api;
return [f,gapi]( const variants& args ) { return [f,gapi]( const variants& args ) {
@ -359,7 +360,7 @@ namespace fc {
} }
template<typename ... Args> template<typename ... Args>
std::function<variant(const fc::variants&)> detail::generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
{ {
generic_api* gapi = &api; generic_api* gapi = &api;
return [f,gapi]( const variants& args ) { return [f,gapi]( const variants& args ) {

View file

@ -45,10 +45,13 @@ namespace fc { namespace rpc {
void close(); void close();
void on_unhandled( const std::function<variant(const string&,const variants&)>& unhandled );
private: private:
uint64_t _next_id = 1; uint64_t _next_id = 1;
std::unordered_map<uint64_t, fc::promise<variant>::ptr> _awaiting; std::unordered_map<uint64_t, fc::promise<variant>::ptr> _awaiting;
std::unordered_map<std::string, method> _methods; std::unordered_map<std::string, method> _methods;
std::function<variant(const string&,const variants&)> _unhandled;
}; };
} } // namespace fc::rpc } } // namespace fc::rpc

View file

@ -19,16 +19,23 @@ namespace fc { namespace rpc {
args[1].as_string(), args[1].as_string(),
args[2].get_array() ); args[2].get_array() );
}); });
_rpc_state.add_method( "notice", [this]( const variants& args ) -> variant { _rpc_state.add_method( "notice", [this]( const variants& args ) -> variant {
FC_ASSERT( args.size() == 2 && args[1].is_array() ); FC_ASSERT( args.size() == 2 && args[1].is_array() );
this->receive_notice( args[0].as_uint64(), args[1].get_array() ); this->receive_notice( args[0].as_uint64(), args[1].get_array() );
return variant(); return variant();
}); });
_rpc_state.add_method( "callback", [this]( const variants& args ) -> variant { _rpc_state.add_method( "callback", [this]( const variants& args ) -> variant {
FC_ASSERT( args.size() == 2 && args[1].is_array() ); FC_ASSERT( args.size() == 2 && args[1].is_array() );
this->receive_callback( args[0].as_uint64(), args[1].get_array() ); this->receive_callback( args[0].as_uint64(), args[1].get_array() );
return variant(); 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); } ); _connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg); } );
} }

View file

@ -21,6 +21,8 @@ void state::remove_method( const fc::string& name )
variant state::local_call( const string& method_name, const variants& args ) variant state::local_call( const string& method_name, const variants& args )
{ {
auto method_itr = _methods.find(method_name); 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) ); FC_ASSERT( method_itr != _methods.end(), "Unknown Method: ${name}", ("name",method_name) );
return method_itr->second(args); 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" )) ); item.second->set_exception( fc::exception_ptr(new FC_EXCEPTION( eof_exception, "connection closed" )) );
_awaiting.clear(); _awaiting.clear();
} }
void state::on_unhandled( const std::function<variant(const string&, const variants&)>& unhandled )
{
_unhandled = unhandled;
}
} } // namespace fc::rpc } } // namespace fc::rpc