|
2 | 2 | How plugins work
|
3 | 3 | ----------------
|
4 | 4 |
|
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. |
6 | 7 |
|
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. |
10 | 9 |
|
11 | 10 | Registering plugins
|
12 | 11 | -------------------
|
13 | 12 |
|
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. |
20 | 17 |
|
21 | 18 | Autogenerating code
|
22 | 19 | -------------------
|
23 | 20 |
|
24 | 21 | 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`.
|
25 | 22 |
|
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). |
0 commit comments