steem的API插件
都位于源碼的libraries\plugins\apis
目錄下。這些API插件
的基本上都包含兩個(gè)cpp:pname_api.cpp
和pname_api_plugin.cpp
。本文將理清這些在命名上容易混淆的cpp文件的關(guān)系,分析steem這套API框架的實(shí)現(xiàn),以及外部以何種方式來調(diào)用這些APIs污茵。
steemd
自己用宏實(shí)現(xiàn)一套API聲明注冊(cè)的框架涮雷,每個(gè)API依溯,對(duì)應(yīng)一個(gè)class老厌,如condenser_api
。這個(gè)class并不實(shí)現(xiàn)任何API的邏輯黎炉,每個(gè)API下的方法對(duì)應(yīng)的實(shí)現(xiàn)枝秤,由存儲(chǔ)在class內(nèi)的my
指 針上,該指針必須使用這個(gè)名稱慷嗜。然后需要對(duì)外暴露哪些方法淀弹,則使用DECLARE_API
/DEFINE_READ_APIS
來聲明、 實(shí)現(xiàn)這個(gè)代理層庆械,然后其生成的方法會(huì)調(diào)用my
指針指向的實(shí)現(xiàn)類里對(duì)應(yīng)的方法薇溃。
下面以condenser API為例。
condenser模塊
condenser模塊是前端瀏覽器訪問區(qū)塊鏈鏈上信息的入口模塊, 它主要由condenser_api_plugin
和condenser_api
構(gòu)成缭乘,同時(shí)它還依賴json_rpc
和database
提供的JSON解析和共享內(nèi)存訪問功能沐序,最終得以實(shí)現(xiàn)前端區(qū)塊信息瀏覽。先看其api插件類condenser_api_plugin
的定義:
class condenser_api_plugin : public appbase::plugin< condenser_api_plugin >
{
public:
APPBASE_PLUGIN_REQUIRES( (steem::plugins::json_rpc::json_rpc_plugin)(steem::plugins::database_api::database_api_plugin) )
condenser_api_plugin();
virtual ~condenser_api_plugin();
static const std::string& name() { static std::string name = STEEM_CONDENSER_API_PLUGIN_NAME; return name; }
virtual void set_program_options( options_description& cli, options_description& cfg ) override;
virtual void plugin_initialize( const variables_map& options ) override;
virtual void plugin_startup() override;
virtual void plugin_shutdown() override;
std::shared_ptr< class condenser_api > api;
};
-
condenser_api_plugin
是一個(gè)插件類堕绩,按照插件類的實(shí)現(xiàn)要求策幼,它實(shí)現(xiàn)了abstract_plugin
要求final派生類必須實(shí)現(xiàn)的4個(gè)純虛函數(shù)。 -
condenser_api_plugin
插件依賴兩個(gè)插件:json_rpc_plugin
和database_api_plugin
- 只有一個(gè)數(shù)據(jù)成員即
api
奴紧,指向API類condenser_api
特姐,這樣就將api插件類
與對(duì)應(yīng)的api類
聯(lián)系起來。
condenser_api類
API類condenser_api
的定義:
class condenser_api
{
public:
condenser_api();
~condenser_api();
DECLARE_API(
....
(get_state)
(get_block)
(get_accounts)
...
(lookup_accounts)
(get_witnesses)
...
)
private:
friend class condenser_api_plugin;
void api_startup();
std::unique_ptr< detail::condenser_api_impl > my;
};
condenser_api
封裝一組對(duì)外的公共方法黍氮,因?yàn)?code>condenser_api_plugin會(huì)在plugin_startup
在調(diào)用私有方法api_startup
唐含,故將其聲明為友元類.
API類的方法聲明
該類中每個(gè)方法通過DECLARE_API
來宏來聲明,支持一次聲明多個(gè)方法沫浆。例如chain_api
類:
DECLARE_API( (push_block) (push_transaction) )
先看宏DECLARE_API
的定義:
#define DECLARE_API( METHODS ) \
BOOST_PP_SEQ_FOR_EACH( DECLARE_API_METHOD_HELPER, _, METHODS ) \
\
template< typename Lambda > \
void for_each_api( Lambda&& callback ) \
{ \
BOOST_PP_SEQ_FOR_EACH( FOR_EACH_API_HELPER, callback, METHODS ) \
}
這個(gè)宏①聲明condenser對(duì)外提供的APIs: 各個(gè)get_*
方法②定義了for_each_api
方法捷枯,用于注冊(cè)到所有方法到json_rpc_plugin
通過展開宏BOOST_PP_SEQ_FOR_EACH
:
DECLARE_API_METHOD_HELPER(r, _, get_state) \
DECLARE_API_METHOD_HELPER(r, _, get_block) \
DECLARE_API_METHOD_HELPER(r, _, get_witnesses) \
... \
展開宏DECLARE_API_METHOD_HELPER
#define DECLARE_API_METHOD_HELPER( r, data, method ) \
BOOST_PP_CAT( method, _return ) method( const BOOST_PP_CAT( method, _args )& args, bool lock = false );
//===>展開BOOST_PP_CAT
#define DECLARE_API_METHOD_HELPER( r, data, method ) \
method_return method(const method_args& args, bool lock = false);
最終在condenser_api
類聲明了一組方法:
...
get_state_return
get_state(const get_state_args& args, bool lock = false);
get_block_return
get_block(const get_block_args& args, bool lock = false);
get_witnesses_return
get_witnesses(const get_witnesses_args& args, bool lock = false);
...
再看②for_each_api
,將這個(gè)模板函數(shù)的宏展開:
template< typename Lambda >
void for_each_api( Lambda&& callback )
{
# 對(duì)于每個(gè)method都聲明這么對(duì)應(yīng)的一個(gè)代碼塊
{
typedef std::remove_pointer<decltype(this)>::type this_type;
callback(*this, "${method}", &this_type::${method},
static_cast< ${method}_args *>(nullptr),
static_cast< ${method}_return *>(nullptr)
);
}
...
}
condenser_api
類通過宏展開后就是:
class condenser_api
{
public:
condenser_api();
~condenser_api();
//各個(gè)對(duì)外方法聲明
get_state_return
get_state(const get_state_args& args, bool lock = false);
get_block_return
get_block(const get_block_args& args, bool lock = false);
get_witnesses_return
get_witnesses(const get_witnesses_args& args, bool lock = false);
...
//將方法注冊(cè)到j(luò)son_rpc_plugin
template< typename Lambda >
void for_each_api( Lambda&& callback )
{
//for get_state
{
typedef std::remove_pointer<decltype(this)>::type this_type;
callback(*this, "get_state", &this_type::get_state,
static_cast< get_state_args *>(nullptr),
static_cast< get_state_return *>(nullptr)
);
}
//for get_block
{
typedef std::remove_pointer<decltype(this)>::type this_type;
callback(*this, "get_block", &this_type::get_block,
static_cast< get_block_args *>(nullptr),
static_cast< get_block_return *>(nullptr)
);
}
//for get_witnesses
{
typedef std::remove_pointer<decltype(this)>::type this_type;
callback(*this, "get_witnesses", &this_type::get_witnesses,
static_cast< get_witnesses_args *>(nullptr),
static_cast< get_witnesses_return *>(nullptr)
);
}
//for other get_*
...
}//end of for_each_api
private:
friend class condenser_api_plugin;
void api_startup();
std::unique_ptr< detail::condenser_api_impl > my;
};
在condenser_api
構(gòu)造函數(shù)中,register_api_method_visitor
調(diào)用for_each_api
, 實(shí)現(xiàn)方法注冊(cè)到json_rpc_plugin
:
condenser_api::condenser_api()
: my( new detail::condenser_api_impl() )
{
JSON_RPC_REGISTER_API( STEEM_CONDENSER_API_PLUGIN_NAME );
}
//---->展開JSON_RPC_REGISTER_API后
condenser_api::condenser_api()
: my( new detail::condenser_api_impl() )
{
{
steem::plugins::json_rpc::detail::register_api_method_visitor vtor( "condenser_api" );
for_each_api( vtor );
}
}
register_api_method_visitor
是一個(gè)可調(diào)用對(duì)象模板類
//constructor
//_json_rpc_plugin是application中json_rpc_plugin插件的引用
register_api_method_visitor( const std::string& api_name )
: _api_name( api_name ), //"condenser_api"
_json_rpc_plugin( appbase::app().get_plugin<steem::plugins::json_rpc::json_rpc_plugin >() )
{}
...
template< typename Plugin, typename Method, typename Args, typename Ret >
void operator()(
Plugin& plugin, //condenser_api
const std::string& method_name, //方法名专执,比如"get_block"
Method method, //方法淮捆,比如condenser_api::get_block
Args* args, //static_cast< get_block_args *>(nullptr),
Ret* ret ) //static_cast< get_block_return *>(nullptr)
{
//注冊(cè)condenser_api的所有方法到j(luò)son_rpc_plugin
_json_rpc_plugin.add_api_method(
_api_name,
method_name,
[&plugin,method]( const fc::variant& args ) -> fc::variant
{
return fc::variant( (plugin.*method)( args.as< Args >(), true ) );
},
api_method_signature{ fc::variant( Args() ), fc::variant( Ret() ) } );
}
...
這樣就將condenser_api
的聲明所有方法的注冊(cè)到json_rpc_plugin
下篇將介紹condenser_api_impl