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