EOS插件通信机制

在上一篇 EOS应用程序框架appbase已经提到appbase给插件提供了插件之间的通信接口channel和method, 使插件的之间的通信耦合性更加低,一般我们把method看成是函数调用接口一般为1对1,channel为广播一般有多个收听者,不管是method还是channel它们的实现都是基于boost::signals2::signal(类似QT中的信号槽)

接口的注册

接口的注册其实就是定义一个method或者channel接口说明类型,说明调用的参数跟返回值,然后任何插件可以实现该接口并使用,eos中chain注册的接口:

namespace eosio { namespace chain { namespace plugin_interface {
   using namespace eosio::chain;
   using namespace appbase;

   template
   using next_function = std::function&)>;

   struct chain_plugin_interface;

   namespace channels {
      using pre_accepted_block     = channel_decl;
      using rejected_block         = channel_decl;
      using accepted_block_header  = channel_decl;
      using accepted_block         = channel_decl;
      using irreversible_block     = channel_decl;
      using accepted_transaction   = channel_decl;
      using applied_transaction    = channel_decl;
      using accepted_confirmation  = channel_decl;

   }

   namespace methods {
      using get_block_by_number    = method_decl;
      using get_block_by_id        = method_decl;
      using get_head_block_id      = method_decl;
      using get_lib_block_id       = method_decl;

      using get_last_irreversible_block_number = method_decl;
   }

   namespace incoming {
      namespace channels {
         using block                 = channel_decl;
         using transaction           = channel_decl;
      }

      namespace methods {
         // synchronously push a block/trx to a single provider
         using block_sync            = method_decl;
         using transaction_async     = method_decl), first_provider_policy>;
      }
   }

   namespace compat {
      namespace channels {
         using transaction_ack       = channel_decl>;
      }
   }
} } }

1)channel接口using accepted_block_header = channel_decl; 这里就定义了一个channel类型的说明接口channel_decl<>,其中第一个类型accepted_block_header_tag这个我们可以不用管因为没什么用,第二个类型block_state_ptr表示该channel接口的参数为block_state_ptr,因为channel没有返回值所以这里不需要定义返回值
2)method接口using transaction_async = method_decl), first_provider_policy>; 这里就定义了一个method类型的说明接口method_decl<>, 这是一个处理http接收到的trx的一个异步方法,其中第一个类型chain_plugin_interface这个我们可以不用管因为没什么用,第二个参数void(const packed_transaction_ptr&, bool, next_function), first_provider_policy>是一个接口参数跟返回类型的定义,该接口的返回类型为void,参数为一共有3个

接口的使用

接口注册完成之后可以通过app().get_method<...>(),app().get_channel<...>()来获取接口对象,例如get_method:

template
auto get_method() -> std::enable_if_t::value, typename MethodDecl::method_type&>
{
     using method_type = typename MethodDecl::method_type;
     auto key = std::type_index(typeid(MethodDecl));
     auto itr = methods.find(key);
     if(itr != methods.end()) {
         return *method_type::get_method(itr->second);
     } else {
         methods.emplace(std::make_pair(key, method_type::make_unique()));
         return  *method_type::get_method(methods.at(key));
    }
}

上述get_method()如果该接口类型已经存在直接返回反之则创建,所以具体的某种类型的接口只会被创建一次后面返回的都是同一个接口对象,返回类型 std::enable_if_t::value, typename MethodDecl::method_type&>表示如果MethodDecl该接口类型已经注册则返回MethodDecl::method_type类型对象,MethodDecl::method_type定义

template< typename Tag, typename FunctionSig, template  class DispatchPolicy = first_success_policy>
   struct method_decl {
      using method_type = method>;
      using tag_type = Tag;
   };

获取接口对象

using eosio::chain::plugin_interface::incoming::methods
auto transaction_async_method = app().get_method();

1)接口的调用方
上述获取到接口对象之后直接调用

transaction_async_method (pretty_input, true, [this, next](const fc::static_variant& result) -> void{
         ...
      });

2)接口的被调用方(接口的实现)
如果没有被调用方,调用方调用接口之后会直接返回,接口的被调用方可以通过register_provider实现接口

   transaction_async_method.register_provider([this](const packed_transaction_ptr& trx, bool persist_until_expired, next_function next) -> void {
      return my->on_incoming_transaction_async(trx, persist_until_expired, next );
   });

channel接口的使用跟上述method大同小异,channel接口的接收方/被调用方通过channel对象的subscribe方法注册,目前method的调用为同步,channel的调用为异步。

你可能感兴趣的:(EOS插件通信机制)