From 171eb212cd7e68ef2a42f336cb796795fe3e725e Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Wed, 11 Mar 2015 10:49:30 -0400 Subject: [PATCH] refactor api_client and api_server into api_connection and add JSON impl --- include/fc/api.hpp | 14 +- include/fc/rpc/api_client.hpp | 56 ------- include/fc/rpc/api_connection.hpp | 261 ++++++++++++++++++++++++++++++ include/fc/rpc/api_server.hpp | 179 -------------------- tests/api.cpp | 29 +++- 5 files changed, 290 insertions(+), 249 deletions(-) delete mode 100644 include/fc/rpc/api_client.hpp create mode 100644 include/fc/rpc/api_connection.hpp delete mode 100644 include/fc/rpc/api_server.hpp diff --git a/include/fc/api.hpp b/include/fc/api.hpp index 68c159c..943aedd 100644 --- a/include/fc/api.hpp +++ b/include/fc/api.hpp @@ -68,22 +68,14 @@ namespace fc { _vtable->template visit_other( vtable_copy_visitor(pointed_at) ); } - template - api( const std::shared_ptr< api >& p ) - :_vtable( std::make_shared() ) - { - _data = std::make_shared(p); - auto& ptr = *boost::any_cast< decltype(p) >(*_data); - auto& pointed_at = *ptr; - typedef typename std::remove_reference::type source_vtable_type; - _vtable->template visit_other( vtable_copy_visitor(pointed_at) ); - } - api( const api& cpy ) :_vtable(cpy._vtable),_data(cpy._data) { } + friend bool operator == ( const api& a, const api& b ) { return a._data == b._data && a._vtable == b._vtable; } + friend bool operator != ( const api& a, const api& b ) { return !(a._data == b._data && a._vtable == b._vtable); } + vtable_type& operator*()const { wdump((uint64_t(this))); assert(_vtable); FC_ASSERT( _vtable ); return *_vtable; } vtable_type* operator->()const { assert(_vtable); diff --git a/include/fc/rpc/api_client.hpp b/include/fc/rpc/api_client.hpp deleted file mode 100644 index d1841c3..0000000 --- a/include/fc/rpc/api_client.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include - -namespace fc { - - template - class api_client : public api - { - public: - api_client( fc::api server, uint64_t api_id = 0 ) - { - (*this)->visit( api_visitor(this, api_id, std::make_shared>(server)) ); - } - - private: - struct api_visitor - { - api_client* _client = nullptr; - uint32_t _api_id; - std::shared_ptr> _server; - - api_visitor( api_client* c, uint32_t api_id, std::shared_ptr> serv ) - :_client(c),_api_id(api_id),_server(std::move(serv)) - { wdump((int64_t(c))); } - - api_visitor() = delete; - - template - static Result from_variant( const variant& v, Result&&, const std::shared_ptr>& ) - { - return v.as(); - } - - template - static fc::api from_variant( const variant& v, fc::api&&, - const std::shared_ptr>& serv - ) - { - return api_client( serv, v.as_uint64() ); - } - - - template - void operator()( const char* name, std::function& memb )const - { - auto serv = _server; - auto api_id = _api_id; - memb = [serv,api_id,name]( Args... args ) { - vtable test; - auto var_result = (*serv)->call( api_id, name, {args...} ); - return from_variant( var_result, Result(), serv ); - }; - } - }; - }; -} diff --git a/include/fc/rpc/api_connection.hpp b/include/fc/rpc/api_connection.hpp new file mode 100644 index 0000000..9e9eb22 --- /dev/null +++ b/include/fc/rpc/api_connection.hpp @@ -0,0 +1,261 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { + class api_connection; + + typedef uint32_t api_id_type; + + 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); + } + + private: + friend struct api_visitor; + + struct api_visitor + { + api_visitor( generic_api& a, const std::shared_ptr& s ):api(a),_api_con(s){ } + + 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& f, variants::const_iterator a0, variants::const_iterator e )const + { + FC_ASSERT( a0 != e ); + return f(a0->as()); + } + */ + + template + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e )const + { + FC_ASSERT( a0 != e ); + return call_generic( bind_first_arg( f, a0->as() ), a0+1, e ); + } + + 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 + { + return [=]( const variants& args ) { + return call_generic( f, args.begin(), args.end() ); + }; + } + + 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 api_connection : public std::enable_shared_from_this + { + public: + api_connection(){} + virtual ~api_connection(){}; + + + template + api get_remote_api( api_id_type api_id = 0 ) + { + api result; + result->visit( api_visitor( api_id, this->shared_from_this() ) ); + return result; + } + + /** makes calls to the remote server */ + virtual variant send_call( api_id_type api_id, const string& method_name, const variants& args = variants() )const + { + FC_ASSERT( _remote_connection ); + return _remote_connection->receive_call( api_id, method_name, args ); + } + + variant receive_call( api_id_type api_id, const string& method_name, const variants& args = variants() )const + { + wdump( (api_id)(method_name)(args) ); + FC_ASSERT( _local_apis.size() > api_id ); + return _local_apis[api_id]->call( method_name, args ); + } + + template + api_id_type register_api( const Interface& a ) + { + _local_apis.push_back( std::unique_ptr( new detail::generic_api(a, shared_from_this() ) ) ); + return _local_apis.size() - 1; + } + + void set_remote_connection( const std::shared_ptr& rc ) + { + FC_ASSERT( !_remote_connection ); + FC_ASSERT( rc != this->shared_from_this() ); + _remote_connection = rc; + if( _remote_connection && _remote_connection->remote_connection() != this->shared_from_this() ) + _remote_connection->set_remote_connection( this->shared_from_this() ); + } + const std::shared_ptr& remote_connection()const { return _remote_connection; } + + private: + std::vector< std::unique_ptr > _local_apis; + std::shared_ptr _remote_connection; + + + struct api_visitor + { + uint32_t _api_id; + std::shared_ptr _connection; + + api_visitor( uint32_t api_id, std::shared_ptr con ) + :_api_id(api_id),_connection(std::move(con)) + { + } + + api_visitor() = delete; + + template + static Result from_variant( const variant& v, Result*, const std::shared_ptr& ) + { + return v.as(); + } + + template + static fc::api from_variant( const variant& v, + fc::api* /*used for template deduction*/, + const std::shared_ptr& con + ) + { + return con->get_remote_api( v.as_uint64() ); + } + + + template + void operator()( const char* name, std::function& memb )const + { + auto con = _connection; + auto api_id = _api_id; + memb = [con,api_id,name]( Args... args ) { + auto var_result = con->send_call( api_id, name, {args...} ); + return from_variant( var_result, (Result*)nullptr, con ); + }; + } + }; + }; + + template + detail::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( + const std::function(Args...)>& f )const + { + auto api_con = _api_con; + return [=]( const variants& args ) { + auto api_result = call_generic( f, args.begin(), args.end() ); + return api_con->register_api( api_result ); + }; + } + template + std::function detail::generic_api::api_visitor::to_generic( + const std::function>(Args...)>& f )const + { + auto api_con = _api_con; + return [=]( const variants& args )-> fc::variant { + auto api_result = call_generic( f, args.begin(), args.end() ); + if( api_result ) + return api_con->register_api( *api_result ); + return variant(); + }; + } + + class json_api_connection : public api_connection + { + public: + json_api_connection(){}; + void set_json_connection( const std::shared_ptr& json_con ) + { + json_con->add_method( "call", [this]( const variants& args ) -> variant { + FC_ASSERT( args.size() == 3 && args[2].is_array() ); + return this->receive_call( args[0].as_uint64(), + args[1].as_string(), + args[2].get_array() ); + + }); + } + + json_api_connection( const std::shared_ptr& json_con ) + { + set_json_connection( json_con ); + } + + virtual variant send_call( api_id_type api_id, + const string& method_name, + const variants& args = variants() )const override + { + return _json_con->async_call( "call", {api_id, method_name, args} ).wait(); + } + + private: + std::shared_ptr _json_con; + + }; + +} // fc diff --git a/include/fc/rpc/api_server.hpp b/include/fc/rpc/api_server.hpp deleted file mode 100644 index 24c5861..0000000 --- a/include/fc/rpc/api_server.hpp +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - class api_server; - namespace impl { - using std::vector; - - class generic_api - { - public: - template - generic_api( const Api& a, api_server& s ) - :_api_server(s),_api(a) - { - boost::any_cast(a)->visit( api_visitor( *this, _api_server ) ); - } - 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); - } - - private: - friend struct api_visitor; - - struct api_visitor - { - api_visitor( generic_api& a, api_server& s ):api(a),server(s){ - } - ~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& f, variants::const_iterator a0, variants::const_iterator e )const - { - FC_ASSERT( a0 != e ); - return f(a0->as()); - } - template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e )const - { - FC_ASSERT( a0 != e && (a0+1) != e); - return f(a0->as(), (a0+1)->as()); - } - - template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e )const - { - FC_ASSERT( a0 != e ); - return call_generic( bind_first_arg( f, a0->as() ), a0+1, e ); - } - - 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 - { - return [=]( const variants& args ) { - return call_generic( f, args.begin(), args.end() ); - }; - } - - - 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; - api_server& server; - api_server* server_ptr = nullptr; - }; - - - api_server& _api_server; - fc::any _api; - std::map< std::string, uint32_t > _by_name; - vector< std::function > _methods; - }; - - - - } // namespace impl - - - /** - * @brief exposes Object Oriented API via a flat RPC call interface - * - * The wire API is simply: - * - * variant call( obj_id, method_num|name, [params...] ) - * - * The default obj_id is 0. - */ - class api_server - { - public: - typedef uint32_t api_id_type; - api_server() - { - } - api_server( const api_server& cpy ) = delete; - - template - api_id_type register_api( const Interface& a ) - { - _apis.push_back( std::unique_ptr( new impl::generic_api(a, *this) ) ); - return _apis.size() - 1; - } - - variant call( api_id_type api_id, const string& method_name, const variants& args = variants() )const - { - wdump( (api_id)(method_name)(args) ); - FC_ASSERT( _apis.size() > api_id ); - return _apis[api_id]->call( method_name, args ); - } - - private: - std::vector< std::unique_ptr > _apis; - - }; - - template - std::function impl::generic_api::api_visitor::to_generic( - const std::function(Args...)>& f )const - { - auto tmp = *this; - return [=]( const variants& args ) { - auto api_result = tmp.call_generic( f, args.begin(), args.end() ); - return tmp.server.register_api( api_result ); - }; - } - template - std::function impl::generic_api::api_visitor::to_generic( - const std::function>(Args...)>& f )const - { - auto tmp = *this; - return [=]( const variants& args )-> fc::variant { - auto api_result = tmp.call_generic( f, args.begin(), args.end() ); - if( api_result ) - return tmp.server.register_api( *api_result ); - return variant(); - }; - } - -} // namesapce fc - -FC_API( fc::api_server, (call) ) diff --git a/tests/api.cpp b/tests/api.cpp index afa078b..aedd6aa 100644 --- a/tests/api.cpp +++ b/tests/api.cpp @@ -1,7 +1,6 @@ #include #include -#include -#include +#include class calculator { @@ -76,7 +75,6 @@ int main( int argc, char** argv ) { elog( "${e}", ("e",e.to_detail_string() ) ); } - */ ilog( "------------------ NESTED TEST --------------" ); try { @@ -100,6 +98,31 @@ int main( int argc, char** argv ) fc::api remote_api = apic; + auto remote_calc = remote_api->get_calc(); + int r = remote_calc->add( 4, 5 ); + idump( (r) ); + + } catch ( const fc::exception& e ) + { + elog( "${e}", ("e",e.to_detail_string() ) ); + } + */ + + ilog( "------------------ NESTED TEST --------------" ); + try { + nested_api napi_impl; + napi_impl.calc = api_calc; + fc::api napi(&napi_impl); + + + auto client_side = std::make_shared(); + auto server_side = std::make_shared(); + server_side->set_remote_connection( client_side ); + + server_side->register_api( napi ); + + fc::api remote_api = client_side->get_remote_api(); + auto remote_calc = remote_api->get_calc(); int r = remote_calc->add( 4, 5 ); idump( (r) );