采用异步读写的方式调用异步处理宏CALL_ASYNC。call_name是调用的函数名,call_result传入声明的结果接收体(例如chain_apis::read_write::push_transaction_results),http_response_code是响应码。下面进入宏CALL_ASYNC。
/** * @attention 目前调用CALL_ASYNC函数的只有read_write的应用。 * @param api_name "chain' * @param api_handle app().get_plugin<chain_plugin>().get_read_write_api(); * @param api_namespace chain_apis::read_write * @param call_name -INHERIT * @param call_result -INHERIT * @param http_response_code -INHERIT */ #define CALL_ASYNC(api_name, api_handle, api_namespace, call_name, call_result, http_response_code) \ {std::string("/v1/" #api_name "http://www.likecs.com/" #call_name), \ /*同上,拼接接口url::port/v1/chain/{call_name}*/ \ /* * http处理请求的函数结构不变,同上。 * @param body:http请求体 * @param cb:回调函数,用于返回处理结果 */ \ [api_handle](string, string body, url_response_callback cb) mutable { \ if (body.empty()) body = "{}"; \ api_handle.validate(); \ /* * api_handle为chain_plugin中read_only类的实例 * call_name为函数名,实现体找chain_plugin.cpp文件 * 函数参数2个: * @param 此处规定了一个命名规则,接口名加入后缀_param即为请求参数结构 * @param lambda表达式,将cb和body按值传递进内部函数,该内部函数整体作为异步操作的回调函数,注意与http的回调函数cb区分。 */ \ api_handle.call_name(fc::json::from_string(body).as<api_namespace::call_name ## _params>(),\ [cb, body](const fc::static_variant<fc::exception_ptr, call_result>& result){\ /*捕获异常,分发异常处理*/ \ if (result.contains<fc::exception_ptr>()) {\ try {\ result.get<fc::exception_ptr>()->dynamic_rethrow_exception();\ } catch (...) {\ http_plugin::handle_exception(#api_name, #call_name, body, cb);\ }\ } else {\ /* * 异步处理成功,通过http的回调函数cb返回结果。 */ \ cb(http_response_code, result.visit(async_result_visitor()));\ }\ });\ }\ }其中最后处理结果的语句比较令人好奇result.visit(async_result_visitor())
result的类型是:const fc::static_variant<fc::exception_ptr, call_result>&
async_result_visitor()函数:
接着,进入fc库的static_variant.hpp文件中寻找类static_variant,它包含一个模板函数visit:
template<typename visitor> typename visitor::result_type visit(const visitor& v)const { return impl::storage_ops<0, Types...>::apply(_tag, storage, v); }异步处理将处理结果转型放置在结果容器中。
api_handle参数异步读写的请求传入的api_handle参数值为rw_api变量,该变量是在chain_api_plugin插件启动chain_api_plugin::plugin_startup时(插件的生命周期前文已有介绍)初始化的,
auto rw_api = app().get_plugin<chain_plugin>().get_read_write_api();app()函数以及与application类相关的内容前文已经介绍过,通过get_plugin<chain_plugin>获取chain_plugin的实例,然后调用其成员函数get_read_write_api(),
chain_apis::read_write get_read_write_api() { return chain_apis::read_write(chain(), get_abi_serializer_max_time()); }返回的是chain_apis::read_write构造函数返回的read_write实例。类read_write中包含了所有基于读写机制的接口实现,与上面接口列表中声明的保持一致。
read_write(controller& db, const fc::microseconds& abi_serializer_max_time) : db(db), abi_serializer_max_time(abi_serializer_max_time) {}因此,最后传入CALL_ASYNC宏的api_handle参数值实际就是这个类read_write的实例。之后使用该实例去调用call_name,就是简单的实例调用自身成员函数(一般这个成员函数是声明和实现都有的)的逻辑了。
chain_api_plugin生命周期set_program_options,空
plugin_initialize,空
plugin_startup,添加rpc接口,请求chain_plugin功能函数。
plugin_shutdown,空
二、结构体成员序列化FC_REFLECTFC_REFLECT为结构体提供序列化成员的能力。
FC_REFLECT是FC库中提供反射功能的宏。反射的意义在于了解一个未知的对象,反射是不限编程语言的,通过反射能够获取到对象的成员结构。宏#define FC_REFLECT( TYPE, MEMBERS )内部又调用了宏#define FC_REFLECT_DERIVED( TYPE, INHERITS, MEMBERS ),反射功能的具体实现就不深入探究了。下面来看其应用,举个例子:
FC_REFLECT( eosio::chain_apis::read_only::get_required_keys_params, (transaction)(available_keys) ) FC_REFLECT( eosio::chain_apis::read_only::get_required_keys_result, (required_keys) )