nested API calls fully abstracted
This commit is contained in:
parent
cf849b8b54
commit
fa352e14bd
4 changed files with 376 additions and 76 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/thread/future.hpp>
|
#include <fc/thread/future.hpp>
|
||||||
|
#include <fc/any.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/preprocessor/repeat.hpp>
|
#include <boost/preprocessor/repeat.hpp>
|
||||||
|
|
@ -9,8 +10,6 @@
|
||||||
#include <boost/preprocessor/facilities/empty.hpp>
|
#include <boost/preprocessor/facilities/empty.hpp>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
struct identity_member {
|
struct identity_member {
|
||||||
template<typename R, typename C, typename P, typename... Args>
|
template<typename R, typename C, typename P, typename... Args>
|
||||||
static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...) ) {
|
static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...) ) {
|
||||||
|
|
@ -22,50 +21,80 @@ namespace fc {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename Interface, typename Transform = detail::identity_member >
|
|
||||||
struct vtable{};
|
|
||||||
|
|
||||||
template<typename ThisPtr>
|
template< typename Interface, typename Transform >
|
||||||
struct vtable_visitor {
|
struct vtable : public std::enable_shared_from_this<vtable<Interface,Transform>>
|
||||||
template<typename U>
|
{
|
||||||
vtable_visitor( U&& u ):_this( fc::forward<U>(u) ){}
|
private:
|
||||||
|
vtable();
|
||||||
template<typename Function, typename MemberPtr>
|
|
||||||
void operator()( const char* name, Function& memb, MemberPtr m )const {
|
|
||||||
memb = identity_member::functor( _this, m );
|
|
||||||
}
|
|
||||||
ThisPtr _this;
|
|
||||||
};
|
};
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename Interface, typename Transform = detail::identity_member >
|
|
||||||
|
template<typename OtherType>
|
||||||
|
struct vtable_copy_visitor {
|
||||||
|
typedef OtherType other_type;
|
||||||
|
|
||||||
|
vtable_copy_visitor( OtherType& s):_source( s ){}
|
||||||
|
|
||||||
|
template<typename R, typename MemberPtr, typename... Args>
|
||||||
|
void operator()( const char* name, std::function<R(Args...)>& memb, MemberPtr m )const {
|
||||||
|
OtherType* src = &_source;
|
||||||
|
memb = [src,m]( Args... args ){
|
||||||
|
wdump( (uint64_t(src) ) );
|
||||||
|
return (src->*m)(args...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
OtherType& _source;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Interface, typename Transform = identity_member >
|
||||||
class api {
|
class api {
|
||||||
public:
|
public:
|
||||||
typedef detail::vtable<Interface,Transform> vtable_type;
|
typedef vtable<Interface,Transform> vtable_type;
|
||||||
|
|
||||||
api(){}
|
api()
|
||||||
|
:_vtable( std::make_shared<vtable_type>() )
|
||||||
|
{}
|
||||||
|
|
||||||
template<typename InterfaceType>
|
/** T is anything with pointer semantics */
|
||||||
api( InterfaceType* p )
|
template<typename T >
|
||||||
:_vtable( new vtable_type() ) {
|
api( const T& p )
|
||||||
_vtable->template visit_other<InterfaceType>( detail::vtable_visitor<InterfaceType*>(p) );
|
:_vtable( std::make_shared<vtable_type>() )
|
||||||
|
{
|
||||||
|
_data = std::make_shared<fc::any>(p);
|
||||||
|
T& ptr = boost::any_cast<T&>(*_data);
|
||||||
|
auto& pointed_at = *ptr;
|
||||||
|
typedef typename std::remove_reference<decltype(pointed_at)>::type source_vtable_type;
|
||||||
|
_vtable->template visit_other( vtable_copy_visitor<source_vtable_type>(pointed_at) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename InterfaceType>
|
template<typename T >
|
||||||
api( const fc::shared_ptr<InterfaceType>& p )
|
api( const std::shared_ptr< api<T> >& p )
|
||||||
:_vtable( new vtable_type() ),_self(p){
|
:_vtable( std::make_shared<vtable_type>() )
|
||||||
_vtable->template visit_other<InterfaceType>( detail::vtable_visitor<InterfaceType*>(p.get()) );
|
{
|
||||||
|
_data = std::make_shared<fc::any>(p);
|
||||||
|
auto& ptr = *boost::any_cast< decltype(p) >(*_data);
|
||||||
|
auto& pointed_at = *ptr;
|
||||||
|
typedef typename std::remove_reference<decltype(pointed_at)>::type source_vtable_type;
|
||||||
|
_vtable->template visit_other( vtable_copy_visitor<source_vtable_type>(pointed_at) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//vtable_type& operator*() { return *_vtable; }
|
api( const api& cpy )
|
||||||
vtable_type& operator*()const { return *_vtable; }
|
:_vtable(cpy._vtable),_data(cpy._data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
//vtable_type* operator->() { return _vtable.get(); }
|
vtable_type& operator*()const { wdump((uint64_t(this))); assert(_vtable); FC_ASSERT( _vtable ); return *_vtable; }
|
||||||
vtable_type* operator->()const { return _vtable.get(); }
|
vtable_type* operator->()const {
|
||||||
|
assert(_vtable);
|
||||||
|
FC_ASSERT( _vtable );
|
||||||
|
return _vtable.get();
|
||||||
|
}
|
||||||
|
void test();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
fc::shared_ptr< vtable_type > _vtable;
|
std::shared_ptr<vtable_type> _vtable;
|
||||||
fc::shared_ptr< fc::retainable > _self;
|
std::shared_ptr<fc::any> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -77,17 +106,17 @@ namespace fc {
|
||||||
#define FC_API_VTABLE_DEFINE_MEMBER( r, data, elem ) \
|
#define FC_API_VTABLE_DEFINE_MEMBER( r, data, elem ) \
|
||||||
decltype(Transform::functor( (data*)nullptr, &data::elem)) elem;
|
decltype(Transform::functor( (data*)nullptr, &data::elem)) elem;
|
||||||
#define FC_API_VTABLE_DEFINE_VISIT_OTHER( r, data, elem ) \
|
#define FC_API_VTABLE_DEFINE_VISIT_OTHER( r, data, elem ) \
|
||||||
v( BOOST_PP_STRINGIZE(elem), elem, &T::elem );
|
{ typedef typename Visitor::other_type OtherType; \
|
||||||
|
v( BOOST_PP_STRINGIZE(elem), elem, &OtherType::elem ); }
|
||||||
#define FC_API_VTABLE_DEFINE_VISIT( r, data, elem ) \
|
#define FC_API_VTABLE_DEFINE_VISIT( r, data, elem ) \
|
||||||
v( BOOST_PP_STRINGIZE(elem), elem );
|
v( BOOST_PP_STRINGIZE(elem), elem );
|
||||||
|
|
||||||
#define FC_API( CLASS, METHODS ) \
|
#define FC_API( CLASS, METHODS ) \
|
||||||
namespace fc { namespace detail { \
|
namespace fc { \
|
||||||
template<typename Transform> \
|
template<typename Transform> \
|
||||||
struct vtable<CLASS,Transform> : public fc::retainable { \
|
struct vtable<CLASS,Transform> : public std::enable_shared_from_this<vtable<CLASS,Transform>> { \
|
||||||
vtable(){} \
|
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_MEMBER, CLASS, METHODS ) \
|
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_MEMBER, CLASS, METHODS ) \
|
||||||
template<typename T, typename Visitor> \
|
template<typename Visitor> \
|
||||||
void visit_other( Visitor&& v ){ \
|
void visit_other( Visitor&& v ){ \
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT_OTHER, CLASS, METHODS ) \
|
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT_OTHER, CLASS, METHODS ) \
|
||||||
} \
|
} \
|
||||||
|
|
@ -96,6 +125,6 @@ namespace fc { namespace detail { \
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT, CLASS, METHODS ) \
|
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT, CLASS, METHODS ) \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
} }
|
}
|
||||||
//#undef FC_API_VTABLE_DEFINE_MEMBER
|
//#undef FC_API_VTABLE_DEFINE_MEMBER
|
||||||
//#undef FC_API_VTABLE_DEFINE_VISIT
|
//#undef FC_API_VTABLE_DEFINE_VISIT
|
||||||
|
|
|
||||||
56
include/fc/rpc/api_client.hpp
Normal file
56
include/fc/rpc/api_client.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fc/rpc/api_server.hpp>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
template<typename Interface, typename Adaptor = identity_member>
|
||||||
|
class api_client : public api<Interface,Adaptor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
api_client( fc::api<api_server> server, uint64_t api_id = 0 )
|
||||||
|
{
|
||||||
|
(*this)->visit( api_visitor(this, api_id, std::make_shared<api<api_server>>(server)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct api_visitor
|
||||||
|
{
|
||||||
|
api_client* _client = nullptr;
|
||||||
|
uint32_t _api_id;
|
||||||
|
std::shared_ptr<api<api_server>> _server;
|
||||||
|
|
||||||
|
api_visitor( api_client* c, uint32_t api_id, std::shared_ptr<api<api_server>> serv )
|
||||||
|
:_client(c),_api_id(api_id),_server(std::move(serv))
|
||||||
|
{ wdump((int64_t(c))); }
|
||||||
|
|
||||||
|
api_visitor() = delete;
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
static Result from_variant( const variant& v, Result&&, const std::shared_ptr<api<api_server>>& )
|
||||||
|
{
|
||||||
|
return v.as<Result>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ResultInterface, typename ResultAdaptor>
|
||||||
|
static fc::api<ResultInterface,ResultAdaptor> from_variant( const variant& v, fc::api<ResultInterface,ResultAdaptor>&&,
|
||||||
|
const std::shared_ptr<api<api_server>>& serv
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return api_client<ResultInterface,ResultAdaptor>( serv, v.as_uint64() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Result, typename... Args>
|
||||||
|
void operator()( const char* name, std::function<Result(Args...)>& memb )const
|
||||||
|
{
|
||||||
|
auto serv = _server;
|
||||||
|
auto api_id = _api_id;
|
||||||
|
memb = [serv,api_id,name]( Args... args ) {
|
||||||
|
vtable<api_server,identity_member> test;
|
||||||
|
auto var_result = (*serv)->call( api_id, name, {args...} );
|
||||||
|
return from_variant( var_result, Result(), serv );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
179
include/fc/rpc/api_server.hpp
Normal file
179
include/fc/rpc/api_server.hpp
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fc/variant.hpp>
|
||||||
|
#include <fc/optional.hpp>
|
||||||
|
#include <fc/api.hpp>
|
||||||
|
#include <fc/any.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
class api_server;
|
||||||
|
namespace impl {
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
class generic_api
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename Api>
|
||||||
|
generic_api( const Api& a, api_server& s )
|
||||||
|
:_api_server(s),_api(a)
|
||||||
|
{
|
||||||
|
boost::any_cast<const Api&>(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<typename R, typename Arg0, typename ... Args>
|
||||||
|
std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )const
|
||||||
|
{
|
||||||
|
return [=]( Args... args ) { return f( a0, args... ); };
|
||||||
|
}
|
||||||
|
template<typename R>
|
||||||
|
R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e )const
|
||||||
|
{
|
||||||
|
return f();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename Arg0>
|
||||||
|
R call_generic( const std::function<R(Arg0)>& f, variants::const_iterator a0, variants::const_iterator e )const
|
||||||
|
{
|
||||||
|
FC_ASSERT( a0 != e );
|
||||||
|
return f(a0->as<Arg0>());
|
||||||
|
}
|
||||||
|
template<typename R, typename Arg0, typename Arg1>
|
||||||
|
R call_generic( const std::function<R(Arg0,Arg1)>& f, variants::const_iterator a0, variants::const_iterator e )const
|
||||||
|
{
|
||||||
|
FC_ASSERT( a0 != e && (a0+1) != e);
|
||||||
|
return f(a0->as<Arg0>(), (a0+1)->as<Arg1>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename Arg0, typename ... Args>
|
||||||
|
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )const
|
||||||
|
{
|
||||||
|
FC_ASSERT( a0 != e );
|
||||||
|
return call_generic<R,Args...>( bind_first_arg( f, a0->as<Arg0>() ), a0+1, e );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Interface, typename Adaptor, typename ... Args>
|
||||||
|
std::function<variant(const fc::variants&)> to_generic( const std::function<api<Interface,Adaptor>(Args...)>& f )const;
|
||||||
|
template<typename Interface, typename Adaptor, typename ... Args>
|
||||||
|
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::optional<api<Interface,Adaptor>>(Args...)>& f )const;
|
||||||
|
|
||||||
|
template<typename R, typename ... Args>
|
||||||
|
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )const
|
||||||
|
{
|
||||||
|
return [=]( const variants& args ) {
|
||||||
|
return call_generic( f, args.begin(), args.end() );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Result, typename... Args>
|
||||||
|
void operator()( const char* name, std::function<Result(Args...)>& 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<variant(const variants&)> > _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<typename Interface>
|
||||||
|
api_id_type register_api( const Interface& a )
|
||||||
|
{
|
||||||
|
_apis.push_back( std::unique_ptr<impl::generic_api>( 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<impl::generic_api> > _apis;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Interface, typename Adaptor, typename ... Args>
|
||||||
|
std::function<variant(const fc::variants&)> impl::generic_api::api_visitor::to_generic(
|
||||||
|
const std::function<fc::api<Interface,Adaptor>(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<typename Interface, typename Adaptor, typename ... Args>
|
||||||
|
std::function<variant(const fc::variants&)> impl::generic_api::api_visitor::to_generic(
|
||||||
|
const std::function<fc::optional<fc::api<Interface,Adaptor>>(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) )
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <fc/api.hpp>
|
#include <fc/api.hpp>
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
//#include <fc/rpc/api_server.hpp>
|
#include <fc/rpc/api_server.hpp>
|
||||||
|
#include <fc/rpc/api_client.hpp>
|
||||||
|
|
||||||
class calculator
|
class calculator
|
||||||
{
|
{
|
||||||
|
|
@ -11,6 +12,19 @@ class calculator
|
||||||
|
|
||||||
FC_API( calculator, (add)(sub) )
|
FC_API( calculator, (add)(sub) )
|
||||||
|
|
||||||
|
|
||||||
|
class nested_api
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
fc::api<calculator> get_calc()const
|
||||||
|
{
|
||||||
|
FC_ASSERT( calc );
|
||||||
|
return *calc;
|
||||||
|
}
|
||||||
|
fc::optional<fc::api<calculator>> calc;
|
||||||
|
};
|
||||||
|
FC_API( nested_api, (get_calc) );
|
||||||
|
|
||||||
using namespace fc;
|
using namespace fc;
|
||||||
|
|
||||||
class some_calculator
|
class some_calculator
|
||||||
|
|
@ -26,37 +40,16 @@ class variant_calculator
|
||||||
double sub( fc::variant a, fc::variant b ) { return a.as_double()-b.as_double(); }
|
double sub( fc::variant a, fc::variant b ) { return a.as_double()-b.as_double(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename Arg0, typename ... Args>
|
|
||||||
//std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 ao )
|
|
||||||
std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 ao )
|
|
||||||
{
|
|
||||||
return [=]( Args... args ) { return f( ao, args... ); };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename Arg0>
|
|
||||||
R call_generic( const std::function<R(Arg0)>& f, variants::const_iterator a0, variants::const_iterator e )
|
|
||||||
{
|
|
||||||
return f(a0->as<Arg0>());
|
|
||||||
}
|
|
||||||
template<typename R, typename Arg0, typename ... Args>
|
|
||||||
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
|
|
||||||
{
|
|
||||||
return call_generic<R,Args...>( bind_first_arg( f, a0->as<Arg0>() ), a0+1, e );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ... Args>
|
|
||||||
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )
|
|
||||||
{
|
|
||||||
return [=]( const variants& args ) { return call_generic( f, args.begin(), args.end() ); };
|
|
||||||
}
|
|
||||||
|
|
||||||
int main( int argc, char** argv )
|
int main( int argc, char** argv )
|
||||||
{
|
{
|
||||||
some_calculator calc;
|
some_calculator calc;
|
||||||
variant_calculator vcalc;
|
variant_calculator vcalc;
|
||||||
|
|
||||||
fc::api<calculator> api_calc( &calc );
|
fc::api<calculator> api_calc( &calc );
|
||||||
fc::api<calculator> api_vcalc( &vcalc );
|
fc::api<calculator> api_vcalc( &vcalc );
|
||||||
fc::api<calculator> api_nested_calc( api_calc );
|
fc::api<calculator> api_nested_calc( api_calc );
|
||||||
|
|
||||||
wdump( (api_calc->add(5,4)) );
|
wdump( (api_calc->add(5,4)) );
|
||||||
wdump( (api_calc->sub(5,4)) );
|
wdump( (api_calc->sub(5,4)) );
|
||||||
wdump( (api_vcalc->add(5,4)) );
|
wdump( (api_vcalc->add(5,4)) );
|
||||||
|
|
@ -64,14 +57,57 @@ int main( int argc, char** argv )
|
||||||
wdump( (api_nested_calc->sub(5,4)) );
|
wdump( (api_nested_calc->sub(5,4)) );
|
||||||
wdump( (api_nested_calc->sub(5,4)) );
|
wdump( (api_nested_calc->sub(5,4)) );
|
||||||
|
|
||||||
|
/*
|
||||||
variants v = { 4, 5 };
|
variants v = { 4, 5 };
|
||||||
auto g = to_generic( api_calc->add );
|
auto g = to_generic( api_calc->add );
|
||||||
auto r = call_generic( api_calc->add, v.begin(), v.end() );
|
auto r = call_generic( api_calc->add, v.begin(), v.end() );
|
||||||
wdump((r));
|
wdump((r));
|
||||||
wdump( (g(v)) );
|
wdump( (g(v)) );
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
try {
|
||||||
|
fc::api_server server;
|
||||||
|
auto api_id = server.register_api( api_calc );
|
||||||
|
wdump( (api_id) );
|
||||||
|
auto result = server.call( api_id, "add", {4, 5} );
|
||||||
|
wdump( (result) );
|
||||||
|
} 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<nested_api> napi(&napi_impl);
|
||||||
|
|
||||||
|
fc::api_server server;
|
||||||
|
auto api_id = server.register_api( napi );
|
||||||
|
wdump( (api_id) );
|
||||||
|
auto result = server.call( api_id, "get_calc" );
|
||||||
|
wdump( (result) );
|
||||||
|
result = server.call( result.as_uint64(), "add", {4,5} );
|
||||||
|
wdump( (result) );
|
||||||
|
|
||||||
|
|
||||||
// fc::api_server server;
|
fc::api<api_server> serv( &server );
|
||||||
// server.register_api( api_calc );
|
|
||||||
|
fc::api_client<nested_api> apic( serv );
|
||||||
|
|
||||||
|
fc::api<nested_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() ) );
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue