steem的API插件
都位于源码的libraries\plugins\apis
目录下。这些API插件
的基本上都包含两个cpp:pname_api.cpp
和pname_api_plugin.cpp
。本文将理清这些在命名上容易混淆的cpp文件的关系,分析steem这套API框架的实现,以及外部以何种方式来调用这些APIs。
steemd
自己用宏实现一套API声明注册的框架,每个API,对应一个class,如condenser_api
。这个class并不实现任何API的逻辑,每个API下的方法对应的实现,由存储在class内的my
指 针上,该指针必须使用这个名称。然后需要对外暴露哪些方法,则使用DECLARE_API
/DEFINE_READ_APIS
来声明、 实现这个代理层,然后其生成的方法会调用my
指针指向的实现类里对应的方法。
下面以condenser API为例。
condenser模块
condenser模块是前端浏览器访问区块链链上信息的入口模块, 它主要由condenser_api_plugin
和condenser_api
构成,同时它还依赖json_rpc
和database
提供的JSON解析和共享内存访问功能,最终得以实现前端区块信息浏览。先看其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
是一个插件类,按照插件类的实现要求,它实现了abstract_plugin
要求final派生类必须实现的4个纯虚函数。 -
condenser_api_plugin
插件依赖两个插件:json_rpc_plugin
和database_api_plugin
- 只有一个数据成员即
api
,指向API类condenser_api
,这样就将api插件类
与对应的api类
联系起来。
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
封装一组对外的公共方法,因为condenser_api_plugin
会在plugin_startup
在调用私有方法api_startup
,故将其声明为友元类.
API类的方法声明
该类中每个方法通过DECLARE_API
来宏来声明,支持一次声明多个方法。例如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 ) \
}
这个宏①声明condenser对外提供的APIs: 各个get_*
方法②定义了for_each_api
方法,用于注册到所有方法到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
,将这个模板函数的宏展开:
template< typename Lambda >
void for_each_api( Lambda&& callback )
{
# 对于每个method都声明这么对应的一个代码块
{
typedef std::remove_pointer::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();
//各个对外方法声明
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);
...
//将方法注册到json_rpc_plugin
template< typename Lambda >
void for_each_api( Lambda&& callback )
{
//for get_state
{
typedef std::remove_pointer::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::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::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
构造函数中,register_api_method_visitor
调用for_each_api
, 实现方法注册到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
是一个可调用对象模板类
//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() )
{}
...
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)
{
//注册condenser_api的所有方法到json_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
的声明所有方法的注册到json_rpc_plugin
下篇将介绍condenser_api_impl