Skip to content

Commit

Permalink
Allow exposing public_api via get_api_by_name()
Browse files Browse the repository at this point in the history
This commit changes the required method signature of API class ctors.
The main reason is that the mapping of names to API objects occurs at
the connection level, which is an intermediate level between the level
of the app and the level of the individual API.  A shared_ptr reference
to api_connection_context (a container for state at this intermediate
level) is now passed to API ctor's along with the & reference to the
application.
  • Loading branch information
theoreticalbts committed May 13, 2016
1 parent 59e7ea9 commit a594663
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 36 deletions.
4 changes: 2 additions & 2 deletions example_plugins/hello_api/hello_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class hello_api_plugin : public steemit::app::plugin
class hello_api_api
{
public:
hello_api_api( steemit::app::application& app );
hello_api_api( const steemit::app::api_context& ctx );

/**
* Called immediately after the constructor. If the API class uses enable_shared_from_this,
Expand Down Expand Up @@ -96,7 +96,7 @@ std::string hello_api_plugin::get_message()
return result.str();
}

hello_api_api::hello_api_api( steemit::app::application& app ) : _app(app) {}
hello_api_api::hello_api_api( const steemit::app::api_context& ctx ) : _app(ctx.app) {}

void hello_api_api::on_api_startup() {}

Expand Down
16 changes: 10 additions & 6 deletions libraries/app/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@

namespace steemit { namespace app {

login_api::login_api(application& a)
:_app(a)
login_api::login_api(const api_context& ctx)
:_ctx(ctx)
{
}

Expand All @@ -54,7 +54,7 @@ namespace steemit { namespace app {
bool login_api::login(const string& user, const string& password)
{
idump((user)(password));
optional< api_access_info > acc = _app.get_api_access_info( user );
optional< api_access_info > acc = _ctx.app.get_api_access_info( user );
if( !acc.valid() )
return false;
if( acc->password_hash_b64 != "*" )
Expand All @@ -70,6 +70,8 @@ namespace steemit { namespace app {
}

idump((acc->allowed_apis));
std::map< std::string, api_ptr >& _api_map = _ctx.connection->api_map;

for( const std::string& api_name : acc->allowed_apis )
{
auto it = _api_map.find( api_name );
Expand All @@ -78,13 +80,15 @@ namespace steemit { namespace app {
continue;
}
idump((api_name));
_api_map[ api_name ] = _app.create_api_by_name( api_name );
api_context new_ctx( _ctx.app, api_name, _ctx.connection );
_api_map[ api_name ] = _ctx.app.create_api_by_name( new_ctx );
}
return true;
}

fc::api_ptr login_api::get_api_by_name( const string& api_name )const
{
const std::map< std::string, api_ptr >& _api_map = _ctx.connection->api_map;
auto it = _api_map.find( api_name );
if( it == _api_map.end() )
{
Expand All @@ -99,7 +103,7 @@ namespace steemit { namespace app {
return it->second;
}

network_broadcast_api::network_broadcast_api(application& a):_app(a)
network_broadcast_api::network_broadcast_api(const api_context& a):_app(a.app)
{
/// NOTE: cannot register callbacks in constructor because shared_from_this() is not valid.
}
Expand Down Expand Up @@ -183,7 +187,7 @@ namespace steemit { namespace app {
_app.p2p_node()->broadcast_transaction(trx);
}

network_node_api::network_node_api( application& a ) : _app( a )
network_node_api::network_node_api( const api_context& a ) : _app( a.app )
{
}

Expand Down
27 changes: 17 additions & 10 deletions libraries/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ using std::vector;

namespace bpo = boost::program_options;

api_context::api_context( application& _app, const std::string& _api_name, std::weak_ptr< api_connection_context > _connection )
: app(_app), api_name(_api_name), connection(_connection) {}

namespace detail {

class application_impl : public graphene::net::node_delegate
Expand Down Expand Up @@ -189,14 +192,18 @@ namespace detail {
void on_connection( const fc::http::websocket_connection_ptr& c )
{
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
std::shared_ptr< api_connection_context > conn_ctx = std::make_shared< api_connection_context >();

for( const std::string& name : _public_apis )
{
fc::api_ptr api = create_api_by_name( name );
api_context ctx( *_self, name, conn_ctx );
fc::api_ptr api = create_api_by_name( ctx );
if( !api )
{
elog( "Couldn't create API ${name}", ("name", name) );
continue;
}
conn_ctx->api_map[name] = api;
api->register_api( *wsc );
}
c->set_session_data( wsc );
Expand Down Expand Up @@ -362,20 +369,20 @@ namespace detail {
_apiaccess.permission_map.insert(std::make_pair(username, std::move(permissions)));
}

void register_api_factory( const string& name, std::function< fc::api_ptr() > factory )
void register_api_factory( const string& name, std::function< fc::api_ptr( const api_context& ) > factory )
{
_api_factories_by_name[name] = factory;
}

fc::api_ptr create_api_by_name( const string& name )
fc::api_ptr create_api_by_name( const api_context& ctx )
{
auto it = _api_factories_by_name.find(name);
auto it = _api_factories_by_name.find(ctx.api_name);
if( it == _api_factories_by_name.end() )
{
wlog( "unknown api: ${api}", ("api",name) );
wlog( "unknown api: ${api}", ("api",ctx.api_name) );
return nullptr;
}
return it->second();
return it->second(ctx);
}

/**
Expand Down Expand Up @@ -787,7 +794,7 @@ namespace detail {

std::map<string, std::shared_ptr<abstract_plugin> > _plugins_available;
std::map<string, std::shared_ptr<abstract_plugin> > _plugins_enabled;
flat_map< std::string, std::function< fc::api_ptr() > > _api_factories_by_name;
flat_map< std::string, std::function< fc::api_ptr( const api_context& ) > > _api_factories_by_name;
std::vector< std::string > _public_apis;

bool _is_finished_syncing = false;
Expand Down Expand Up @@ -904,14 +911,14 @@ bool application::is_finished_syncing() const
return my->_is_finished_syncing;
}

void application::register_api_factory( const string& name, std::function< fc::api_ptr() > factory )
void application::register_api_factory( const string& name, std::function< fc::api_ptr( const api_context& ) > factory )
{
return my->register_api_factory( name, factory );
}

fc::api_ptr application::create_api_by_name( const string& name )
fc::api_ptr application::create_api_by_name( const api_context& ctx )
{
return my->create_api_by_name( name );
return my->create_api_by_name( ctx );
}

void application::shutdown_plugins()
Expand Down
5 changes: 3 additions & 2 deletions libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* THE SOFTWARE.
*/

#include <steemit/app/api_context.hpp>
#include <steemit/app/application.hpp>
#include <steemit/app/database_api.hpp>
#include <steemit/chain/get_config.hpp>
Expand Down Expand Up @@ -185,8 +186,8 @@ void database_api_impl::cancel_all_subscriptions()
database_api::database_api( steemit::chain::database& db )
: my( new database_api_impl( db ) ) {}

database_api::database_api( steemit::app::application& app )
: database_api( *app.chain_database() ) {}
database_api::database_api( const steemit::app::api_context& ctx )
: database_api( *ctx.app.chain_database() ) {}

database_api::~database_api() {}

Expand Down
12 changes: 7 additions & 5 deletions libraries/app/include/steemit/app/api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
#pragma once

#include <steemit/app/api_context.hpp>
#include <steemit/app/database_api.hpp>
#include <steemit/chain/protocol/types.hpp>

Expand All @@ -46,14 +47,15 @@ namespace steemit { namespace app {
using namespace std;

class application;
struct api_context;

/**
* @brief The network_broadcast_api class allows broadcasting of transactions.
*/
class network_broadcast_api : public std::enable_shared_from_this<network_broadcast_api>
{
public:
network_broadcast_api(application& a);
network_broadcast_api(const api_context& a);

struct transaction_confirmation
{
Expand Down Expand Up @@ -114,7 +116,7 @@ namespace steemit { namespace app {
class network_node_api
{
public:
network_node_api(application& a);
network_node_api(const api_context& a);

/**
* @brief Return general network information, such as p2p port
Expand Down Expand Up @@ -152,6 +154,7 @@ namespace steemit { namespace app {

/// internal method, not exposed via JSON RPC
void on_api_startup();

private:
application& _app;
};
Expand All @@ -164,7 +167,7 @@ namespace steemit { namespace app {
class login_api
{
public:
login_api(application& a);
login_api(const api_context& ctx);
virtual ~login_api();

/**
Expand All @@ -184,8 +187,7 @@ namespace steemit { namespace app {
void on_api_startup();

private:
application& _app;
flat_map< std::string, fc::api_ptr > _api_map;
api_context _ctx;
};

}} // steemit::app
Expand Down
35 changes: 35 additions & 0 deletions libraries/app/include/steemit/app/api_context.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <map>
#include <string>
#include <utility>

#include <fc/api.hpp>

namespace steemit { namespace app {

class application;

/**
* Contains state shared by all API's on the same connection.
*/

struct api_connection_context
{
std::map< std::string, fc::api_ptr > api_map;
};

/**
* Contains information needed by API class constructors.
*/

struct api_context
{
api_context( application& _app, const std::string& _api_name, std::weak_ptr< api_connection_context > _connection );

application& app;
std::string api_name;
std::shared_ptr< api_connection_context > connection;
};

} }
9 changes: 5 additions & 4 deletions libraries/app/include/steemit/app/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#pragma once

#include <steemit/app/api_access.hpp>
#include <steemit/app/api_context.hpp>
#include <steemit/chain/database.hpp>

#include <graphene/net/node.hpp>
Expand Down Expand Up @@ -88,7 +89,7 @@ namespace steemit { namespace app {
/**
* Register a way to instantiate the named API with the application.
*/
void register_api_factory( const string& name, std::function< fc::api_ptr() > factory );
void register_api_factory( const string& name, std::function< fc::api_ptr( const api_context& ) > factory );

/**
* Convenience method to build an API factory from a type which only requires a reference to the application.
Expand All @@ -97,11 +98,11 @@ namespace steemit { namespace app {
void register_api_factory( const string& name )
{
idump((name));
register_api_factory( name, [this]() -> fc::api_ptr
register_api_factory( name, []( const api_context& ctx ) -> fc::api_ptr
{
// apparently the compiler is smart enough to downcast shared_ptr< api<Api> > to shared_ptr< api_base > automatically
// see http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast for example
std::shared_ptr< Api > api = std::make_shared< Api >( *this );
std::shared_ptr< Api > api = std::make_shared< Api >( ctx );
api->on_api_startup();
return std::make_shared< fc::api< Api > >( api );
} );
Expand All @@ -110,7 +111,7 @@ namespace steemit { namespace app {
/**
* Instantiate the named API. Currently this simply calls the previously registered factory method.
*/
fc::api_ptr create_api_by_name( const string& name );
fc::api_ptr create_api_by_name( const api_context& ctx );

/// Emitted when syncing finishes (is_finished_syncing will return true)
boost::signals2::signal<void()> syncing_finished;
Expand Down
4 changes: 2 additions & 2 deletions libraries/app/include/steemit/app/database_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ struct order_book
vector< order > bids;
};

class api_context;
class database_api_impl;
class application;

/**
* @brief The database_api class implements the RPC API for the chain database.
Expand All @@ -75,7 +75,7 @@ class database_api
{
public:
database_api(steemit::chain::database& db);
database_api(steemit::app::application& app);
database_api(const steemit::app::api_context& ctx);
~database_api();

///////////////////
Expand Down
5 changes: 3 additions & 2 deletions libraries/plugins/debug_node/debug_node_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <fc/optional.hpp>
#include <fc/variant_object.hpp>

#include <steemit/app/api_context.hpp>
#include <steemit/app/application.hpp>

#include <steemit/chain/block_database.hpp>
Expand Down Expand Up @@ -192,9 +193,9 @@ void debug_node_api_impl::debug_set_hardfork( uint32_t hardfork_id )

} // detail

debug_node_api::debug_node_api( steemit::app::application& app )
debug_node_api::debug_node_api( const steemit::app::api_context& ctx )
{
my = std::make_shared< detail::debug_node_api_impl >(app);
my = std::make_shared< detail::debug_node_api_impl >(ctx.app);
}

void debug_node_api::on_api_startup() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <fc/variant_object.hpp>

namespace steemit { namespace app {
class application;
class api_context;
} }

namespace steemit { namespace plugin { namespace debug_node {
Expand All @@ -20,7 +20,7 @@ class debug_node_api_impl;
class debug_node_api
{
public:
debug_node_api( steemit::app::application& app );
debug_node_api( const steemit::app::api_context& ctx );

void on_api_startup();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class private_message_plugin : public steemit::app::plugin
class private_message_api : public std::enable_shared_from_this<private_message_api> {
public:
private_message_api(){};
private_message_api(app::application& a):_app(&a){
private_message_api(const app::api_context& ctx):_app(&ctx.app){
ilog( "creating private message api" );
}
void on_api_startup(){
Expand Down

0 comments on commit a594663

Please sign in to comment.