# Plugins

The EMQ broker could be extended by plugins. Users could develop plugins to customize authentication, ACL and functions of the broker, or integrate the broker with other systems.

The plugins that EMQ 2.0-rc.2 released:

PluginDescription
emq_dashboard (opens new window)Web Dashboard
emq_retainer (opens new window)Store Retained Messages
emq_modules (opens new window)Extend Modules Plugin
emq_auth_clientid (opens new window)ClientId Auth Plugin
emq_auth_username (opens new window)Username/Password Auth Plugin
emq_auth_ldap (opens new window)LDAP Auth
emq_auth_http (opens new window)HTTP Auth/ACL Plugin
emq_auth_mysql (opens new window)MySQL Auth/ACL Plugin
emq_auth_pgsql (opens new window)PostgreSQL Auth/ACL Plugin
emq_auth_redis (opens new window)Redis Auth/ACL Plugin
emq_auth_mongo (opens new window)MongoDB Auth/ACL Plugin
emq_web_hook (opens new window)Web Hook Plugin
emq_lua_hook (opens new window)Lua Hook Plugin
emq_coap (opens new window)CoAP Protocol Plugin
emq_sn (opens new window)MQTT-SN Protocol Plugin
emq_stomp (opens new window)STOMP Protocol Plugin
emq_sockjs (opens new window)STOMP over SockJS Plugin
emq_recon (opens new window)Recon Plugin
emq_reloader (opens new window)Reloader Plugin
emq_plugin_template (opens new window)Template Plugin

# emq_plugin_template - Template Plugin

A plugin is just a normal Erlang application which has its own configuration file: 'etc/<PluginName>.conf|config'.

emq_plugin_template is a plugin template.

# Load, unload Plugin

Use 'bin/emqttd_ctl plugins' CLI to load, unload a plugin:

./bin/emqttd_ctl plugins load \<PluginName>

./bin/emqttd_ctl plugins unload \<PluginName>

./bin/emqttd_ctl plugins list

# emq_retainer - Retainer Plugin

Renamed the emq_mod_retainer to emq_retainer (opens new window) project in 2.1-beta release.

# Configure Retainer Plugin

etc/plugins/emq_retainer.conf:

## disc: disc_copies, ram: ram_copies
## Notice: retainer's storage_type on each node in a cluster must be the same!
retainer.storage_type = disc

## Max number of retained messages
retainer.max_message_num = 1000000

## Max Payload Size of retained message
retainer.max_payload_size = 64KB

## Expiry interval. Never expired if 0
## h - hour
## m - minute
## s - second
retainer.expiry_interval = 0

# emq_auth_clientid - ClientID Auth Plugin

Released in 2.0-rc.2: https://github.com/emqtt/emq_auth_clientid (opens new window)

# Configure ClientID Auth Plugin

etc/plugins/emq_auth_clientid.conf:

##auth.client.$N.clientid = clientid
##auth.client.$N.password = passwd

## Examples
##auth.client.1.clientid = id
##auth.client.1.password = passwd
##auth.client.2.clientid = dev:devid
##auth.client.2.password = passwd2
##auth.client.3.clientid = app:appid
##auth.client.3.password = passwd3

# Load ClientId Auth Plugin

./bin/emqttd_ctl plugins load emq_auth_clientid

# emq_auth_username - Username Auth Plugin

Released in 2.0-rc.2: https://github.com/emqtt/emq_auth_username (opens new window)

# Configure Username Auth Plugin

etc/plugins/emq_auth_username.conf:

##auth.user.$N.username = admin
##auth.user.$N.password = public

## Examples:
##auth.user.1.username = admin
##auth.user.1.password = public
##auth.user.2.username = feng@emqx.io
##auth.user.2.password = public

Add username/password by ./bin/emqttd_ctl users CLI:

$ ./bin/emqttd_ctl users add <Username> <Password>

# Load Username Auth Plugin

./bin/emqttd_ctl plugins load emq_auth_username

# emq_dashboard - Dashboard Plugin

The Web Dashboard for EMQ broker. The plugin will be loaded automatically when the broker started successfully.

Addresshttp://localhost:18083 (opens new window)
Default Useradmin
Default Passwordpublic

image

# Configure Dashboard Plugin

etc/plugins/emq_dashboard.conf:

## HTTP Listener
dashboard.listener.http = 18083
dashboard.listener.http.acceptors = 2
dashboard.listener.http.max_clients = 512

## HTTPS Listener
## dashboard.listener.https = 18084
## dashboard.listener.https.acceptors = 2
## dashboard.listener.https.max_clients = 512
## dashboard.listener.https.handshake_timeout = 15s
## dashboard.listener.https.certfile = etc/certs/cert.pem
## dashboard.listener.https.keyfile = etc/certs/key.pem
## dashboard.listener.https.cacertfile = etc/certs/cacert.pem
## dashboard.listener.https.verify = verify_peer
## dashboard.listener.https.fail_if_no_peer_cert = true

# emq_auth_ldap: LDAP Auth Plugin

LDAP Auth Plugin: https://github.com/emqtt/emq_auth_ldap (opens new window)

Tip

Released in 2.0-beta.1

# Configure LDAP Plugin

etc/plugins/emq_auth_ldap.conf:

auth.ldap.servers = 127.0.0.1

auth.ldap.port = 389

auth.ldap.timeout = 30

auth.ldap.user_dn = uid=%u,ou=People,dc=example,dc=com

auth.ldap.ssl = false

# Load LDAP Plugin

./bin/emqttd_ctl plugins load emq_auth_ldap

# emq_auth_http - HTTP Auth/ACL Plugin

MQTT Authentication/ACL with HTTP API: https://github.com/emqtt/emq_auth_http (opens new window)

Tip

Supported in 1.1 release

# Configure HTTP Auth/ACL Plugin

etc/plugins/emq_auth_http.conf:

## Variables: %u = username, %c = clientid, %a = ipaddress, %P = password, %t = topic

auth.http.auth_req = http://127.0.0.1:8080/mqtt/auth
auth.http.auth_req.method = post
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

auth.http.super_req = http://127.0.0.1:8080/mqtt/superuser
auth.http.super_req.method = post
auth.http.super_req.params = clientid=%c,username=%u

## 'access' parameter: sub = 1, pub = 2
auth.http.acl_req = http://127.0.0.1:8080/mqtt/acl
auth.http.acl_req.method = get
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

# HTTP Auth/ACL API

Return 200 if ok

Return 4xx if unauthorized

# Load HTTP Auth/ACL Plugin

./bin/emqttd_ctl plugins load emq_auth_http

# emq_auth_mysql - MySQL Auth/ACL Plugin

MQTT Authentication, ACL with MySQL database.

# MQTT User Table

CREATE TABLE `mqtt_user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `salt` varchar(20) DEFAULT NULL,
  `is_superuser` tinyint(1) DEFAULT 0,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mqtt_username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

# MQTT ACL Table

CREATE TABLE `mqtt_acl` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `allow` int(1) DEFAULT NULL COMMENT '0: deny, 1: allow',
  `ipaddr` varchar(60) DEFAULT NULL COMMENT 'IpAddress',
  `username` varchar(100) DEFAULT NULL COMMENT 'Username',
  `clientid` varchar(100) DEFAULT NULL COMMENT 'ClientId',
  `access` int(2) NOT NULL COMMENT '1: subscribe, 2: publish, 3: pubsub',
  `topic` varchar(100) NOT NULL DEFAULT '' COMMENT 'Topic Filter',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `mqtt_acl` (`id`, `allow`, `ipaddr`, `username`, `clientid`, `access`, `topic`)
VALUES
    (1,1,NULL,'$all',NULL,2,'#'),
    (2,0,NULL,'$all',NULL,1,'$SYS/#'),
    (3,0,NULL,'$all',NULL,1,'eq #'),
    (5,1,'127.0.0.1',NULL,NULL,2,'$SYS/#'),
    (6,1,'127.0.0.1',NULL,NULL,2,'#'),
    (7,1,NULL,'dashboard',NULL,1,'$SYS/#');

# Configure MySQL Auth/ACL Plugin

etc/plugins/emq_auth_mysql.conf:

## Mysql Server
auth.mysql.server = 127.0.0.1:3306

## Mysql Pool Size
auth.mysql.pool = 8

## Mysql Username
## auth.mysql.username =

## Mysql Password
## auth.mysql.password =

## Mysql Database
auth.mysql.database = mqtt

## Variables: %u = username, %c = clientid

## Authentication Query: select password only
auth.mysql.auth_query = select password from mqtt_user where username = '%u' limit 1

## Password hash: plain, md5, sha, sha256, pbkdf2
auth.mysql.password_hash = sha256

## %% Superuser Query
auth.mysql.super_query = select is_superuser from mqtt_user where username = '%u' limit 1

## ACL Query Command
auth.mysql.acl_query = select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'

# Load MySQL Auth/ACL plugin

./bin/emqttd_ctl plugins load emq_auth_mysql

# emq_auth_pgsql - PostgreSQL Auth/ACL Plugin

MQTT Authentication/ACL with PostgreSQL Database.

# Postgre MQTT User Table

CREATE TABLE mqtt_user (
  id SERIAL primary key,
  is_superuser boolean,
  username character varying(100),
  password character varying(100),
  salt character varying(40)
);

# Postgre MQTT ACL Table

CREATE TABLE mqtt_acl (
  id SERIAL primary key,
  allow integer,
  ipaddr character varying(60),
  username character varying(100),
  clientid character varying(100),
  access  integer,
  topic character varying(100)
);

INSERT INTO mqtt_acl (id, allow, ipaddr, username, clientid, access, topic)
VALUES
    (1,1,NULL,'$all',NULL,2,'#'),
    (2,0,NULL,'$all',NULL,1,'$SYS/#'),
    (3,0,NULL,'$all',NULL,1,'eq #'),
    (5,1,'127.0.0.1',NULL,NULL,2,'$SYS/#'),
    (6,1,'127.0.0.1',NULL,NULL,2,'#'),
    (7,1,NULL,'dashboard',NULL,1,'$SYS/#');

# Configure Postgre Auth/ACL Plugin

Plugin Config: etc/plugins/emq_auth_pgsql.conf.

Configure host, username, password and database of PostgreSQL:

## Postgre Server
auth.pgsql.server = 127.0.0.1:5432

auth.pgsql.pool = 8

auth.pgsql.username = root

#auth.pgsql.password =

auth.pgsql.database = mqtt

auth.pgsql.encoding = utf8

auth.pgsql.ssl = false

## Variables: %u = username, %c = clientid, %a = ipaddress

## Authentication Query: select password only
auth.pgsql.auth_query = select password from mqtt_user where username = '%u' limit 1

## Password hash: plain, md5, sha, sha256, pbkdf2
auth.pgsql.password_hash = sha256

## sha256 with salt prefix
## auth.pgsql.password_hash = salt sha256

## sha256 with salt suffix
## auth.pgsql.password_hash = sha256 salt

## Superuser Query
auth.pgsql.super_query = select is_superuser from mqtt_user where username = '%u' limit 1

## ACL Query. Comment this query, the acl will be disabled.
auth.pgsql.acl_query = select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'

# Load Postgre Auth/ACL Plugin

./bin/emqttd_ctl plugins load emq_auth_pgsql

# emq_auth_redis - Redis Auth/ACL Plugin

MQTT Authentication, ACL with Redis: https://github.com/emqtt/emq_auth_redis (opens new window)

# Configure Redis Auth/ACL Plugin

etc/plugins/emq_auth_redis.conf:

## Redis Server
auth.redis.server = 127.0.0.1:6379

## Redis Pool Size
auth.redis.pool = 8

## Redis Database
auth.redis.database = 0

## Redis Password
## auth.redis.password =

## Variables: %u = username, %c = clientid

## Authentication Query Command
auth.redis.auth_cmd = HGET mqtt_user:%u password

## Password hash: plain, md5, sha, sha256, pbkdf2
auth.redis.password_hash = sha256

## Superuser Query Command
auth.redis.super_cmd = HGET mqtt_user:%u is_superuser

## ACL Query Command
auth.redis.acl_cmd = HGETALL mqtt_acl:%u

# Redis User Hash

Set a 'user' hash with 'password' field, for example:

HSET mqtt_user:<username> is_superuser 1
HSET mqtt_user:<username> password "passwd"

# Redis ACL Rule Hash

The plugin uses a redis Hash to store ACL rules:

HSET mqtt_acl:<username> topic1 1
HSET mqtt_acl:<username> topic2 2
HSET mqtt_acl:<username> topic3 3

Tip

1: subscribe, 2: publish, 3: pubsub

# Redis Subscription Hash

The plugin can store static subscriptions in a redis Hash:

HSET mqtt_subs:<username> topic1 0
HSET mqtt_subs:<username> topic2 1
HSET mqtt_subs:<username> topic3 2

# Load Redis Auth/ACL Plugin

./bin/emqttd_ctl plugins load emq_auth_redis

# emq_auth_mongo - MongoDB Auth/ACL Plugin

MQTT Authentication/ACL with MongoDB: https://github.com/emqtt/emq_auth_mongo (opens new window)

# Configure MongoDB Auth/ACL Plugin

etc/plugins/emq_auth_mongo.conf:

## Mongo Server
auth.mongo.server = 127.0.0.1:27017

## Mongo Pool Size
auth.mongo.pool = 8

## Mongo User
## auth.mongo.user =

## Mongo Password
## auth.mongo.password =

## Mongo Database
auth.mongo.database = mqtt

## auth_query
auth.mongo.auth_query.collection = mqtt_user

auth.mongo.auth_query.password_field = password

auth.mongo.auth_query.password_hash = sha256

auth.mongo.auth_query.selector = username=%u

## super_query
auth.mongo.super_query.collection = mqtt_user

auth.mongo.super_query.super_field = is_superuser

auth.mongo.super_query.selector = username=%u

## acl_query
auth.mongo.acl_query.collection = mqtt_user

auth.mongo.acl_query.selector = username=%u

# MongoDB Database

use mqtt
db.createCollection("mqtt_user")
db.createCollection("mqtt_acl")
db.mqtt_user.ensureIndex({"username":1})

# MongoDB User Collection

{
    username: "user",
    password: "password hash",
    is_superuser: boolean (true, false),
    created: "datetime"
}

For example:

db.mqtt_user.insert({username: "test", password: "password hash", is_superuser: false})
db.mqtt_user:insert({username: "root", is_superuser: true})

# MongoDB ACL Collection

{
    username: "username",
    clientid: "clientid",
    publish: ["topic1", "topic2", ...],
    subscribe: ["subtop1", "subtop2", ...],
    pubsub: ["topic/#", "topic1", ...]
}

For example:

db.mqtt_acl.insert({username: "test", publish: ["t/1", "t/2"], subscribe: ["user/%u", "client/%c"]})
db.mqtt_acl.insert({username: "admin", pubsub: ["#"]})

# Load MongoDB Auth/ACL Plugin

./bin/emqttd_ctl plugins load emq_auth_mongo

# emq_modules - Modules Plugin

Merged the emq_mod_presence (opens new window) , emq_mod_subscription (opens new window) , emq_mod_rewrite (opens new window) into one emq_modules (opens new window) project.

# Configure Modules Plugin

##--------------------------------------------------------------------
## Presence Module
##--------------------------------------------------------------------

## Enable Presence, Values: on | off
module.presence = on

module.presence.qos = 1

##--------------------------------------------------------------------
## Subscription Module
##--------------------------------------------------------------------

## Enable Subscription, Values: on | off
module.subscription = on

## Subscribe the Topics automatically when client connected
module.subscription.1.topic = $client/%c
## Qos of the subscription: 0 | 1 | 2
module.subscription.1.qos = 1

## module.subscription.2.topic = $user/%u
## module.subscription.2.qos = 1

##--------------------------------------------------------------------
## Rewrite Module
##--------------------------------------------------------------------

## Enable Rewrite, Values: on | off
module.rewrite = off

## {rewrite, Topic, Re, Dest}
## module.rewrite.rule.1 = x/# ^x/y/(.+)$ z/y/$1
## module.rewrite.rule.2 = y/+/z/# ^y/(.+)/z/(.+)$ y/z/$2

# emq_mod_presence - Presence Module

Presence module will publish presence message to $SYS topic when a client connected or disconnected:

Tip

This project has been deprecated in 2.1-beta release.

# Configure Presence Module

etc/plugins/emq_mod_presence.conf:

## Enable presence module
## Values: on | off
module.presence = on

module.presence.qos = 0

# Load Presence Module

Tip

This module will be loaded by default.

./bin/emqttd_ctl plugins load emq_mod_presence

# emq_mod_retainer - Retainer Module

Retainer module is responsible for storing MQTT retained messages.

Tip

This project has been deprecated in 2.1-beta release.

# Configure Retainer Module

etc/plugins/emq_mod_retainer.conf:

## disc: disc_copies, ram: ram_copies
module.retainer.storage_type = ram

## Max number of retained messages
module.retainer.max_message_num = 100000

## Max Payload Size of retained message
module.retainer.max_payload_size = 64KB

## Expired after seconds, never expired if 0
module.retainer.expired_after = 0

# Load Retainer Module

Tip

This module will be loaded by default.

./bin/emqttd_ctl plugins load emq_mod_retainer

# emq_mod_subscription - Subscription Module

Subscription module forces the client to subscribe some topics when connected to the broker:

Tip

This project has been deprecated in 2.1-beta release.

# Configure Subscription Module

etc/plugins/emq_mod_subscription.conf:

## Subscribe the Topics automatically when client connected
module.subscription.1.topic = $client/%c
## Qos of the subscription: 0 | 1 | 2
module.subscription.1.qos = 1

##module.subscription.2.topic = $user/%u
##module.subscription.2.qos = 1

# Load Subscription Module

Tip

This module will be loaded by default.

./bin/emqttd_ctl plugins load emq_mod_subscription

# emq_mod_rewrite - Topic Rewrite Module

Released in 2.0-rc.2: https://github.com/emqtt/emq_mod_rewrite (opens new window)

Tip

This project has been deprecated in 2.1-beta release.

# Configure Rewrite Module

etc/plugins/emq_mod_rewrite.config:

[
  {emq_mod_rewrite, [
    {rules, [
      %% {rewrite, Topic, Re, Dest}

      %% Example: x/y/ -> z/y/
      %% {rewrite, "x/#", "^x/y/(.+)$", "z/y/$1"},

      %% {rewrite, "y/+/z/#", "^y/(.+)/z/(.+)$", "y/z/$2"}
    ]}
  ]}
].

# Load Rewrite Module

./bin/emqttd_ctl plugins load emq_mod_rewrite

# emq_coap: CoAP Protocol Plugin

CoAP Protocol Plugin: https://github.com/emqtt/emqttd_coap (opens new window)

# Configure CoAP Plugin

coap.server = 5683

coap.prefix.mqtt = mqtt

coap.handler.mqtt = emq_coap_gateway

# Load CoAP Protocol Plugin

./bin/emqttd_ctl plugins load emq_coap

# libcoap Client

yum install libcoap

% coap client publish message
coap-client -m post -e "qos=0&retain=0&message=payload&topic=hello" coap://localhost/mqtt

# emq_sn: MQTT-SN Protocol

MQTT-SN Protocol/Gateway Plugin.

# Configure MQTT-SN Plugin

Tip

UDP Port for MQTT-SN: 1884

etc/plugins/emq_sn.conf:

mqtt.sn.port = 1884

# Load MQTT-SN Plugin

./bin/emqttd_ctl plugins load emq_sn

# emq_stomp - STOMP Protocol

Support STOMP 1.0/1.1/1.2 clients to connect to emqttd broker and communicate with MQTT Clients.

# Configure Stomp Plugin

etc/plugins/emq_stomp.conf:

Tip

Default Port for STOMP Protocol: 61613

stomp.default_user.login = guest

stomp.default_user.passcode = guest

stomp.allow_anonymous = true

stomp.frame.max_headers = 10

stomp.frame.max_header_length = 1024

stomp.frame.max_body_length = 8192

stomp.listener = 61613

stomp.listener.acceptors = 4

stomp.listener.max_clients = 512

# Load Stomp Plugin

./bin/emqttd_ctl plugins load emq_stomp

# emq_sockjs - STOMP/SockJS Plugin

emq_sockjs plugin enables web browser to connect to emqttd broker and communicate with MQTT clients.

Warning

The plugin is deprecated in 2.0

# Configure SockJS Plugin

Tip

Default TCP Port: 61616

[
  {emq_sockjs, [

    {sockjs, []},

    {cowboy_listener, {stomp_sockjs, 61616, 4}},

    %% TODO: unused...
    {stomp, [
      {frame, [
        {max_headers,       10},
        {max_header_length, 1024},
        {max_body_length,   8192}
      ]}
    ]}
  ]}
].

# Load SockJS Plugin

./bin/emqttd_ctl plugins load emqttd_sockjs

# SockJS Demo Page

http://localhost:61616/index.html (opens new window)

# emq_recon - Recon Plugin

The plugin loads recon (opens new window) library on a running EMQ broker. Recon libray helps debug and optimize an Erlang application.

# Load Recon Plugin

./bin/emqttd_ctl plugins load emq_recon

# Recon CLI

./bin/emqttd_ctl recon

recon memory                 #recon_alloc:memory/2
recon allocated              #recon_alloc:memory(allocated_types, current|max)
recon bin_leak               #recon:bin_leak(100)
recon node_stats             #recon:node_stats(10, 1000)
recon remote_load Mod        #recon:remote_load(Mod)

# emq_reloader - Reloader Plugin

Erlang Module Reloader for Development

Tip

Don't load the plugin in production!

# Load Reloader Plugin

./bin/emqttd_ctl plugins load emq_reloader

# reload CLI

./bin/emqttd_ctl reload

reload \<Module>             # Reload a Module

# Plugin Development Guide

# Create a Plugin Project

Clone emq_plugin_template source from github.com:

git clone https://github.com/emqtt/emq_plugin_template.git

Create a plugin project with erlang.mk and depends on 'emqttd' application, the 'Makefile':

PROJECT = emq_plugin_abc
PROJECT_DESCRIPTION = emqttd abc plugin
PROJECT_VERSION = 1.0

BUILD_DEPS = emqttd
dep_emqttd = git https://github.com/emqtt/emqttd master

COVER = true

include erlang.mk

Template Plugin: https://github.com/emqtt/emq_plugin_template (opens new window)

# Register Auth/ACL Modules

emq_auth_demo.erl - demo authentication module:

-module(emq_auth_demo).

-behaviour(emqttd_auth_mod).

-include_lib("emqttd/include/emqttd.hrl").

-export([init/1, check/3, description/0]).

init(Opts) -> {ok, Opts}.

check(#mqtt_client{client_id = ClientId, username = Username}, Password, _Opts) ->
    io:format("Auth Demo: clientId=~p, username=~p, password=~p~n",
              [ClientId, Username, Password]),
    ok.

description() -> "Demo Auth Module".

emq_acl_demo.erl - demo ACL module:

-module(emq_acl_demo).

-include_lib("emqttd/include/emqttd.hrl").

%% ACL callbacks
-export([init/1, check_acl/2, reload_acl/1, description/0]).

init(Opts) ->
    {ok, Opts}.

check_acl({Client, PubSub, Topic}, Opts) ->
    io:format("ACL Demo: ~p ~p ~p~n", [Client, PubSub, Topic]),
    allow.

reload_acl(_Opts) ->
    ok.

description() -> "ACL Module Demo".

emq_plugin_template_app.erl - Register the auth/ACL modules:

ok = emqttd_access_control:register_mod(auth, emq_auth_demo, []),
ok = emqttd_access_control:register_mod(acl, emq_acl_demo, []),

# Register Callbacks for Hooks

The plugin could register callbacks for hooks. The hooks will be run by the broker when a client connected/disconnected, a topic subscribed/unsubscribed or a message published/delivered:

NameDescription
client.connectedRun when a client connected to the broker successfully
client.subscribeRun before a client subscribes topics
client.unsubscribeRun when a client unsubscribes topics
session.subscribedRun after a client subscribed a topic
session.unsubscribedRun after a client unsubscribed a topic
message.publishRun when a message is published
message.deliveredRun when a message is delivered
message.ackedRun when a message(qos1/2) is acked
client.disconnectedRun when a client is disconnnected

emq_plugin_template.erl for example:

%% Called when the plugin application start
load(Env) ->
    emqttd:hook('client.connected', fun ?MODULE:on_client_connected/3, [Env]),
    emqttd:hook('client.disconnected', fun ?MODULE:on_client_disconnected/3, [Env]),
    emqttd:hook('client.subscribe', fun ?MODULE:on_client_subscribe/4, [Env]),
    emqttd:hook('session.subscribed', fun ?MODULE:on_session_subscribed/4, [Env]),
    emqttd:hook('client.unsubscribe', fun ?MODULE:on_client_unsubscribe/4, [Env]),
    emqttd:hook('session.unsubscribed', fun ?MODULE:on_session_unsubscribed/4, [Env]),
    emqttd:hook('message.publish', fun ?MODULE:on_message_publish/2, [Env]),
    emqttd:hook('message.delivered', fun ?MODULE:on_message_delivered/4, [Env]),
    emqttd:hook('message.acked', fun ?MODULE:on_message_acked/4, [Env]).

# Register CLI Modules

emq_cli_demo.erl:

-module(emqttd_cli_demo).

-include_lib("emqttd/include/emqttd_cli.hrl").

-export([cmd/1]).

cmd(["arg1", "arg2"]) ->
    ?PRINT_MSG("ok");

cmd(_) ->
    ?USAGE([{"cmd arg1 arg2", "cmd demo"}]).

emqplugin_template_app.erl - register the CLI module to _EMQ broker:

emqttd_ctl:register_cmd(cmd, {emq_cli_demo, cmd}, []).

There will be a new CLI after the plugin loaded:

./bin/emqttd_ctl cmd arg1 arg2

# Create Configuration File

Create etc/${pluginname}.conf|config file for the plugin. The _EMQ broker supports two type of config syntax:

  1. ${plugin_name}.config with erlang syntax:

    [
     {plugin_name, [
        {key, value}
     ]}
    ].
    
  2. ${plugin_name}.conf with a general k = v syntax:

    plugin_name.key = value
    

# Build and Release the Plugin

  1. clone emq-relx project:

    git clone https://github.com/emqtt/emq-relx.git
    
  2. Add DEPS in Makefile:

    DEPS += plugin_name
    dep_plugin_name = git url_of_plugin
    
  3. Add the plugin in relx.config:

    {plugin_name, load},