steem API插件上

steem的API插件都位于源码的libraries\plugins\apis目录下。这些API插件的基本上都包含两个cpp:pname_api.cpppname_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_plugincondenser_api构成,同时它还依赖json_rpcdatabase提供的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_plugindatabase_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

你可能感兴趣的:(steem API插件上)