Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
api_connection.hpp
Go to the documentation of this file.
1#pragma once
2#include <fc/variant.hpp>
3#include <fc/api.hpp>
4#include <fc/any.hpp>
5#include <memory>
6#include <vector>
7#include <functional>
8#include <utility>
9#include <fc/signals.hpp>
10
11namespace fc {
12 class api_connection;
13
14 namespace detail {
15 template<typename Signature>
16 class callback_functor
17 {
18 public:
19 typedef typename std::function<Signature>::result_type result_type;
20
21 callback_functor( std::weak_ptr< fc::api_connection > con, uint64_t id )
22 :_callback_id(id),_api_connection(con){}
23
24 template<typename... Args>
25 result_type operator()( Args... args )const;
26
27 private:
28 uint64_t _callback_id;
29 std::weak_ptr< fc::api_connection > _api_connection;
30 };
31
32 template<typename R, typename Arg0, typename ... Args>
33 std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )
34 {
35 return [=]( Args... args ) { return f( a0, args... ); };
36 }
37 template<typename R>
38 R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e )
39 {
40 return f();
41 }
42
43 template<typename R, typename Arg0, typename ... Args>
44 R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
45 {
46 FC_ASSERT( a0 != e );
47 return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >() ), a0+1, e );
48 }
49
50 template<typename R, typename ... Args>
51 std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )
52 {
53 return [=]( const variants& args ) {
54 return variant( call_generic( f, args.begin(), args.end() ) );
55 };
56 }
57
58 template<typename ... Args>
59 std::function<variant(const fc::variants&)> to_generic( const std::function<void(Args...)>& f )
60 {
61 return [=]( const variants& args ) {
62 call_generic( f, args.begin(), args.end() );
63 return variant();
64 };
65 }
66
78 class any_api : public api_base
79 {
80 public:
81 any_api( api_id_type api_id, const std::shared_ptr<fc::api_connection>& con )
82 : _api_id(api_id), _api_connection(con) {}
83
84 virtual uint64_t get_handle()const override
85 { return _api_id; }
86
87 virtual api_id_type register_api( api_connection& conn )const override
88 { FC_ASSERT( false ); return api_id_type(); }
89
91 std::weak_ptr<fc::api_connection> _api_connection;
92 };
93
94 } // namespace detail
95
96 class generic_api
97 {
98 public:
99 template<typename Api>
100 generic_api( const Api& a, const std::shared_ptr<fc::api_connection>& c );
101
102 generic_api( const generic_api& cpy ) = delete;
103
104 variant call( const string& name, const variants& args )
105 {
106 auto itr = _by_name.find(name);
107 FC_ASSERT( itr != _by_name.end(), "no method with name '${name}'", ("name",name)("api",_by_name) );
108 return call( itr->second, args );
109 }
110
111 variant call( uint32_t method_id, const variants& args )
112 {
113 FC_ASSERT( method_id < _methods.size() );
114 return _methods[method_id](args);
115 }
116
117 std::weak_ptr< fc::api_connection > get_connection()
118 {
119 return _api_connection;
120 }
121
122 std::vector<std::string> get_method_names()const
123 {
124 std::vector<std::string> result;
125 result.reserve( _by_name.size() );
126 for( auto& m : _by_name ) result.push_back(m.first);
127 return result;
128 }
129
130 private:
131 friend struct api_visitor;
132
133 template<typename R, typename Arg0, typename ... Args>
134 std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )const
135 {
136 return [=]( Args... args ) { return f( a0, args... ); };
137 }
138
139 template<typename R>
140 R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e )const
141 {
142 return f();
143 }
144
145 template<typename R, typename Signature, typename ... Args>
146 R call_generic( const std::function<R(std::function<Signature>,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
147 {
148 FC_ASSERT( a0 != e, "too few arguments passed to method" );
149 detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>() );
150 return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f, std::function<Signature>(arg0) ), a0+1, e );
151 }
152 template<typename R, typename Signature, typename ... Args>
153 R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
154 {
155 FC_ASSERT( a0 != e, "too few arguments passed to method" );
156 detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>() );
157 return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f, arg0 ), a0+1, e );
158 }
159
160 template<typename R, typename Arg0, typename ... Args>
161 R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
162 {
163 FC_ASSERT( a0 != e, "too few arguments passed to method" );
164 return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >() ), a0+1, e );
165 }
166
167 struct api_visitor
168 {
169 api_visitor( generic_api& a, const std::weak_ptr<fc::api_connection>& s ):_api(a),_api_con(s){ }
170
171 template<typename Interface, typename Adaptor, typename ... Args>
172 std::function<variant(const fc::variants&)> to_generic( const std::function<api<Interface,Adaptor>(Args...)>& f )const;
173
174 template<typename Interface, typename Adaptor, typename ... Args>
175 std::function<variant(const fc::variants&)> to_generic( const std::function<std::optional<api<Interface,Adaptor>>(Args...)>& f )const;
176
177 template<typename ... Args>
178 std::function<variant(const fc::variants&)> to_generic( const std::function<fc::api_ptr(Args...)>& f )const;
179
180 template<typename R, typename ... Args>
181 std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )const;
182
183 template<typename ... Args>
184 std::function<variant(const fc::variants&)> to_generic( const std::function<void(Args...)>& f )const;
185
186 template<typename Result, typename... Args>
187 void operator()( const char* name, std::function<Result(Args...)>& memb )const {
188 _api._methods.emplace_back( to_generic( memb ) );
189 _api._by_name[name] = _api._methods.size() - 1;
190 }
191
192 generic_api& _api;
193 const std::weak_ptr<fc::api_connection>& _api_con;
194 };
195
196
197 std::weak_ptr<fc::api_connection> _api_connection;
198 fc::any _api;
199 std::map< std::string, uint32_t > _by_name;
200 std::vector< std::function<variant(const variants&)> > _methods;
201 }; // class generic_api
202
203
204
205 class api_connection : public std::enable_shared_from_this<fc::api_connection>
206 {
207 public:
209 virtual ~api_connection(){};
210
211
212 template<typename T>
214 {
215 api<T> result;
216 result->visit( api_visitor( api_id, this->shared_from_this() ) );
217 return result;
218 }
219
221 virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ) = 0;
222 virtual variant send_callback( uint64_t callback_id, variants args = variants() ) = 0;
223 virtual void send_notice( uint64_t callback_id, variants args = variants() ) = 0;
224
225 variant receive_call( api_id_type api_id, const string& method_name, const variants& args = variants() )const
226 {
227 FC_ASSERT( _local_apis.size() > api_id );
228 return _local_apis[api_id]->call( method_name, args );
229 }
230 variant receive_callback( uint64_t callback_id, const variants& args = variants() )const
231 {
232 FC_ASSERT( _local_callbacks.size() > callback_id );
233 return _local_callbacks[callback_id]( args );
234 }
235 void receive_notice( uint64_t callback_id, const variants& args = variants() )const
236 {
237 FC_ASSERT( _local_callbacks.size() > callback_id );
238 _local_callbacks[callback_id]( args );
239 }
240
241 template<typename Interface>
243 {
244 auto handle = a.get_handle();
245 auto itr = _handle_to_id.find(handle);
246 if( itr != _handle_to_id.end() ) return itr->second;
247
248 _local_apis.push_back( std::unique_ptr<generic_api>( new generic_api(a, shared_from_this() ) ) );
249 _handle_to_id[handle] = _local_apis.size() - 1;
250 return _local_apis.size() - 1;
251 }
252
253 template<typename Signature>
254 uint64_t register_callback( const std::function<Signature>& cb )
255 {
256 _local_callbacks.push_back( detail::to_generic( cb ) );
257 return _local_callbacks.size() - 1;
258 }
259
260 std::vector<std::string> get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); }
261
262 fc::signal<void()> closed;
263 private:
264 std::vector< std::unique_ptr<generic_api> > _local_apis;
265 std::map< uint64_t, api_id_type > _handle_to_id;
266 std::vector< std::function<variant(const variants&)> > _local_callbacks;
267
268
269 struct api_visitor
270 {
271 uint32_t _api_id;
272 std::shared_ptr<fc::api_connection> _connection;
273
274 api_visitor( uint32_t api_id, std::shared_ptr<fc::api_connection> con )
275 :_api_id(api_id),_connection(std::move(con))
276 {
277 }
278
279 api_visitor() = delete;
280
281 template<typename Result>
282 static Result from_variant( const variant& v, Result*, const std::shared_ptr<fc::api_connection>& )
283 {
284 return v.as<Result>();
285 }
286
287 template<typename ResultInterface>
288 static fc::api<ResultInterface> from_variant( const variant& v,
289 fc::api<ResultInterface>* /*used for template deduction*/,
290 const std::shared_ptr<fc::api_connection>& con
291 )
292 {
293 return con->get_remote_api<ResultInterface>( v.as_uint64() );
294 }
295
296 static fc::api_ptr from_variant(
297 const variant& v,
298 fc::api_ptr* /* used for template deduction */,
299 const std::shared_ptr<fc::api_connection>& con
300 )
301 {
302 return fc::api_ptr( new detail::any_api( v.as_uint64(), con ) );
303 }
304
305 template<typename T>
306 static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>&, const T& v )
307 {
308 return fc::variant(v);
309 }
310
311 template<typename Signature>
312 static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>& con, const std::function<Signature>& v )
313 {
314 return con->register_callback( v );
315 }
316
317 template<typename Result, typename... Args>
318 void operator()( const char* name, std::function<Result(Args...)>& memb )const
319 {
320 auto con = _connection;
321 auto api_id = _api_id;
322 memb = [con,api_id,name]( Args... args ) {
323 auto var_result = con->send_call( api_id, name, { convert_callbacks(con,args)...} );
324 return from_variant( var_result, (Result*)nullptr, con );
325 };
326 }
327 template<typename... Args>
328 void operator()( const char* name, std::function<void(Args...)>& memb )const
329 {
330 auto con = _connection;
331 auto api_id = _api_id;
332 memb = [con,api_id,name]( Args... args ) {
333 con->send_call( api_id, name, { convert_callbacks(con,args)...} );
334 };
335 }
336 };
337 };
338
340 {
341 public:
343 virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ) override
344 {
346 return _remote_connection->receive_call( api_id, method_name, std::move(args) );
347 }
348 virtual variant send_callback( uint64_t callback_id, variants args = variants() ) override
349 {
351 return _remote_connection->receive_callback( callback_id, args );
352 }
353 virtual void send_notice( uint64_t callback_id, variants args = variants() ) override
354 {
356 _remote_connection->receive_notice( callback_id, args );
357 }
358
359
360 void set_remote_connection( const std::shared_ptr<fc::api_connection>& rc )
361 {
363 FC_ASSERT( rc != this->shared_from_this() );
365 }
366 const std::shared_ptr<fc::api_connection>& remote_connection()const { return _remote_connection; }
367
368 std::shared_ptr<fc::api_connection> _remote_connection;
369 };
370
371 template<typename Api>
372 generic_api::generic_api( const Api& a, const std::shared_ptr<fc::api_connection>& c )
373 :_api_connection(c),_api(a)
374 {
375 boost::any_cast<const Api&>(a)->visit( api_visitor( *this, c ) );
376 }
377
378 template<typename Interface, typename Adaptor, typename ... Args>
379 std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
380 const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const
381 {
382 auto api_con = _api_con;
383 auto gapi = &_api;
384 return [=]( const variants& args ) {
385 auto con = api_con.lock();
386 FC_ASSERT( con, "not connected" );
387
388 auto api_result = gapi->call_generic( f, args.begin(), args.end() );
389 return con->register_api( api_result );
390 };
391 }
392 template<typename Interface, typename Adaptor, typename ... Args>
393 std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
394 const std::function<std::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const
395 {
396 auto api_con = _api_con;
397 auto gapi = &_api;
398 return [=]( const variants& args )-> fc::variant {
399 auto con = api_con.lock();
400 FC_ASSERT( con, "not connected" );
401
402 auto api_result = gapi->call_generic( f, args.begin(), args.end() );
403 if( api_result )
404 return con->register_api( *api_result );
405 return variant();
406 };
407 }
408
409 template<typename ... Args>
410 std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
411 const std::function<fc::api_ptr(Args...)>& f )const
412 {
413 auto api_con = _api_con;
414 auto gapi = &_api;
415 return [=]( const variants& args ) -> fc::variant {
416 auto con = api_con.lock();
417 FC_ASSERT( con, "not connected" );
418
419 auto api_result = gapi->call_generic( f, args.begin(), args.end() );
420 if( !api_result )
421 return variant();
422 return api_result->register_api( *con );
423 };
424 }
425
426 template<typename R, typename ... Args>
427 std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
428 {
429 generic_api* gapi = &_api;
430 return [f,gapi]( const variants& args ) {
431 return variant( gapi->call_generic( f, args.begin(), args.end() ) );
432 };
433 }
434
435 template<typename ... Args>
436 std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
437 {
438 generic_api* gapi = &_api;
439 return [f,gapi]( const variants& args ) {
440 gapi->call_generic( f, args.begin(), args.end() );
441 return variant();
442 };
443 }
444
458 template< typename Interface, typename Transform >
460 {
461 return conn.register_api( *this );
462 }
463
464 template< typename T >
466 {
467 // TODO: this method should probably be const (if it is not too hard)
468 api<T>* maybe_requested_type = dynamic_cast< api<T>* >(this);
469 if( maybe_requested_type != nullptr )
470 return *maybe_requested_type;
471
472 detail::any_api* maybe_any = dynamic_cast< detail::any_api* >(this);
473 FC_ASSERT( maybe_any != nullptr );
474 std::shared_ptr< api_connection > api_conn = maybe_any->_api_connection.lock();
475 FC_ASSERT( api_conn );
476 return api_conn->get_remote_api<T>( maybe_any->_api_id );
477 }
478
479 namespace detail {
480 template<typename Signature>
481 template<typename... Args>
483 {
484 std::shared_ptr< fc::api_connection > locked = _api_connection.lock();
485 // TODO: make new exception type for this instead of recycling eof_exception
486 if( !locked )
487 throw fc::eof_exception();
488 locked->send_callback( _callback_id, fc::variants{ args... } ).template as< result_type >();
489 }
490
491
492 template<typename... Args>
493 class callback_functor<void(Args...)>
494 {
495 public:
496 typedef void result_type;
497
498 callback_functor( std::weak_ptr< fc::api_connection > con, uint64_t id )
499 :_callback_id(id),_api_connection(con){}
500
501 void operator()( Args... args )const
502 {
503 std::shared_ptr< fc::api_connection > locked = _api_connection.lock();
504 // TODO: make new exception type for this instead of recycling eof_exception
505 if( !locked )
506 throw fc::eof_exception();
507 locked->send_notice( _callback_id, fc::variants{ args... } );
508 }
509
510 private:
511 uint64_t _callback_id;
512 std::weak_ptr< fc::api_connection > _api_connection;
513 };
514 } // namespace detail
515
516} // fc
std::string name
api< T, identity_member > as()
variant receive_callback(uint64_t callback_id, const variants &args=variants()) const
std::vector< std::string > get_method_names(api_id_type local_api_id=0) const
virtual variant send_call(api_id_type api_id, string method_name, variants args=variants())=0
api< T > get_remote_api(api_id_type api_id=0)
fc::signal< void()> closed
uint64_t register_callback(const std::function< Signature > &cb)
virtual void send_notice(uint64_t callback_id, variants args=variants())=0
void receive_notice(uint64_t callback_id, const variants &args=variants()) const
virtual variant send_callback(uint64_t callback_id, variants args=variants())=0
api_id_type register_api(const Interface &a)
variant receive_call(api_id_type api_id, const string &method_name, const variants &args=variants()) const
virtual api_id_type register_api(api_connection &conn) const override
any_api(api_id_type api_id, const std::shared_ptr< fc::api_connection > &con)
virtual api_id_type register_api(api_connection &conn) const override
virtual uint64_t get_handle() const override
std::weak_ptr< fc::api_connection > _api_connection
callback_functor(std::weak_ptr< fc::api_connection > con, uint64_t id)
callback_functor(std::weak_ptr< fc::api_connection > con, uint64_t id)
result_type operator()(Args... args) const
std::function< Signature >::result_type result_type
generic_api(const generic_api &cpy)=delete
variant call(uint32_t method_id, const variants &args)
std::vector< std::string > get_method_names() const
std::weak_ptr< fc::api_connection > get_connection()
friend struct api_visitor
variant call(const string &name, const variants &args)
generic_api(const Api &a, const std::shared_ptr< fc::api_connection > &c)
std::shared_ptr< fc::api_connection > _remote_connection
const std::shared_ptr< fc::api_connection > & remote_connection() const
void set_remote_connection(const std::shared_ptr< fc::api_connection > &rc)
virtual void send_notice(uint64_t callback_id, variants args=variants()) override
virtual variant send_call(api_id_type api_id, string method_name, variants args=variants()) override
virtual variant send_callback(uint64_t callback_id, variants args=variants()) override
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
uint64_t as_uint64() const
Definition variant.cpp:398
T as() const
Definition variant.hpp:327
uint64_t id
Definition code_cache.cpp:0
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
std::function< variant(const fc::variants &)> to_generic(const std::function< R(Args...)> &f)
R call_generic(const std::function< R()> &f, variants::const_iterator a0, variants::const_iterator e)
std::function< R(Args...)> bind_first_arg(const std::function< R(Arg0, Args...)> &f, Arg0 a0)
namespace sysio::chain
Definition authority.cpp:3
uint32_t api_id_type
Definition api.hpp:46
boost::any any
Definition any.hpp:6
std::vector< fc::variant > variants
Definition variant.hpp:173
std::shared_ptr< api_base > api_ptr
Definition api.hpp:62
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
#define T(meth, val, expected)
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
#define R
char * s
yh_rc rc