Plugin Development and Management
Start/Stop Plugin
There are four ways to load plugins:
- Default loading
- Start and stop the plugin on command line
- Start and stop the plugin on Dashboard
- Start and stop the plugin by calling the management API
Default loading
If a plugin needs to start with the broker, add this plugin in data/loaded_plugins
.
For example, the plugins that are loaded by default are:
{emqx_management, true}.
{emqx_recon, true}.
{emqx_retainer, true}.
{emqx_dashboard, true}.
{emqx_rule_engine, true}.
{emqx_bridge_mqtt, false}.
Start/stop plugin on command line
When the EMQX is running, plugins can be checked, loaded/unloaded by CLI - Load/Unload Plugin:
Start/stop plugin on Dashboard
If Dashboard plugin is started (by default), the plugins can be start or stopped by visiting the managing page that can be found under http://localhost:18083/plugins
.
Start and stop plugins using management API
When EMQX Broker is running, you can view, start and stop a plugin through Managing and Monitoring API - Load Plugin.
Plugin Development
Create Plugin Project
Refer to the emqx_plugin_template plugin template to create a new plugin project.
Tip
The tag of -emqx_plugin (? MODULE)
should be added to <plugin name>_app.erl
file to indicate that this is an EMQX Broker plugin.
Create Authentication / Access Control Module
Authentication/Access sample code - emqx_auth_demo.erl
:
-module(emqx_auth_demo).
-export([ init/1
, check/2
, description/0
]).
init(Opts) -> {ok, Opts}.
check(_ClientInfo = #{clientid := ClientId, username := Username, password := Password}, _State) ->
io:format("Auth Demo: clientId=~p, username=~p, password=~p~n", [ClientId, Username, Password]),
ok.
description() -> "Auth Demo Module".
Access control sample code - emqx_acl_demo.erl
:
-module(emqx_acl_demo).
-include_lib("emqx/include/emqx.hrl").
%% ACL callbacks
-export([ init/1
, check_acl/5
, reload_acl/1
, description/0
]).
init(Opts) ->
{ok, Opts}.
check_acl({ClientInfo, PubSub, _NoMatchAction, Topic}, _State) ->
io:format("ACL Demo: ~p ~p ~p~n", [ClientInfo, PubSub, Topic]),
allow.
reload_acl(_State) ->
ok.
description() -> "ACL Demo Module".
Example code for mounting authentication and access control hooks - emqx_plugin_template_app.erl
:
ok = emqx:hook('client.authenticate', fun emqx_auth_demo:check/2, []),
ok = emqx:hook('client.check_acl', fun emqx_acl_demo:check_acl/5, []).
Load Hook
During the plugin extension, you can load hooks to handle events such as client online and offline, topic subscription, and message sending and receiving.
Hook load sample code - emqx_plugin_template.erl
:
load(Env) ->
emqx:hook('client.connect', {?MODULE, on_client_connect, [Env]}),
emqx:hook('client.connack', {?MODULE, on_client_connack, [Env]}),
emqx:hook('client.connected', {?MODULE, on_client_connected, [Env]}),
emqx:hook('client.disconnected', {?MODULE, on_client_disconnected, [Env]}),
emqx:hook('client.authenticate', {?MODULE, on_client_authenticate, [Env]}),
emqx:hook('client.check_acl', {?MODULE, on_client_check_acl, [Env]}),
emqx:hook('client.subscribe', {?MODULE, on_client_subscribe, [Env]}),
emqx:hook('client.unsubscribe', {?MODULE, on_client_unsubscribe, [Env]}),
emqx:hook('session.created', {?MODULE, on_session_created, [Env]}),
emqx:hook('session.subscribed', {?MODULE, on_session_subscribed, [Env]}),
emqx:hook('session.unsubscribed',{?MODULE, on_session_unsubscribed, [Env]}),
emqx:hook('session.resumed', {?MODULE, on_session_resumed, [Env]}),
emqx:hook('session.discarded', {?MODULE, on_session_discarded, [Env]}),
emqx:hook('session.takeovered', {?MODULE, on_session_takeovered, [Env]}),
emqx:hook('session.terminated', {?MODULE, on_session_terminated, [Env]}),
emqx:hook('message.publish', {?MODULE, on_message_publish, [Env]}),
emqx:hook('message.delivered', {?MODULE, on_message_delivered, [Env]}),
emqx:hook('message.acked', {?MODULE, on_message_acked, [Env]}),
emqx:hook('message.dropped', {?MODULE, on_message_dropped, [Env]}).
Register CLI Commands
Processing command line sample code - emqx_cli_demo.erl
:
-module(emqx_cli_demo).
-export([cmd/1]).
cmd(["arg1", "arg2"]) ->
emqx_cli:print ("ok");
cmd(_) ->
emqx_cli:usage ([{"cmd arg1 arg2", "cmd demo"}]).
Register command line sample code - emqx_plugin_template_app.erl
:
ok = emqx_ctl:register_command(cmd, {emqx_cli_demo, cmd}, []),
After the plugin is loaded, use ./bin/emqx_ctl
to verify the new command line:
./bin/emqx_ctl cmd arg1 arg2
Plugin Configuration File
Plug-in configuration files are placed in etc/${plugin_name}.conf|config
. EMQX Broker supports two plugin configuration formats:
- Erlang native configuration file format-
${plugin_name}.config
:
[
{plugin_name, [
{key, value}
]}
].
- Common format of
k = v
for sysctl-${plugin_name}.conf
:
plugin_name.key = value
Tip
k = v
format configuration requires the plugin developer to create priv/plugin_name.schema
mapping file.
Compile and Publish the Plugin
Clone emqx project
git clone https://github.com/emqx/emqx.git
Add plugin_name
as a dependency by describing it in lib-extra/plugins
:
{erlang_plugins,
[ {plugin_name, {git, "url_of_plugin", {tag, "tag_of_plugin"}}}
, ....
....
]
}
Build a release
$ export EMQX_EXTRA_PLUGINS=plugin_name
$ make
Run your code
Start the node (interactive mode)
./_build/emqx/rel/emqx/bin/emqx console
Load the plugin with the command:
./_build/emqx/rel/emqx/bin/emqx_ctl plugins load plugin_name
Tip
To have the plugin enabled/loaded by default, you can include it in data/loaded_plugins.tmpl
.