BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
api_connection.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <fc/variant.hpp>
3 #include <fc/optional.hpp>
4 #include <fc/api.hpp>
5 #include <boost/any.hpp>
6 #include <memory>
7 #include <vector>
8 #include <functional>
9 #include <utility>
10 #include <fc/signals.hpp>
11 
12 namespace fc {
13  class api_connection;
14 
15  namespace detail {
16  template<typename Signature>
18  {
19  public:
21 
22  callback_functor( std::weak_ptr< fc::api_connection > con, uint64_t id )
23  :_callback_id(id),_api_connection(con){}
24 
25  template<typename... Args>
26  result_type operator()( Args... args )const;
27 
28  private:
29  uint64_t _callback_id;
30  std::weak_ptr< fc::api_connection > _api_connection;
31  };
32 
33  template<typename R, typename Arg0, typename ... Args>
34  std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )
35  {
36  // Capture a0 this way because of a {compiler,fc,???} bug that causes optional<bool>() to be incorrectly
37  // captured as optional<bool>(false).
38  return [f, a0 = std::decay_t<Arg0>(a0)]( Args... args ) { return f( a0, args... ); };
39  }
40  template<typename R>
41  R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth = 1 )
42  {
43  return f();
44  }
45 
46  template<typename R, typename Arg0, typename ... Args>
47  R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0,
48  variants::const_iterator e, uint32_t max_depth )
49  {
50  bool optional_args = all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
51  FC_ASSERT( a0 != e || optional_args );
52  FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
53  if (a0==e)
54  return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, std::decay_t<Arg0>() ), a0,
55  e, max_depth - 1 );
56  auto arg = a0->as<std::decay_t<Arg0>>(max_depth - 1);
57  return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, std::move(arg) ), a0+1, e,
58  max_depth - 1 );
59  }
60 
61  template<typename R, typename ... Args>
62  std::function<variant(const fc::variants&, uint32_t)> to_generic( const std::function<R(Args...)>& f )
63  {
64  return [=]( const variants& args, uint32_t max_depth ) {
65  FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
66  return variant( call_generic( f, args.begin(), args.end(), max_depth - 1 ), max_depth - 1 );
67  };
68  }
69 
70  template<typename ... Args>
71  std::function<variant(const fc::variants&, uint32_t)> to_generic( const std::function<void(Args...)>& f )
72  {
73  return [=]( const variants& args, uint32_t max_depth ) {
74  FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
75  call_generic( f, args.begin(), args.end(), max_depth - 1 );
76  return variant();
77  };
78  }
79 
91  class any_api : public api_base
92  {
93  public:
94  any_api( api_id_type api_id, const std::shared_ptr<fc::api_connection>& con )
95  : _api_id(api_id), _api_connection(con) {}
96 
97  virtual uint64_t get_handle()const override
98  { return _api_id; }
99 
100  virtual api_id_type register_api( api_connection& conn )const override
101  { FC_ASSERT( false ); return api_id_type(); }
102 
104  std::weak_ptr<fc::api_connection> _api_connection;
105  };
106 
107  } // namespace detail
108 
110  {
111  public:
112  template<typename Api>
113  generic_api( const Api& a, const std::shared_ptr<fc::api_connection>& c );
114 
115  generic_api( const generic_api& cpy ) = delete;
116 
117  variant call( const string& name, const variants& args )
118  {
119  auto itr = _by_name.find(name);
120  if( itr == _by_name.end() )
121  FC_THROW_EXCEPTION( method_not_found_exception, "No method with name '${name}'",
122  ("name",name)("api",_by_name) );
123  return call( itr->second, args );
124  }
125 
126  variant call( uint32_t method_id, const variants& args )
127  {
128  if( method_id >= _methods.size() )
129  FC_THROW_EXCEPTION( method_not_found_exception, "No method with id '${id}'",
130  ("id",method_id)("api",_by_name) );
131  return _methods[method_id](args);
132  }
133 
134  std::weak_ptr< fc::api_connection > get_connection()
135  {
136  return _api_connection;
137  }
138 
139  std::vector<std::string> get_method_names()const
140  {
141  std::vector<std::string> result;
142  result.reserve( _by_name.size() );
143  for( auto& m : _by_name ) result.push_back(m.first);
144  return result;
145  }
146 
147  private:
148  friend struct api_visitor;
149 
150  template<typename R, typename Arg0, typename ... Args>
151  std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )const
152  {
153  // Capture a0 this way because of a {compiler,fc,???} bug that causes optional<bool>() to be incorrectly
154  // captured as optional<bool>(false).
155  return [f, a0 = std::decay_t<Arg0>(a0)]( Args... args ) { return f( a0, args... ); };
156  }
157 
158  template<typename R>
159  R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth = 1 )const
160  {
161  return f();
162  }
163 
164  template<typename R, typename Signature, typename ... Args,
165  typename std::enable_if<std::is_function<Signature>::value,Signature>::type* = nullptr>
166  R call_generic( const std::function<R(std::function<Signature>,Args...)>& f,
167  variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
168  {
169  FC_ASSERT( a0 != e, "too few arguments passed to method" );
170  FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
171  detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>(1) );
172  return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f,
173  std::function<Signature>(arg0) ), a0+1, e, max_depth - 1 );
174  }
175  template<typename R, typename Signature, typename ... Args,
176  typename std::enable_if<std::is_function<Signature>::value,Signature>::type* = nullptr>
177  R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f,
178  variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
179  {
180  FC_ASSERT( a0 != e, "too few arguments passed to method" );
181  FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
182  detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>(1) );
183  return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f,
184  arg0 ), a0+1, e, max_depth - 1 );
185  }
186 
187  template<typename R, typename Arg0, typename ... Args>
188  R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0,
189  variants::const_iterator e, uint32_t max_depth )
190  {
191  bool optional_args = detail::all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
192  FC_ASSERT( a0 != e || optional_args, "too few arguments passed to method" );
193  FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
194  if (a0==e)
195  return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, std::decay_t<Arg0>() ), a0,
196  e, max_depth - 1 );
197  auto arg = a0->as<std::decay_t<Arg0>>(max_depth - 1);
198  return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, std::move(arg) ), a0+1, e,
199  max_depth - 1 );
200  }
201 
202  struct api_visitor
203  {
204  api_visitor( generic_api& a, const std::weak_ptr<fc::api_connection>& s ):_api(a),_api_con(s){ }
205 
206  template<typename Interface, typename Adaptor, typename ... Args>
207  std::function<variant(const fc::variants&)> to_generic( const std::function<api<Interface,Adaptor>(Args...)>& f )const;
208 
209  template<typename Interface, typename Adaptor, typename ... Args>
210  std::function<variant(const fc::variants&)> to_generic( const std::function<fc::optional<api<Interface,Adaptor>>(Args...)>& f )const;
211 
212  template<typename ... Args>
213  std::function<variant(const fc::variants&)> to_generic( const std::function<fc::api_ptr(Args...)>& f )const;
214 
215  template<typename R, typename ... Args>
216  std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )const;
217 
218  template<typename ... Args>
219  std::function<variant(const fc::variants&)> to_generic( const std::function<void(Args...)>& f )const;
220 
221  template<typename Result, typename... Args>
222  void operator()( const char* name, std::function<Result(Args...)>& memb )const {
223  _api._methods.emplace_back( to_generic( memb ) );
224  _api._by_name[name] = _api._methods.size() - 1;
225  }
226 
227  generic_api& _api;
228  const std::weak_ptr<fc::api_connection>& _api_con;
229  };
230 
231 
232  std::weak_ptr<fc::api_connection> _api_connection;
233  boost::any _api;
234  std::map< std::string, uint32_t > _by_name;
235  std::vector< std::function<variant(const variants&)> > _methods;
236  }; // class generic_api
237 
238 
239 
240  class api_connection : public std::enable_shared_from_this<fc::api_connection>
241  {
242  public:
243  api_connection(uint32_t max_depth):_max_conversion_depth(max_depth){}
244  virtual ~api_connection(){};
245 
246 
247  template<typename T>
249  {
250  api<T> result;
251  result->visit( api_visitor( api_id, this->shared_from_this() ) );
252  return result;
253  }
254 
256  virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ) = 0;
257  virtual variant send_callback( uint64_t callback_id, variants args = variants() ) = 0;
258  virtual void send_notice( uint64_t callback_id, variants args = variants() ) = 0;
259 
260  variant receive_call( api_id_type api_id, const string& method_name, const variants& args = variants() )const
261  {
262  FC_ASSERT( _local_apis.size() > api_id );
263  return _local_apis[api_id]->call( method_name, args );
264  }
265  variant receive_callback( uint64_t callback_id, const variants& args = variants() )const
266  {
267  FC_ASSERT( _local_callbacks.size() > callback_id );
268  return _local_callbacks[callback_id]( args, _max_conversion_depth );
269  }
270  void receive_notice( uint64_t callback_id, const variants& args = variants() )const
271  {
272  FC_ASSERT( _local_callbacks.size() > callback_id );
273  _local_callbacks[callback_id]( args, _max_conversion_depth );
274  }
275 
276  template<typename Interface>
277  api_id_type register_api( const Interface& a )
278  {
279  auto handle = a.get_handle();
280  auto itr = _handle_to_id.find(handle);
281  if( itr != _handle_to_id.end() ) return itr->second;
282 
283  _local_apis.push_back( std::unique_ptr<generic_api>( new generic_api(a, shared_from_this() ) ) );
284  _handle_to_id[handle] = _local_apis.size() - 1;
285  return _local_apis.size() - 1;
286  }
287 
288  template<typename Signature>
289  uint64_t register_callback( const std::function<Signature>& cb )
290  {
291  _local_callbacks.push_back( detail::to_generic( cb ) );
292  return _local_callbacks.size() - 1;
293  }
294 
295  std::vector<std::string> get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); }
296 
298  const uint32_t _max_conversion_depth; // for nested structures, json, variant etc.
299  private:
300  std::vector< std::unique_ptr<generic_api> > _local_apis;
301  std::map< uint64_t, api_id_type > _handle_to_id;
302  std::vector< std::function<variant(const variants&, uint32_t)> > _local_callbacks;
303 
304 
305  struct api_visitor
306  {
307  uint32_t _api_id;
308  std::shared_ptr<fc::api_connection> _connection;
309 
310  api_visitor( uint32_t api_id, std::shared_ptr<fc::api_connection> con )
311  :_api_id(api_id),_connection(std::move(con))
312  {
313  }
314 
315  api_visitor() = delete;
316 
317  template<typename Result>
318  static Result from_variant( const variant& v, Result*, const std::shared_ptr<fc::api_connection>&, uint32_t max_depth )
319  {
320  return v.as<Result>( max_depth );
321  }
322 
323  template<typename ResultInterface>
325  fc::api<ResultInterface>* /*used for template deduction*/,
326  const std::shared_ptr<fc::api_connection>& con,
327  uint32_t max_depth = 1
328  )
329  {
330  return con->get_remote_api<ResultInterface>( v.as_uint64() );
331  }
332 
333  static fc::api_ptr from_variant(
334  const variant& v,
335  fc::api_ptr* /* used for template deduction */,
336  const std::shared_ptr<fc::api_connection>& con,
337  uint32_t max_depth = 1
338  )
339  {
340  if( v.is_null() )
341  return fc::api_ptr();
342  return fc::api_ptr( new detail::any_api( v.as_uint64(), con ) );
343  }
344 
345  template<typename T>
346  static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>& con, const T& v )
347  {
348  return fc::variant( v, con->_max_conversion_depth );
349  }
350 
351  template<typename Signature>
352  static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>& con, const std::function<Signature>& v )
353  {
354  return con->register_callback( v );
355  }
356 
357  template<typename Result, typename... Args>
358  void operator()( const char* name, std::function<Result(Args...)>& memb )const
359  {
360  auto con = _connection;
361  auto api_id = _api_id;
362  memb = [con,api_id,name]( Args... args ) {
363  auto var_result = con->send_call( api_id, name, { convert_callbacks(con,args)...} );
364  return from_variant( var_result, (Result*)nullptr, con, con->_max_conversion_depth );
365  };
366  }
367  template<typename... Args>
368  void operator()( const char* name, std::function<void(Args...)>& memb )const
369  {
370  auto con = _connection;
371  auto api_id = _api_id;
372  memb = [con,api_id,name]( Args... args ) {
373  con->send_call( api_id, name, { convert_callbacks(con,args)...} );
374  };
375  }
376  };
377  };
378 
380  {
381  public:
382  local_api_connection( uint32_t max_depth ) : api_connection(max_depth){}
384 
386  virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ) override
387  {
388  FC_ASSERT( _remote_connection );
389  return _remote_connection->receive_call( api_id, method_name, std::move(args) );
390  }
391  virtual variant send_callback( uint64_t callback_id, variants args = variants() ) override
392  {
393  FC_ASSERT( _remote_connection );
394  return _remote_connection->receive_callback( callback_id, args );
395  }
396  virtual void send_notice( uint64_t callback_id, variants args = variants() ) override
397  {
398  FC_ASSERT( _remote_connection );
399  _remote_connection->receive_notice( callback_id, args );
400  }
401 
402 
403  void set_remote_connection( const std::shared_ptr<fc::api_connection>& rc )
404  {
405  FC_ASSERT( !_remote_connection );
406  FC_ASSERT( rc != this->shared_from_this() );
407  _remote_connection = rc;
408  }
409  const std::shared_ptr<fc::api_connection>& remote_connection()const { return _remote_connection; }
410 
411  std::shared_ptr<fc::api_connection> _remote_connection;
412  };
413 
414  template<typename Api>
415  generic_api::generic_api( const Api& a, const std::shared_ptr<fc::api_connection>& c )
416  :_api_connection(c),_api(a)
417  {
418  boost::any_cast<const Api&>(a)->visit( api_visitor( *this, c ) );
419  }
420 
421  template<typename Interface, typename Adaptor, typename ... Args>
422  std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
423  const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const
424  {
425  auto api_con = _api_con;
426  auto gapi = &_api;
427  return [=]( const variants& args ) {
428  auto con = api_con.lock();
429  FC_ASSERT( con, "not connected" );
430 
431  auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth );
432  return con->register_api( api_result );
433  };
434  }
435  template<typename Interface, typename Adaptor, typename ... Args>
436  std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
437  const std::function<fc::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const
438  {
439  auto api_con = _api_con;
440  auto gapi = &_api;
441  return [=]( const variants& args )-> fc::variant {
442  auto con = api_con.lock();
443  FC_ASSERT( con, "not connected" );
444 
445  auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth );
446  if( api_result )
447  return con->register_api( *api_result );
448  return variant();
449  };
450  }
451 
452  template<typename ... Args>
453  std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
454  const std::function<fc::api_ptr(Args...)>& f )const
455  {
456  auto api_con = _api_con;
457  auto gapi = &_api;
458  return [=]( const variants& args ) -> fc::variant {
459  auto con = api_con.lock();
460  FC_ASSERT( con, "not connected" );
461 
462  auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth );
463  if( !api_result )
464  return variant();
465  return api_result->register_api( *con );
466  };
467  }
468 
469  template<typename R, typename ... Args>
470  std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
471  {
472  auto con = _api_con.lock();
473  FC_ASSERT( con, "not connected" );
474  uint32_t max_depth = con->_max_conversion_depth;
475  generic_api* gapi = &_api;
476  return [f,gapi,max_depth]( const variants& args ) {
477  return variant( gapi->call_generic( f, args.begin(), args.end(), max_depth ), max_depth );
478  };
479  }
480 
481  template<typename ... Args>
482  std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
483  {
484  auto con = _api_con.lock();
485  FC_ASSERT( con, "not connected" );
486  uint32_t max_depth = con->_max_conversion_depth;
487  generic_api* gapi = &_api;
488  return [f,gapi,max_depth]( const variants& args ) {
489  gapi->call_generic( f, args.begin(), args.end(), max_depth );
490  return variant();
491  };
492  }
493 
507  template< typename Interface, typename Transform >
509  {
510  return conn.register_api( *this );
511  }
512 
513  template< typename T >
515  {
516  // TODO: this method should probably be const (if it is not too hard)
517  api<T>* maybe_requested_type = dynamic_cast< api<T>* >(this);
518  if( maybe_requested_type != nullptr )
519  return *maybe_requested_type;
520 
521  detail::any_api* maybe_any = dynamic_cast< detail::any_api* >(this);
522  FC_ASSERT( maybe_any != nullptr );
523  std::shared_ptr< api_connection > api_conn = maybe_any->_api_connection.lock();
524  FC_ASSERT( api_conn );
525  return api_conn->get_remote_api<T>( maybe_any->_api_id );
526  }
527 
528  namespace detail {
529  template<typename Signature>
530  template<typename... Args>
532  {
533  std::shared_ptr< fc::api_connection > locked = _api_connection.lock();
534  // TODO: make new exception type for this instead of recycling eof_exception
535  if( !locked )
536  throw fc::eof_exception();
537  locked->send_callback( _callback_id, fc::variants{ args... } ).template as< result_type >();
538  }
539 
540 
541  template<typename... Args>
542  class callback_functor<void(Args...)>
543  {
544  public:
545  typedef void result_type;
546 
547  callback_functor( std::weak_ptr< fc::api_connection > con, uint64_t id )
548  :_callback_id(id),_api_connection(con){}
549 
550  void operator()( Args... args )const
551  {
552  std::shared_ptr< fc::api_connection > locked = _api_connection.lock();
553  // TODO: make new exception type for this instead of recycling eof_exception
554  if( !locked )
555  throw fc::eof_exception();
556  locked->send_notice( _callback_id, fc::variants{ args... } );
557  }
558 
559  private:
560  uint64_t _callback_id;
561  std::weak_ptr< fc::api_connection > _api_connection;
562  };
563  } // namespace detail
564 
565 } // fc
const std::shared_ptr< fc::api_connection > & remote_connection() const
std::function< R(Args...)> bind_first_arg(const std::function< R(Arg0, Args...)> &f, Arg0 a0)
std::weak_ptr< fc::api_connection > get_connection()
T as(uint32_t max_depth) const
Definition: variant.hpp:336
void receive_notice(uint64_t callback_id, const variants &args=variants()) const
std::function< Signature >::result_type result_type
std::function< variant(const fc::variants &, uint32_t)> to_generic(const std::function< R(Args...)> &f)
variant receive_call(api_id_type api_id, const string &method_name, const variants &args=variants()) const
generic_api(const Api &a, const std::shared_ptr< fc::api_connection > &c)
virtual variant send_callback(uint64_t callback_id, variants args=variants()) override
local_api_connection(uint32_t max_depth)
bool is_null() const
Definition: variant.cpp:309
virtual api_id_type register_api(api_connection &conn) const override
virtual variant send_call(api_id_type api_id, string method_name, variants args=variants()) override
std::vector< variant > variants
Definition: variant.hpp:170
callback_functor(std::weak_ptr< fc::api_connection > con, uint64_t id)
uint64_t as_uint64() const
Definition: variant.cpp:398
api_connection(uint32_t max_depth)
std::shared_ptr< api_base > api_ptr
Definition: api.hpp:140
const uint32_t _max_conversion_depth
any_api(api_id_type api_id, const std::shared_ptr< fc::api_connection > &con)
api< T, identity_member_with_optionals > as()
variant call(uint32_t method_id, const variants &args)
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
virtual api_id_type register_api(api_connection &conn) const override
variant call(const string &name, const variants &args)
virtual void send_notice(uint64_t callback_id, variants args=variants()) override
std::vector< std::string > get_method_names() const
std::weak_ptr< fc::api_connection > _api_connection
std::function< variant(const fc::variants &, uint32_t)> to_generic(const std::function< void(Args...)> &f)
virtual uint64_t get_handle() const override
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
void set_remote_connection(const std::shared_ptr< fc::api_connection > &rc)
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:378
fc::signal< void()> closed
api_id_type register_api(const Interface &a)
R call_generic(const std::function< R()> &f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth=1)
friend struct api_visitor
object_restriction_predicate< operation > result_type
Definition: list_1.cpp:29
callback_functor(std::weak_ptr< fc::api_connection > con, uint64_t id)
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
uint32_t api_id_type
Definition: api.hpp:122
uint64_t register_callback(const std::function< Signature > &cb)
variant receive_callback(uint64_t callback_id, const variants &args=variants()) const
Definition: api.hpp:15
std::shared_ptr< fc::api_connection > _remote_connection
boost::signals2::signal< T > signal
Definition: signals.hpp:20
api< T > get_remote_api(api_id_type api_id=0)
This metafunction determines whether all of its template arguments are instantiations of fc::optional...
Definition: api.hpp:21
std::vector< std::string > get_method_names(api_id_type local_api_id=0) const
Definition: api.hpp:120
result_type operator()(Args...args) const