在上一篇 EOS應(yīng)用程序框架appbase已經(jīng)提到appbase給插件提供了插件之間的通信接口channel和method张抄, 使插件的之間的通信耦合性更加低局扶,一般我們把method看成是函數(shù)調(diào)用接口一般為1對(duì)1,channel為廣播一般有多個(gè)收聽者兰英,不管是method還是channel它們的實(shí)現(xiàn)都是基于boost::signals2::signal(類似QT中的信號(hào)槽)
接口的注冊(cè)
接口的注冊(cè)其實(shí)就是定義一個(gè)method或者channel接口說(shuō)明類型,說(shuō)明調(diào)用的參數(shù)跟返回值,然后任何插件可以實(shí)現(xiàn)該接口并使用厌蔽,eos中chain注冊(cè)的接口:
namespace eosio { namespace chain { namespace plugin_interface {
using namespace eosio::chain;
using namespace appbase;
template<typename T>
using next_function = std::function<void(const fc::static_variant<fc::exception_ptr, T>&)>;
struct chain_plugin_interface;
namespace channels {
using pre_accepted_block = channel_decl<struct pre_accepted_block_tag, signed_block_ptr>;
using rejected_block = channel_decl<struct rejected_block_tag, signed_block_ptr>;
using accepted_block_header = channel_decl<struct accepted_block_header_tag, block_state_ptr>;
using accepted_block = channel_decl<struct accepted_block_tag, block_state_ptr>;
using irreversible_block = channel_decl<struct irreversible_block_tag, block_state_ptr>;
using accepted_transaction = channel_decl<struct accepted_transaction_tag, transaction_metadata_ptr>;
using applied_transaction = channel_decl<struct applied_transaction_tag, transaction_trace_ptr>;
using accepted_confirmation = channel_decl<struct accepted_confirmation_tag, header_confirmation>;
}
namespace methods {
using get_block_by_number = method_decl<chain_plugin_interface, signed_block_ptr(uint32_t block_num)>;
using get_block_by_id = method_decl<chain_plugin_interface, signed_block_ptr(const block_id_type& block_id)>;
using get_head_block_id = method_decl<chain_plugin_interface, block_id_type ()>;
using get_lib_block_id = method_decl<chain_plugin_interface, block_id_type ()>;
using get_last_irreversible_block_number = method_decl<chain_plugin_interface, uint32_t ()>;
}
namespace incoming {
namespace channels {
using block = channel_decl<struct block_tag, signed_block_ptr>;
using transaction = channel_decl<struct transaction_tag, packed_transaction_ptr>;
}
namespace methods {
// synchronously push a block/trx to a single provider
using block_sync = method_decl<chain_plugin_interface, void(const signed_block_ptr&), first_provider_policy>;
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
}
}
namespace compat {
namespace channels {
using transaction_ack = channel_decl<struct accepted_transaction_tag, std::pair<fc::exception_ptr, packed_transaction_ptr>>;
}
}
} } }
1)channel接口using accepted_block_header = channel_decl<struct accepted_block_header_tag, block_state_ptr>; 這里就定義了一個(gè)channel類型的說(shuō)明接口channel_decl<>,其中第一個(gè)類型accepted_block_header_tag這個(gè)我們可以不用管因?yàn)闆](méi)什么用摔癣,第二個(gè)類型block_state_ptr表示該channel接口的參數(shù)為block_state_ptr奴饮,因?yàn)閏hannel沒(méi)有返回值所以這里不需要定義返回值
2)method接口using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, next_function<transaction_trace_ptr>), first_provider_policy>; 這里就定義了一個(gè)method類型的說(shuō)明接口method_decl<>, 這是一個(gè)處理http接收到的trx的一個(gè)異步方法择浊,其中第一個(gè)類型chain_plugin_interface這個(gè)我們可以不用管因?yàn)闆](méi)什么用拐云,第二個(gè)參數(shù)void(const packed_transaction_ptr&, bool, next_function<transaction_trace_ptr>), first_provider_policy>是一個(gè)接口參數(shù)跟返回類型的定義,該接口的返回類型為void近她,參數(shù)為一共有3個(gè)
接口的使用
接口注冊(cè)完成之后可以通過(guò)app().get_method<...>()叉瘩,app().get_channel<...>()來(lái)獲取接口對(duì)象,例如get_method:
template<typename MethodDecl>
auto get_method() -> std::enable_if_t<is_method_decl<MethodDecl>::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()如果該接口類型已經(jīng)存在直接返回反之則創(chuàng)建粘捎,所以具體的某種類型的接口只會(huì)被創(chuàng)建一次后面返回的都是同一個(gè)接口對(duì)象薇缅,返回類型 std::enable_if_t<is_method_decl<MethodDecl>::value, typename MethodDecl::method_type&>表示如果MethodDecl該接口類型已經(jīng)注冊(cè)則返回MethodDecl::method_type類型對(duì)象危彩,MethodDecl::method_type定義
template< typename Tag, typename FunctionSig, template <typename> class DispatchPolicy = first_success_policy>
struct method_decl {
using method_type = method<FunctionSig, DispatchPolicy<FunctionSig>>;
using tag_type = Tag;
};
獲取接口對(duì)象
using eosio::chain::plugin_interface::incoming::methods
auto transaction_async_method = app().get_method<transaction_async>();
1)接口的調(diào)用方
上述獲取到接口對(duì)象之后直接調(diào)用
transaction_async_method (pretty_input, true, [this, next](const fc::static_variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void{
...
});
2)接口的被調(diào)用方(接口的實(shí)現(xiàn))
如果沒(méi)有被調(diào)用方,調(diào)用方調(diào)用接口之后會(huì)直接返回泳桦,接口的被調(diào)用方可以通過(guò)register_provider實(shí)現(xiàn)接口
transaction_async_method.register_provider([this](const packed_transaction_ptr& trx, bool persist_until_expired, next_function<transaction_trace_ptr> next) -> void {
return my->on_incoming_transaction_async(trx, persist_until_expired, next );
});
channel接口的使用跟上述method大同小異汤徽,channel接口的接收方/被調(diào)用方通過(guò)channel對(duì)象的subscribe方法注冊(cè),目前method的調(diào)用為同步灸撰,channel的調(diào)用為異步谒府。