Skip to content

Commit 0f55546

Browse files
committed
Update plugin documentation steemit#1331
1 parent 2de89fc commit 0f55546

File tree

6 files changed

+130
-141
lines changed

6 files changed

+130
-141
lines changed

doc/plugin.md

+30-12
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,44 @@
22
How plugins work
33
----------------
44

5-
All plugins in the `libraries/plugins` directory are iterated over by `CMakeLists.txt` and placed in a CMake environment variable `STEEM_INTERNAL_PLUGINS`, which is used to create a runtime-accessible list of available plugins used by the argument parsing.
5+
All plugins in the `libraries/plugins` directory are iterated over by `CMakeLists.txt`. The manifest directory iterates through all plugins, adding them to the `steem_plugins` build target. Any other build target wanting to access all plugins
6+
available at build time should link to this target.
67

7-
Similarly, `external_plugins` is set aside for third-party plugins. Just drop plugin code into `external_plugins` directory, `make steemd`, and the new plugin will be available.
8-
9-
There is a plugin in `example_plugins` called `hello_api` which is a working example of adding a custom API call.
8+
There is a plugin in `example_plugins` called `example_api_plugin` which is a working example of adding a custom API call.
109

1110
Registering plugins
1211
-------------------
1312

14-
- Plugins are enabled with the `enable-plugin` config file option.
15-
- When specifying plugins, you should specify `witness` and `account_history` in addition to the new plugins.
16-
- Some plugins may keep records in the database (currently only `account_history` does). If you change whether such a plugin is disabled/enabled, you should also replay the chain. Detecting this situation and automatically replaying when needed will be implemented in a future release.
17-
- If you want to make API's available publicly, you must use the `public-api` option.
18-
- When specifying public API's, you should specify `database_api` and `login_api` in addition to the new plugins.
19-
- The `api-user` option allows for password protected access to an API.
13+
- Plugins are enabled with the `plugins` config file option.
14+
- By default, steemd runs the `chain`, `p2p`, and `webserver` plugins.
15+
- Some plugins may keep records in the database (such as `account_history`). If you change whether such a plugin is disabled/enabled, you should also replay the chain. Detecting this situation and automatically replaying when needed will be implemented in a future release.
16+
- To make an API visible, include the associated plugin in the `plugins` config file option. Only APIs explicitly made available through the config will be registered.
2017

2118
Autogenerating code
2219
-------------------
2320

2421
A skeleton structure containing much of the boilerplate of creating a new plugin with an API can be autogenerated by running `programs/util/newplugin.py`.
2522

26-
- Register signal handlers in `plugin_startup()` (if needed)
27-
- Add methods to `myplugin_api` class and reflect them in `FC_API` declaration
23+
- Register signal handlers and custom evaluators in `plugin_initialize()` (if needed)
24+
- Register APIs in `plugin_initialize()`
25+
- API plugins should be separate from the stateful plugin they grant access to. This allows for the API to be disabled while keeping track of state for the plugin.
26+
27+
Startup/Shutdown of Plugins
28+
---------------------------
29+
30+
- Plugins can specify dependencies with the `APPBASE_PLUGIN_REQUIRES` macro, which takes a bubble list of dependencies.
31+
- There is undefined behavior if there are circular dependencies. Be careful how you design the data flow between plugins to eliminate circular dependencies.
32+
- `plugin_initialze` and `plugin_startup` both guarantee that any dependencies are already initialized or started before the dependent plugin is called.
33+
- `plugin_shutdown` is called in the reverse order from startup. Any dependencies will still be running when shutdown is called.
34+
- You can get a reference to a plugin with `appbase::app().get_plugin< PLUIGN >()` or a pointer with `appbase::app().find_plugin< PLUGIN >()`. get_plugin will fail and find_plugin will return a nullptr if the plugin is not registered or has not been initialized. These methods guarantee you are accessing initialized date.
35+
- Because of the inialization order, it is safe to call get/find_plugin on dependencies in initialization, startup, and shutdown.
36+
- It is only safe to call get/find_plugin on an optional dependency in startup. An optional dependency is not explicitly specified. It is simply some optional behavior if a plugin is enabled. See `condenser_api` for an example of optional dependencies.
37+
38+
Asynchronous APIs
39+
-----------------
40+
41+
-The json rpc plugin dispatches API requests asynchronously. This means your API call can be preempted or delayed and must be designed with parallelism in mind.
42+
- To help, chainbase provides a simple read/write locking mechanism: `with_read_lock` and `with_write_lock`.
43+
- This is a global lock over the entire database.
44+
- The methods take a lambda that will be protected with the lock. For most API calls, `with_read_lock` will be sufficient.
45+
- To ensure consistent block times, the read lock automatically expires after 1 second. Design your API call with this in mind. If the API call takes longer than 1 second, your results are undefined. It is best to create limitations on the API call to ensure it does not take longer than 1 second to execute (shorter than 250ms is preferable).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
file(GLOB HEADERS "include/steem/plugins/example_api_plugin/*.hpp")
2+
3+
add_library( example_api_plugin
4+
${HEADERS}
5+
example_api_plugin.cpp
6+
)
7+
8+
target_link_libraries( example_api_plugin appbase steem_chain fc )
9+
target_include_directories( example_api_plugin
10+
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#pragma once
2+
#include <appbase/application.hpp>
3+
4+
#include <steem/plugins/json_rpc/json_rpc_plugin.hpp>
5+
6+
#define STEEM_EXAMPLE_API_PLUGIN_NAME "example_api"
7+
8+
namespace steem { namespace example_api_plugin {
9+
10+
using namespace appbase;
11+
12+
13+
// Define API method arg and return types
14+
typedef json_rpc::void_type hello_world_args;
15+
16+
struct hello_world_return
17+
{
18+
string message;
19+
};
20+
21+
22+
struct echo_args
23+
{
24+
string call;
25+
};
26+
27+
struct echo_return
28+
{
29+
string response;
30+
}
31+
32+
33+
// All plugins must inherit from appbase::plugin
34+
class example_api_plugin : public appbase::plugin< example_api_plugin >
35+
{
36+
public:
37+
example_api_plugin();
38+
virtual ~example_api_plugin();
39+
40+
// This defines what plugins are required to run this plugin.
41+
// These plugins will load before this one and shutdown after.
42+
APPBASE_PLUGIN_REQUIRES( (plugins::json_rpc::json_rpc_plugin) );
43+
44+
// This static method is a required by the appbase::plugin template
45+
static const std::string& name() { static std::string name = STEEM_EXAMPLE_API_PLUGIN_NAME; return name; }
46+
47+
// Specify any config options here
48+
virtual void set_program_options( options_description&, options_description& ) override {}
49+
50+
// These implement startup and shutdown logic for the plugin.
51+
// plugin_initialize and plugin_startup are called such that dependencies go first
52+
// plugin_shutdown goes in reverse order such the dependencies are running when shutting down.
53+
virtual void plugin_initialize( const variables_map& options ) override;
54+
virtual void plugin_startup() override;
55+
virtual void plugin_shutdown() override;
56+
57+
// These are the API methods defined for the plugin
58+
// APIs take struct args and return structs
59+
hello_world_return hello_world( const hello_world_args& args );
60+
echo_return echo( const echo_args& args );
61+
};
62+
63+
example_api_plugin::example_api_plugin() {}
64+
example_api_plugin::~example_api_plugin() {}
65+
66+
void example_api_plugin::plugin_initialize( const variables_map& options )
67+
{
68+
// This registers the API with the json rpc plugin
69+
JSON_RPC_REGISTER_API( name(), (hello_world)(echo) );
70+
}
71+
72+
void example_api_plugin::plugin_startup() {}
73+
void example_api_plugin::plugin_shutdown() {}
74+
75+
hello_world_return hello_world( const hello_world_args& args )
76+
{
77+
return hello_world_return{ "Hello World" };
78+
}
79+
80+
echo_return echo( const echo_args& args )
81+
{
82+
return echo_return{ args.call };
83+
}
84+
85+
} } // steem::example_api_plugin
86+
87+
// Args and return types need to be reflected. hello_world_args does not because it is a typedef of a reflected type
88+
FC_REFLECT( steem::example_api_plugin::hello_world_return, (message) )
89+
FC_REFLECT( steem::example_api_plugin::echo_args, (call) )
90+
FC_REFLECT( steem::example_api_plugin::echo_return, (response) )

example_plugins/hello_api/CMakeLists.txt

-10
This file was deleted.

example_plugins/hello_api/hello_api_plugin.cpp

-117
This file was deleted.

libraries/plugins/apis/test_api/include/steem/plugins/test_api/test_api_plugin.hpp

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
#define STEEM_TEST_API_PLUGIN_NAME "test_api"
77

8-
#define REGISTER_API( api_name, ... )
9-
108
namespace steem { namespace plugins { namespace test_api {
119

1210
using namespace appbase;

0 commit comments

Comments
 (0)