# 插件

EMQ X 发行包中,包含了大量的官方插件,提供了一些基础的、或各类扩展的功能。

它们依赖于 emqx (opens new window) 的代码 API 或者 钩子 进行实现其特殊的功能。

然后通过打包编译工具 emqx-rel (opens new window) 将其与 emqx (opens new window) 核心项目一起编译并打包至一个可运行的软件包中。

# 插件列表

目前 EMQ X 发行包提供的插件包括:

插件配置文件说明
emqx_dashboard (opens new window)etc/plugins/emqx_dashbord.confWeb 控制台插件 (默认加载)
emqx_management (opens new window)etc/plugins/emqx_management.confHTTP API 与 CLI 管理插件
emqx_auth_clientid (opens new window)etc/plugins/emqx_auth_clientid.confClientId 认证插件
emqx_auth_username (opens new window)etc/plugins/emqx_auth_username.conf用户名、密码认证插件
emqx_auth_jwt (opens new window)etc/plugins/emqx_auth_jwt.confJWT 认证 / 访问控制
emqx_auth_ldap (opens new window)etc/plugins/emqx_auth_ldap.confLDAP 认证 / 访问控制
emqx_auth_http (opens new window)etc/plugins/emqx_auth_http.confHTTP 认证 / 访问控制
emqx_auth_mongo (opens new window)etc/plugins/emqx_auth_mongo.confMongoDB 认证 / 访问控制
emqx_auth_mysql (opens new window)etc/plugins/emqx_auth_mysql.confMySQL 认证 / 访问控制
emqx_auth_pgsql (opens new window)etc/plugins/emqx_auth_pgsql.confPostgreSQL 认证 / 访问控制
emqx_auth_redis (opens new window)etc/plugins/emqx_auth_redis.confRedis 认证 / 访问控制
emqx_psk_file (opens new window)etc/plugins/emqx_psk_file.confPSK 支持
emqx_web_hook (opens new window)etc/plugins/emqx_web_hook.confWeb Hook 插件
emqx_lua_hook (opens new window)etc/plugins/emqx_lua_hook.confLua Hook 插件
emqx_retainer (opens new window)etc/plugins/emqx_retainer.confRetain 消息存储模块
emqx_rule_engine (opens new window)etc/plugins/emqx_rule_engine.conf规则引擎
emqx_bridge_mqtt (opens new window)etc/plugins/emqx_bridge_mqtt.confMQTT 消息桥接插件
emqx_delayed_publish (opens new window)etc/plugins/emqx_delayed_publish.conf客户端延时发布消息支持
emqx_coap (opens new window)etc/plugins/emqx_coap.confCoAP 协议支持
emqx_lwm2m (opens new window)etc/plugins/emqx_lwm2m.confLwM2M 协议支持
emqx_sn (opens new window)etc/plugins/emqx_sn.confMQTT-SN 协议支持
emqx_stomp (opens new window)etc/plugins/emqx_stomp.confStomp 协议支持
emqx_recon (opens new window)etc/plugins/emqx_recon.confRecon 性能调试
emqx_reloader (opens new window)etc/plugins/emqx_reloader.conf代码热加载插件
emqx_plugin_template (opens new window)etc/plugins/emqx_plugin_template.conf插件开发模版

# 启停插件

目前启动插件有以下四种方式:

  1. 默认加载
  2. 命令行启停插件
  3. 使用 Dashboard 启停插件
  4. 调用管理 API 启停插件

开启默认加载

如需在 EMQ X 启动时就默认启动某插件,则直接在 data/loaded_plugins 添加需要启动的插件名称。

例如,目前 EMQ X 自动加载的插件有:

{emqx_management, true}.
{emqx_recon, true}.
{emqx_retainer, true}.
{emqx_dashboard, true}.
{emqx_rule_engine, true}.
{emqx_bridge_mqtt, false}.
1
2
3
4
5
6

命令行启停插件

在 EMQ X 运行过程中,可通过 CLI - Load/Unload Plugin 的方式查看、和启停某插件。

使用 Dashboard 启停插件

若开启了 Dashbord 的插件,可以直接通过访问 http://localhost:18083/plugins 中的插件管理页面启停插件。

使用管理 API 启停插件

在 EMQ X 运行过程中,可通过 管理监控 API - Load Plugin 的方式查看、和启停某插件。

# 插件开发

# 创建插件项目

参考 emqx_plugin_template (opens new window) 插件模版创建新的插件项目。

备注:在 <plugin name>_app.erl 文件中必须加上标签 -emqx_plugin(?MODULE). 以表明这是一个 EMQ X 的插件。

# 创建 认证/访问控制 模块

接入认证示例代码 - 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".
1
2
3
4
5
6
7
8
9
10
11
12
13
14

访问控制示例代码 - 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".
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

挂载认证、访问控制钩子示例代码 - 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, []).
1
2

# 挂载钩子

在扩展插件中,可通过挂载 钩子 来处理客户端上下线、主题订阅、消息收发等事件。

钩子挂载示例代码 - 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]}).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 注册 CLI 命令

处理命令行命令示例代码 - 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"}]).
1
2
3
4
5
6
7
8
9

注册命令行示例代码 - emqx_plugin_template_app.erl

ok = emqx_ctl:register_command(cmd, {emqx_cli_demo, cmd}, []),
1

插件加载后,使用./bin/emqx_ctl 验证新增的命令行:

./bin/emqx_ctl cmd arg1 arg2
1

# 插件配置文件

插件自带配置文件放置在 etc/${plugin_name}.conf|config。 EMQ X 支持两种插件配置格式:

  1. Erlang 原生配置文件格式 - ${plugin_name}.config
[
    {plugin_name, [
    {key, value}
    ]}
].
1
2
3
4
5
  1. sysctl 的 k = v 通用格式 - ${plugin_name}.conf
plugin_name.key = value
1

注:k = v 格式配置需要插件开发者创建 priv/plugin_name.schema 映射文件。

# 编译和发布插件

clone emqx-rel 项目:

git clone https://github.com/emqx/emqx-rel.git
1

rebar.config 添加依赖:

{deps,
   [ {plugin_name, {git, "url_of_plugin", {tag, "tag_of_plugin"}}}
   , ....
   ....
   ]
}
1
2
3
4
5
6

rebar.config 中 relx 段落添加:

{relx,
    [...
    , ...
    , {release, {emqx, git_describe},
       [
         {plugin_name, load},
       ]
      }
    ]
}
1
2
3
4
5
6
7
8
9
10