EMQ 2.0 Documentation
This commit is contained in:
parent
ff8d074576
commit
e2415a598b
|
@ -11,11 +11,119 @@ Changes
|
||||||
Version 2.0 (West of West Lake)
|
Version 2.0 (West of West Lake)
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
*Release Date: 2016-08-29*
|
*Release Date: 2016-08-30*
|
||||||
|
|
||||||
Improve the design of PubSub and Router:
|
*Release Name: West of West Lake*
|
||||||
|
|
||||||
.. images:: _static/images/publish.png
|
.. NOTE:: Dont' upgrade 1.x production deployment to 2.0-beta1 release.
|
||||||
|
|
||||||
|
EMQ - Shortened Project Name
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Adopt a shortened projectname: EMQ(Erlang/Enterprise/Elastic MQTT Broker),E means Erlang/OTP, Enterprise and Elastic.
|
||||||
|
|
||||||
|
Improve the Release Management
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
In order to iterate the project fast, we will adopt a new release management strategy since 2.0. There will be two or three 'Preview Release' named beta1, beta2 or beta3, and then one or two 'Release Candidate' named rc1, rc2 before a Major version is production ready.
|
||||||
|
|
||||||
|
Seperate Rel from Application
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
We split the emqttd 1.x project into two projects since 2.0-beta1 release to resolve the plugins' dependency issue.
|
||||||
|
|
||||||
|
A new project named `emqttd-relx`_ is created and responsible for buiding the emqttd application and the plugins::
|
||||||
|
|
||||||
|
git clone https://github.com/emqtt/emqttd-relx.git
|
||||||
|
|
||||||
|
cd emqttd-relx && make
|
||||||
|
|
||||||
|
cd _rel/emqttd && ./bin/emqttd console
|
||||||
|
|
||||||
|
erlang.mk and relx
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The rebar which is used in 1.x release is replaced by `erlang.mk`_ and `relx`_ tools since 2.0-beta1 release.
|
||||||
|
|
||||||
|
You can check the 'Makefile' and 'relx.config' in the release project of the borker: `emqttd-relx`_ .
|
||||||
|
|
||||||
|
Improve Git Branches Management
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
| stable | 1.x Stable Branch |
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
| master | 2.x Master Branch |
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
| emq10 | 1.x Developement Branch |
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
| emq20 | 2.x Development Branch |
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
| emq30 | 3.x Development Branch |
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
| issue#{id} | BugFix Branch |
|
||||||
|
+------------+-------------------------------------------+
|
||||||
|
|
||||||
|
New Config Syntax
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Since 2.0-beta1 release the configuration file of the broker and plugins adopt a new syntax like rebar.config or relx.config:
|
||||||
|
|
||||||
|
etc/emqttd.conf for example::
|
||||||
|
|
||||||
|
%% Max ClientId Length Allowed.
|
||||||
|
{mqtt_max_clientid_len, 512}.
|
||||||
|
|
||||||
|
%% Max Packet Size Allowed, 64K by default.
|
||||||
|
{mqtt_max_packet_size, 65536}.
|
||||||
|
|
||||||
|
%% Client Idle Timeout.
|
||||||
|
{mqtt_client_idle_timeout, 30}. % Second
|
||||||
|
|
||||||
|
MQTT-SN Protocol Plugin
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The MQTT-SN Protocol Plugin `emqttd_sn`_ has been ready in 2.0-beta1 release. The default UDP port of MQTT-SN is 1884.
|
||||||
|
|
||||||
|
Load the plugin::
|
||||||
|
|
||||||
|
./bin/emqttd_ctl plugins load emqttd_sn
|
||||||
|
|
||||||
|
Improve Design of PubSub and Router
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. image:: _static/images/publish.png
|
||||||
|
|
||||||
|
Improve Plugin Management
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
The plugin of EMQ 2.0 broker is a normal erlang application which depends on and extends 'emqttd'. User can create a standalone plugin application project, and add it to `emqttd-relx`_ Makefiel as a dependency.
|
||||||
|
|
||||||
|
All the plugins' config files will be copied to emqttd/etc/plugins/ folder when making emqttd brinary packages in `emqttd-relx`_ project::
|
||||||
|
|
||||||
|
▾ emqttd/
|
||||||
|
▾ etc/
|
||||||
|
▸ modules/
|
||||||
|
▾ plugins/
|
||||||
|
emqtt_coap.conf
|
||||||
|
emqttd.conf
|
||||||
|
emqttd_auth_http.conf
|
||||||
|
emqttd_auth_mongo.conf
|
||||||
|
emqttd_auth_mysql.conf
|
||||||
|
emqttd_auth_pgsql.conf
|
||||||
|
emqttd_auth_redis.conf
|
||||||
|
emqttd_coap.conf
|
||||||
|
emqttd_dashboard.conf
|
||||||
|
emqttd_plugin_template.conf
|
||||||
|
emqttd_recon.conf
|
||||||
|
emqttd_reloader.conf
|
||||||
|
emqttd_sn.conf
|
||||||
|
emqttd_stomp.conf
|
||||||
|
|
||||||
|
EMQ 2.0 Documentation
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
http://emqtt.io/docs/v2/index.html or http://docs.emqtt.com/emq20/
|
||||||
|
|
||||||
.. _release_1.1.3:
|
.. _release_1.1.3:
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ The Firewall
|
||||||
|
|
||||||
If there is a firewall between clustered nodes, the cluster requires to open 4369 port used by epmd daemon, and a port segment for nodes' communication.
|
If there is a firewall between clustered nodes, the cluster requires to open 4369 port used by epmd daemon, and a port segment for nodes' communication.
|
||||||
|
|
||||||
Configure the port segment in etc/emqttd.config, for example:
|
Configure the port segment in releases/2.0/sys.config, for example:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ Show running status of the broker::
|
||||||
$ ./bin/emqttd_ctl status
|
$ ./bin/emqttd_ctl status
|
||||||
|
|
||||||
Node 'emqttd@127.0.0.1' is started
|
Node 'emqttd@127.0.0.1' is started
|
||||||
emqttd 1.1 is running
|
emqttd 2.0 is running
|
||||||
|
|
||||||
.. _command_broker::
|
.. _command_broker::
|
||||||
|
|
||||||
|
@ -382,10 +382,6 @@ Query the subscription table of the broker:
|
||||||
+--------------------------------------------+--------------------------------------+
|
+--------------------------------------------+--------------------------------------+
|
||||||
| subscriptions show <ClientId> | Show a subscription |
|
| subscriptions show <ClientId> | Show a subscription |
|
||||||
+--------------------------------------------+--------------------------------------+
|
+--------------------------------------------+--------------------------------------+
|
||||||
| subscriptions add <ClientId> <Topic> <Qos> | Add a static subscription manually |
|
|
||||||
+--------------------------------------------+--------------------------------------+
|
|
||||||
| subscriptions del <ClientId> <Topic> | Remove a static subscription manually|
|
|
||||||
+--------------------------------------------+--------------------------------------+
|
|
||||||
|
|
||||||
subscriptions list
|
subscriptions list
|
||||||
------------------
|
------------------
|
||||||
|
@ -415,22 +411,6 @@ Show the subscriptions of a MQTT client::
|
||||||
|
|
||||||
clientid: [{<<"x">>,1},{<<"topic2">>,1},{<<"topic3">>,1}]
|
clientid: [{<<"x">>,1},{<<"topic2">>,1},{<<"topic3">>,1}]
|
||||||
|
|
||||||
subscriptions add <ClientId> <Topic> <QoS>
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
Add a static subscription manually::
|
|
||||||
|
|
||||||
$ ./bin/emqttd_ctl subscriptions add clientid new_topic 1
|
|
||||||
ok
|
|
||||||
|
|
||||||
subscriptions del <ClientId> <Topic>
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
Remove a static subscription manually::
|
|
||||||
|
|
||||||
$ ./bin/emqttd_ctl subscriptions del clientid new_topic
|
|
||||||
ok
|
|
||||||
|
|
||||||
.. _command_plugins::
|
.. _command_plugins::
|
||||||
|
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -48,7 +48,7 @@ source_suffix = '.rst'
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'Erlang MQTT Broker'
|
project = u'EMQ 2.0 - Erlang MQTT Broker'
|
||||||
copyright = u'2016, Feng Lee'
|
copyright = u'2016, Feng Lee'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
@ -56,9 +56,9 @@ copyright = u'2016, Feng Lee'
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.0'
|
version = '2.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '1.0'
|
release = '2.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,17 @@ The emqttd broker 1.0 is more like a network Switch or Router, not a traditional
|
||||||
|
|
||||||
.. image:: _static/images/concept.png
|
.. image:: _static/images/concept.png
|
||||||
|
|
||||||
|
The EMQ 2.0 seperated the Message Flow Plane and Monitor/Control Plane, the Architecture is something like::
|
||||||
|
|
||||||
|
Control Plane
|
||||||
|
--------------------
|
||||||
|
| |
|
||||||
|
FrontEnd -> | Flow Plane | -> BackEnd
|
||||||
|
| |
|
||||||
|
Session Router
|
||||||
|
---------------------
|
||||||
|
Monitor Plane
|
||||||
|
|
||||||
Design Philosophy
|
Design Philosophy
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
@ -478,3 +489,32 @@ http://github.com/emqtt/emqttd_plugin_template
|
||||||
.. _eSockd: https://github.com/emqtt/esockd
|
.. _eSockd: https://github.com/emqtt/esockd
|
||||||
.. _Chain-of-responsibility_pattern: https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
|
.. _Chain-of-responsibility_pattern: https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
|
||||||
.. _emqttd_plugin_template: https://github.com/emqtt/emqttd_plugin_template/blob/master/src/emqttd_plugin_template.erl
|
.. _emqttd_plugin_template: https://github.com/emqtt/emqttd_plugin_template/blob/master/src/emqttd_plugin_template.erl
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Mnesia/ETS Tables
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| Table | Type | Description |
|
||||||
|
+====================+========+========================================+
|
||||||
|
| mqtt_trie | mnesia | Trie Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_trie_node | mnesia | Trie Node Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_route | mnesia | Global Route Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_local_route | mnesia | Local Route Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_pubsub | ets | PubSub Tab |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_subscriber | ets | Subscriber Tab |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_subscription | ets | Subscription Tab |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_session | mnesia | Global Session Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_local_session | ets | Local Session Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
| mqtt_client | ets | Client Table |
|
||||||
|
+--------------------+--------+----------------------------------------+
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ Features
|
||||||
* MQTT Over WebSocket(SSL)
|
* MQTT Over WebSocket(SSL)
|
||||||
* HTTP Publish API
|
* HTTP Publish API
|
||||||
* STOMP protocol
|
* STOMP protocol
|
||||||
|
* MQTT-SN Protocol
|
||||||
|
* CoAP Protocol
|
||||||
* STOMP over SockJS
|
* STOMP over SockJS
|
||||||
* $SYS/# Topics
|
* $SYS/# Topics
|
||||||
* ClientID Authentication
|
* ClientID Authentication
|
||||||
|
@ -63,7 +65,7 @@ Installing on Mac, for example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
unzip emqttd-macosx-1.1-beta-20160601.zip && cd emqttd
|
unzip emqttd-macosx-2.0-beta1-20160830.zip && cd emqttd
|
||||||
|
|
||||||
# Start emqttd
|
# Start emqttd
|
||||||
./bin/emqttd start
|
./bin/emqttd start
|
||||||
|
@ -119,8 +121,6 @@ Modules
|
||||||
+-------------------------+--------------------------------------------+
|
+-------------------------+--------------------------------------------+
|
||||||
| emqttd_auth_username | Authentication with Username and Password |
|
| emqttd_auth_username | Authentication with Username and Password |
|
||||||
+-------------------------+--------------------------------------------+
|
+-------------------------+--------------------------------------------+
|
||||||
| emqttd_auth_ldap | Authentication with LDAP |
|
|
||||||
+-------------------------+--------------------------------------------+
|
|
||||||
| emqttd_mod_presence | Publish presence message to $SYS topics |
|
| emqttd_mod_presence | Publish presence message to $SYS topics |
|
||||||
| | when client connected or disconnected |
|
| | when client connected or disconnected |
|
||||||
+-------------------------+--------------------------------------------+
|
+-------------------------+--------------------------------------------+
|
||||||
|
@ -136,22 +136,16 @@ Enable 'emqttd_auth_username' module:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
{access, [
|
|
||||||
%% Authetication. Anonymous Default
|
|
||||||
{auth, [
|
|
||||||
%% Authentication with username, password
|
%% Authentication with username, password
|
||||||
{username, []},
|
{auth, username, [{passwd, "etc/modules/passwd.conf"}]}.
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
Enable 'emqttd_mod_presence' module:
|
Enable 'emqttd_mod_presence' module:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
{modules, [
|
%% Client presence management module. Publish presence messages when
|
||||||
%% Client presence management module.
|
%% client connected or disconnected.
|
||||||
%% Publish messages when client connected or disconnected
|
{module, presence, [{qos, 0}]}.
|
||||||
{presence, [{qos, 0}]}
|
|
||||||
|
|
||||||
Plugins
|
Plugins
|
||||||
-------
|
-------
|
||||||
|
@ -163,16 +157,20 @@ A plugin is an Erlang application to extend the emqttd broker.
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_dashboard`_ | Web Dashboard |
|
| `emqttd_dashboard`_ | Web Dashboard |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
|
| `emqttd_auth_ldap`_ | LDAP Auth Plugin |
|
||||||
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_auth_http`_ | Authentication/ACL with HTTP API |
|
| `emqttd_auth_http`_ | Authentication/ACL with HTTP API |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_plugin_mysql`_ | Authentication with MySQL |
|
| `emqttd_auth_mysql` _ | Authentication with MySQL |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_plugin_pgsql`_ | Authentication with PostgreSQL |
|
| `emqttd_auth_pgsql`_ | Authentication with PostgreSQL |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_plugin_redis`_ | Authentication with Redis |
|
| `emqttd_auth_redis`_ | Authentication with Redis |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_plugin_mongo`_ | Authentication with MongoDB |
|
| `emqttd_plugin_mongo`_ | Authentication with MongoDB |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
|
| `emqttd_sn`_ | MQTT-SN Protocol Plugin |
|
||||||
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_stomp`_ | STOMP Protocol Plugin |
|
| `emqttd_stomp`_ | STOMP Protocol Plugin |
|
||||||
+----------------------------+-----------------------------------+
|
+----------------------------+-----------------------------------+
|
||||||
| `emqttd_sockjs`_ | SockJS(Stomp) Plugin |
|
| `emqttd_sockjs`_ | SockJS(Stomp) Plugin |
|
||||||
|
@ -182,9 +180,9 @@ A plugin is an Erlang application to extend the emqttd broker.
|
||||||
|
|
||||||
A plugin could be enabled by 'bin/emqttd_ctl plugins load' command.
|
A plugin could be enabled by 'bin/emqttd_ctl plugins load' command.
|
||||||
|
|
||||||
For example, enable 'emqttd_plugin_pgsql' plugin::
|
For example, enable 'emqttd_auth_pgsql' plugin::
|
||||||
|
|
||||||
./bin/emqttd_ctl plugins load emqttd_plugin_pgsql
|
./bin/emqttd_ctl plugins load emqttd_auth_pgsql
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
One Million Connections
|
One Million Connections
|
||||||
|
@ -238,11 +236,11 @@ emqttd/etc/vm.args::
|
||||||
emqttd broker
|
emqttd broker
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
emqttd/etc/emqttd.config:
|
emqttd/etc/emqttd.conf:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
{mqtt, 1883, [
|
{listener, mqtt, 1883, [
|
||||||
%% Size of acceptor pool
|
%% Size of acceptor pool
|
||||||
{acceptors, 64},
|
{acceptors, 64},
|
||||||
|
|
||||||
|
@ -258,6 +256,7 @@ emqttd/etc/emqttd.config:
|
||||||
%% {rate_limit, "100,10"} %% 100K burst, 10K rate
|
%% {rate_limit, "100,10"} %% 100K burst, 10K rate
|
||||||
]},
|
]},
|
||||||
...
|
...
|
||||||
|
]}.
|
||||||
|
|
||||||
Test Client
|
Test Client
|
||||||
-----------
|
-----------
|
||||||
|
@ -291,11 +290,15 @@ GitHub: https://github.com/emqtt
|
||||||
|
|
||||||
.. _emqttd_plugin_template: https://github.com/emqtt/emqttd_plugin_template
|
.. _emqttd_plugin_template: https://github.com/emqtt/emqttd_plugin_template
|
||||||
.. _emqttd_dashboard: https://github.com/emqtt/emqttd_dashboard
|
.. _emqttd_dashboard: https://github.com/emqtt/emqttd_dashboard
|
||||||
|
.. _emqttd_auth_ldap: https://github.com/emqtt/emqttd_auth_ldap
|
||||||
.. _emqttd_auth_http: https://github.com/emqtt/emqttd_auth_http
|
.. _emqttd_auth_http: https://github.com/emqtt/emqttd_auth_http
|
||||||
.. _emqttd_plugin_mysql: https://github.com/emqtt/emqttd_plugin_mysql
|
.. _emqttd_auth_mysql: https://github.com/emqtt/emqttd_plugin_mysql
|
||||||
.. _emqttd_plugin_pgsql: https://github.com/emqtt/emqttd_plugin_pgsql
|
.. _emqttd_auth_pgsql: https://github.com/emqtt/emqttd_plugin_pgsql
|
||||||
.. _emqttd_plugin_redis: https://github.com/emqtt/emqttd_plugin_redis
|
.. _emqttd_auth_redis: https://github.com/emqtt/emqttd_plugin_redis
|
||||||
.. _emqttd_plugin_mongo: https://github.com/emqtt/emqttd_plugin_mongo
|
.. _emqttd_auth_mongo: https://github.com/emqtt/emqttd_plugin_mongo
|
||||||
|
.. _emqttd_reloader: https://github.com/emqtt/emqttd_reloader
|
||||||
.. _emqttd_stomp: https://github.com/emqtt/emqttd_stomp
|
.. _emqttd_stomp: https://github.com/emqtt/emqttd_stomp
|
||||||
.. _emqttd_sockjs: https://github.com/emqtt/emqttd_sockjs
|
.. _emqttd_sockjs: https://github.com/emqtt/emqttd_sockjs
|
||||||
.. _emqttd_recon: https://github.com/emqtt/emqttd_recon
|
.. _emqttd_recon: https://github.com/emqtt/emqttd_recon
|
||||||
|
.. _emqttd_sn: https://github.com/emqtt/emqttd_sn
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,6 @@ Sensors, Mobiles, Web Browsers and Application Servers could be connected by emq
|
||||||
| Author: | Feng Lee <feng@emqtt.io> |
|
| Author: | Feng Lee <feng@emqtt.io> |
|
||||||
+---------------+-----------------------------------------+
|
+---------------+-----------------------------------------+
|
||||||
|
|
||||||
.. NOTE:: MQTT-SN,CoAP Protocols are planned to 1.x release.
|
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
|
@ -35,7 +35,7 @@ Download binary packages from: http://emqtt.io/downloads
|
||||||
|
|
||||||
The package name consists of platform, version and release time.
|
The package name consists of platform, version and release time.
|
||||||
|
|
||||||
For example: emqttd-centos64-1.1-beta-20160601.zip
|
For example: emqttd-centos64-2.0-beta1-20160830.zip
|
||||||
|
|
||||||
.. _install_on_linux:
|
.. _install_on_linux:
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ Download CentOS Package from: http://emqtt.io/downloads/latest/centos, and then
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
unzip emqttd-centos64-1.1-beta-20160601.zip
|
unzip emqttd-centos64-2.0-beta-20160830.zip
|
||||||
|
|
||||||
Start the broker in console mode:
|
Start the broker in console mode:
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ If the broker is started successfully, console will print:
|
||||||
mqtt listen on 0.0.0.0:1883 with 16 acceptors.
|
mqtt listen on 0.0.0.0:1883 with 16 acceptors.
|
||||||
mqtts listen on 0.0.0.0:8883 with 4 acceptors.
|
mqtts listen on 0.0.0.0:8883 with 4 acceptors.
|
||||||
http listen on 0.0.0.0:8083 with 4 acceptors.
|
http listen on 0.0.0.0:8083 with 4 acceptors.
|
||||||
Erlang MQTT Broker 1.1 is running now
|
Erlang MQTT Broker 2.0 is running now
|
||||||
Eshell V6.4 (abort with ^G)
|
Eshell V6.4 (abort with ^G)
|
||||||
(emqttd@127.0.0.1)1>
|
(emqttd@127.0.0.1)1>
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ Check the running status of the broker:
|
||||||
|
|
||||||
$ ./bin/emqttd_ctl status
|
$ ./bin/emqttd_ctl status
|
||||||
Node 'emqttd@127.0.0.1' is started
|
Node 'emqttd@127.0.0.1' is started
|
||||||
emqttd 1.1 is running
|
emqttd 2.0 is running
|
||||||
|
|
||||||
Or check the status by URL::
|
Or check the status by URL::
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ We could install the broker on Mac OS X to develop and debug MQTT applications.
|
||||||
|
|
||||||
Download Mac Package from: http://emqtt.io/downloads/latest/macosx
|
Download Mac Package from: http://emqtt.io/downloads/latest/macosx
|
||||||
|
|
||||||
Configure 'lager' log level in 'etc/emqttd.config', all MQTT messages recevied/sent will be printed on console:
|
Configure 'lager' log level in 'releases/2.0/sys.config', all MQTT messages recevied/sent will be printed on console:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
|
@ -198,15 +198,15 @@ When all dependencies are ready, clone the emqttd project from github.com and bu
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
git clone https://github.com/emqtt/emqttd.git
|
git clone https://github.com/emqtt/emqttd-relx.git
|
||||||
|
|
||||||
cd emqttd
|
cd emqttd-relx && make
|
||||||
|
|
||||||
make && make dist
|
cd _rel/emqttd && ./bin/emqttd console
|
||||||
|
|
||||||
The binary package output in folder::
|
The binary package output in folder::
|
||||||
|
|
||||||
rel/emqttd
|
_rel/emqttd
|
||||||
|
|
||||||
.. _tcp_ports:
|
.. _tcp_ports:
|
||||||
|
|
||||||
|
@ -228,19 +228,20 @@ The TCP ports used can be configured in etc/emqttd.config:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
{listeners, [
|
%% Plain MQTT
|
||||||
{mqtt, 1883, [
|
{listener, mqtt, 1883, [
|
||||||
...
|
...
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
{mqtts, 8883, [
|
%% MQTT/SSL
|
||||||
|
{listener, mqtts, 8883, [
|
||||||
...
|
...
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% HTTP and WebSocket Listener
|
%% HTTP and WebSocket Listener
|
||||||
{http, 8083, [
|
{listener, http, 8083, [
|
||||||
...
|
...
|
||||||
]}
|
]}.
|
||||||
]},
|
|
||||||
|
|
||||||
The 18083 port is used by Web Dashboard of the broker. Default login: admin, Password: public
|
The 18083 port is used by Web Dashboard of the broker. Default login: admin, Password: public
|
||||||
|
|
||||||
|
@ -255,7 +256,7 @@ Two main configuration files of the emqttd broker:
|
||||||
+-------------------+-----------------------------------+
|
+-------------------+-----------------------------------+
|
||||||
| etc/vm.args | Erlang VM Arguments |
|
| etc/vm.args | Erlang VM Arguments |
|
||||||
+-------------------+-----------------------------------+
|
+-------------------+-----------------------------------+
|
||||||
| etc/emqttd.config | emqttd broker Config |
|
| etc/emqttd.conf | emqttd broker Config |
|
||||||
+-------------------+-----------------------------------+
|
+-------------------+-----------------------------------+
|
||||||
|
|
||||||
Two important parameters in etc/vm.args:
|
Two important parameters in etc/vm.args:
|
||||||
|
@ -277,17 +278,18 @@ The maximum number of allowed MQTT clients:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
{listeners, [
|
%% Plain MQTT
|
||||||
{mqtt, 1883, [
|
{listener, mqtt, 1883, [
|
||||||
%% TCP Acceptor Pool
|
|
||||||
|
%% Size of acceptor pool
|
||||||
{acceptors, 16},
|
{acceptors, 16},
|
||||||
|
|
||||||
%% Maximum number of concurrent MQTT clients
|
%% Maximum number of concurrent clients
|
||||||
{max_clients, 8192},
|
{max_clients, 8192},
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
.. _init_d_emqttd:
|
.. _init_d_emqttd:
|
||||||
|
|
||||||
|
|
|
@ -7,24 +7,28 @@ Plugins
|
||||||
|
|
||||||
The emqttd 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 emqttd 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 emqtt project released:
|
The plugins that emqttd 2.0 released:
|
||||||
|
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| Plugin | Description |
|
| Plugin | Description |
|
||||||
+===========================+===========================+
|
+===========================+===========================+
|
||||||
|
| `emqttd_dashboard`_ | Web Dashboard |
|
||||||
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_plugin_template`_ | Template Plugin |
|
| `emqttd_plugin_template`_ | Template Plugin |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_dashboard`_ | Web Dashboard |
|
| `emqttd_auth_ldap`_ | LDAP Auth |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_auth_http`_ | HTTP Auth/ACL Plugin |
|
| `emqttd_auth_http`_ | HTTP Auth/ACL Plugin |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_plugin_mysql`_ | MySQL Auth/ACL Plugin |
|
| `emqttd_auth_mysql`_ | MySQL Auth/ACL Plugin |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_plugin_pgsql`_ | PostgreSQL Auth/ACL Plugin|
|
| `emqttd_auth_pgsql`_ | PostgreSQL Auth/ACL Plugin|
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_plugin_redis`_ | Redis Auth/ACL Plugin |
|
| `emqttd_auth_redis`_ | Redis Auth/ACL Plugin |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_plugin_mongo`_ | MongoDB Auth/ACL Plugin |
|
| `emqttd_auth_mongo`_ | MongoDB Auth/ACL Plugin |
|
||||||
|
+---------------------------+---------------------------+
|
||||||
|
| `emqttd_sn`_ | MQTT-SN Protocol Plugin |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
| `emqttd_stomp`_ | STOMP Protocol Plugin |
|
| `emqttd_stomp`_ | STOMP Protocol Plugin |
|
||||||
+---------------------------+---------------------------+
|
+---------------------------+---------------------------+
|
||||||
|
@ -39,17 +43,9 @@ The plugins that emqtt project released:
|
||||||
emqttd_plugin_template - Template Plugin
|
emqttd_plugin_template - Template Plugin
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
A plugin is just a normal Erlang application under the 'emqttd/plugins' folder. Each plugin has e configuration file: 'etc/plugin.config'.
|
A plugin is just a normal Erlang application which has its own configuration file: 'etc/<PluginName>.config'.
|
||||||
|
|
||||||
plugins/emqttd_plugin_template is a demo plugin. The folder structure:
|
emqttd_plugin_template is a demo plugin.
|
||||||
|
|
||||||
+------------------------+---------------------------+
|
|
||||||
| File | Description |
|
|
||||||
+========================+===========================+
|
|
||||||
| etc/plugin.config | Plugin config file |
|
|
||||||
+------------------------+---------------------------+
|
|
||||||
| ebin/ | Erlang program files |
|
|
||||||
+------------------------+---------------------------+
|
|
||||||
|
|
||||||
Load, unload Plugin
|
Load, unload Plugin
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -78,22 +74,51 @@ The Web Dashboard for emqttd broker. The plugin will be loaded automatically whe
|
||||||
|
|
||||||
.. image:: _static/images/dashboard.png
|
.. image:: _static/images/dashboard.png
|
||||||
|
|
||||||
Configure Dashboard
|
Configure Dashboard Plugin
|
||||||
-------------------
|
--------------------------
|
||||||
|
|
||||||
emqttd_dashboard/etc/plugin.config:
|
etc/plugins/emqttd_dashboard.conf:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
|
||||||
{emqttd_dashboard, [
|
|
||||||
{listener,
|
{listener,
|
||||||
{emqttd_dashboard, 18083, [
|
{dashboard, 18083, [
|
||||||
{acceptors, 4},
|
{acceptors, 4},
|
||||||
{max_clients, 512}]}
|
{max_clients, 512}
|
||||||
}
|
|
||||||
]}
|
]}
|
||||||
].
|
}.
|
||||||
|
|
||||||
|
----------------------------------
|
||||||
|
emqttd_auth_ldap: LDAP Auth Plugin
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
LDAP Auth Plugin: https://github.com/emqtt/emqttd_auth_ldap
|
||||||
|
|
||||||
|
.. NOTE:: Supported in 2.0-beta1 release
|
||||||
|
|
||||||
|
Configure LDAP Plugin
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
etc/plugins/emqttd_auth_ldap.conf:
|
||||||
|
|
||||||
|
.. code-block:: erlang
|
||||||
|
|
||||||
|
{ldap, [
|
||||||
|
{servers, ["localhost"]},
|
||||||
|
{port, 389},
|
||||||
|
{timeout, 30},
|
||||||
|
{user_dn, "uid=$u,ou=People,dc=example,dc=com"},
|
||||||
|
{ssl, fasle},
|
||||||
|
{sslopts, [
|
||||||
|
{certfile, "ssl.crt"},
|
||||||
|
{keyfile, "ssl.key"}
|
||||||
|
]}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
Load LDAP Plugin
|
||||||
|
----------------
|
||||||
|
|
||||||
|
./bin/emqttd_ctl plugins load emqttd_auth_ldap
|
||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
emqttd_auth_http - HTTP Auth/ACL Plugin
|
emqttd_auth_http - HTTP Auth/ACL Plugin
|
||||||
|
@ -103,14 +128,12 @@ MQTT Authentication/ACL with HTTP API: https://github.com/emqtt/emqttd_auth_http
|
||||||
|
|
||||||
.. NOTE:: Supported in 1.1 release
|
.. NOTE:: Supported in 1.1 release
|
||||||
|
|
||||||
Configure emqttd_auth_http/etc/plugin.config
|
Configure HTTP Auth/ACL Plugin
|
||||||
--------------------------------------------
|
------------------------------
|
||||||
|
|
||||||
.. code:: erlang
|
etc/plugins/emqttd_auth_http.conf:
|
||||||
|
|
||||||
[
|
.. code-block:: erlang
|
||||||
|
|
||||||
{emqttd_auth_http, [
|
|
||||||
|
|
||||||
%% Variables: %u = username, %c = clientid, %a = ipaddress, %t = topic
|
%% Variables: %u = username, %c = clientid, %a = ipaddress, %t = topic
|
||||||
|
|
||||||
|
@ -121,7 +144,7 @@ Configure emqttd_auth_http/etc/plugin.config
|
||||||
{username, "%u"},
|
{username, "%u"},
|
||||||
{clientid, "%c"}
|
{clientid, "%c"}
|
||||||
]}
|
]}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
{auth_req, [
|
{auth_req, [
|
||||||
{method, post},
|
{method, post},
|
||||||
|
@ -131,7 +154,7 @@ Configure emqttd_auth_http/etc/plugin.config
|
||||||
{username, "%u"},
|
{username, "%u"},
|
||||||
{password, "%P"}
|
{password, "%P"}
|
||||||
]}
|
]}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% 'access' parameter: sub = 1, pub = 2
|
%% 'access' parameter: sub = 1, pub = 2
|
||||||
|
|
||||||
|
@ -145,19 +168,17 @@ Configure emqttd_auth_http/etc/plugin.config
|
||||||
{ipaddr, "%a"},
|
{ipaddr, "%a"},
|
||||||
{topic, "%t"}
|
{topic, "%t"}
|
||||||
]}
|
]}
|
||||||
]}
|
]}.
|
||||||
]}
|
|
||||||
|
|
||||||
].
|
|
||||||
|
|
||||||
HTTP API
|
HTTP Auth/ACL API
|
||||||
--------
|
-----------------
|
||||||
|
|
||||||
Return 200 if ok
|
Return 200 if ok
|
||||||
|
|
||||||
Return 4xx if unauthorized
|
Return 4xx if unauthorized
|
||||||
|
|
||||||
Load emqttd_auth_http plugin
|
Load HTTP Auth/ACL Plugin
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
@ -211,21 +232,17 @@ MQTT ACL Table
|
||||||
(6,1,'127.0.0.1',NULL,NULL,2,'#'),
|
(6,1,'127.0.0.1',NULL,NULL,2,'#'),
|
||||||
(7,1,NULL,'dashboard',NULL,1,'$SYS/#');
|
(7,1,NULL,'dashboard',NULL,1,'$SYS/#');
|
||||||
|
|
||||||
Configure emqttd_plugin_mysql/etc/plugin.config
|
Configure MySQL Auth/ACL Plugin
|
||||||
-----------------------------------------------
|
-------------------------------
|
||||||
|
|
||||||
Configure MySQL host, username, password and database:
|
etc/plugins/emqttd_plugin_mysql.conf:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
|
||||||
|
|
||||||
{emqttd_plugin_mysql, [
|
|
||||||
|
|
||||||
{mysql_pool, [
|
{mysql_pool, [
|
||||||
%% ecpool options
|
%% pool options
|
||||||
{pool_size, 8},
|
{pool_size, 8},
|
||||||
{auto_reconnect, 3},
|
{auto_reconnect, 1},
|
||||||
|
|
||||||
%% mysql options
|
%% mysql options
|
||||||
{host, "localhost"},
|
{host, "localhost"},
|
||||||
|
@ -233,42 +250,39 @@ Configure MySQL host, username, password and database:
|
||||||
{user, ""},
|
{user, ""},
|
||||||
{password, ""},
|
{password, ""},
|
||||||
{database, "mqtt"},
|
{database, "mqtt"},
|
||||||
{encoding, utf8}
|
{encoding, utf8},
|
||||||
]},
|
{keep_alive, true}
|
||||||
|
]}.
|
||||||
|
|
||||||
%% Variables: %u = username, %c = clientid, %a = ipaddress
|
%% Variables: %u = username, %c = clientid, %a = ipaddress
|
||||||
|
|
||||||
%% Superuser Query
|
%% Superuser Query
|
||||||
{superquery, "select is_superuser from mqtt_user where username = '%u' limit 1"},
|
{superquery, "select is_superuser from mqtt_user where username = '%u' limit 1"}.
|
||||||
|
|
||||||
%% Authentication Query: select password only
|
%% Authentication Query: select password only
|
||||||
{authquery, "select password from mqtt_user where username = '%u' limit 1"},
|
{authquery, "select password from mqtt_user where username = '%u' limit 1"}.
|
||||||
|
|
||||||
%% hash algorithm: plain, md5, sha, sha256, pbkdf2?
|
%% hash algorithm: plain, md5, sha, sha256, pbkdf2?
|
||||||
{password_hash, sha256},
|
{password_hash, sha256}.
|
||||||
|
|
||||||
%% select password with salt
|
%% select password with salt
|
||||||
%% {authquery, "select password, salt from mqtt_user where username = '%u'"},
|
%% {authquery, "select password, salt from mqtt_user where username = '%u'"}.
|
||||||
|
|
||||||
%% sha256 with salt prefix
|
%% sha256 with salt prefix
|
||||||
%% {password_hash, {salt, sha256}},
|
%% {password_hash, {salt, sha256}}.
|
||||||
|
|
||||||
%% sha256 with salt suffix
|
%% sha256 with salt suffix
|
||||||
%% {password_hash, {sha256, salt}},
|
%% {password_hash, {sha256, salt}}.
|
||||||
|
|
||||||
%% '%a' = ipaddress, '%u' = username, '%c' = clientid
|
%% '%a' = ipaddress, '%u' = username, '%c' = clientid
|
||||||
%% Comment this query, the acl will be disabled
|
%% Comment this query, the acl will be disabled
|
||||||
{aclquery, "select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'"},
|
{aclquery, "select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'"}.
|
||||||
|
|
||||||
%% If no ACL rules matched, return...
|
%% If no ACL rules matched, return...
|
||||||
{acl_nomatch, allow}
|
{acl_nomatch, allow}.
|
||||||
|
|
||||||
]}
|
Load MySQL Auth/ACL plugin
|
||||||
|
--------------------------
|
||||||
].
|
|
||||||
|
|
||||||
Load emqttd_plugin_mysql plugin
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
@ -280,8 +294,8 @@ emqttd_plugin_pgsql - PostgreSQL Auth/ACL Plugin
|
||||||
|
|
||||||
MQTT Authentication, ACL with PostgreSQL Database.
|
MQTT Authentication, ACL with PostgreSQL Database.
|
||||||
|
|
||||||
MQTT User Table
|
Postgre MQTT User Table
|
||||||
---------------
|
-----------------------
|
||||||
|
|
||||||
.. code-block:: sql
|
.. code-block:: sql
|
||||||
|
|
||||||
|
@ -293,8 +307,8 @@ MQTT User Table
|
||||||
salt character varying(40)
|
salt character varying(40)
|
||||||
);
|
);
|
||||||
|
|
||||||
MQTT ACL Table
|
Postgre MQTT ACL Table
|
||||||
--------------
|
----------------------
|
||||||
|
|
||||||
.. code-block:: sql
|
.. code-block:: sql
|
||||||
|
|
||||||
|
@ -317,19 +331,17 @@ MQTT ACL Table
|
||||||
(6,1,'127.0.0.1',NULL,NULL,2,'#'),
|
(6,1,'127.0.0.1',NULL,NULL,2,'#'),
|
||||||
(7,1,NULL,'dashboard',NULL,1,'$SYS/#');
|
(7,1,NULL,'dashboard',NULL,1,'$SYS/#');
|
||||||
|
|
||||||
Configure emqttd_plugin_pgsql/etc/plugin.config
|
Configure Postgre Auth/ACL Plugin
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
|
Plugin Config: etc/plugins/emqttd_plugin_pgsql.conf.
|
||||||
|
|
||||||
Configure host, username, password and database of PostgreSQL:
|
Configure host, username, password and database of PostgreSQL:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
|
||||||
|
|
||||||
{emqttd_plugin_pgsql, [
|
|
||||||
|
|
||||||
{pgsql_pool, [
|
{pgsql_pool, [
|
||||||
%% ecpool options
|
%% pool options
|
||||||
{pool_size, 8},
|
{pool_size, 8},
|
||||||
{auto_reconnect, 3},
|
{auto_reconnect, 3},
|
||||||
|
|
||||||
|
@ -341,43 +353,40 @@ Configure host, username, password and database of PostgreSQL:
|
||||||
{password, ""},
|
{password, ""},
|
||||||
{database, "mqtt"},
|
{database, "mqtt"},
|
||||||
{encoding, utf8}
|
{encoding, utf8}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% Variables: %u = username, %c = clientid, %a = ipaddress
|
%% Variables: %u = username, %c = clientid, %a = ipaddress
|
||||||
|
|
||||||
%% Superuser Query
|
%% Superuser Query
|
||||||
{superquery, "select is_superuser from mqtt_user where username = '%u' limit 1"},
|
{superquery, "select is_superuser from mqtt_user where username = '%u' limit 1"}.
|
||||||
|
|
||||||
%% Authentication Query: select password only
|
%% Authentication Query: select password only
|
||||||
{authquery, "select password from mqtt_user where username = '%u' limit 1"},
|
{authquery, "select password from mqtt_user where username = '%u' limit 1"}.
|
||||||
|
|
||||||
%% hash algorithm: plain, md5, sha, sha256, pbkdf2?
|
%% hash algorithm: plain, md5, sha, sha256, pbkdf2?
|
||||||
{password_hash, sha256},
|
{password_hash, sha256}.
|
||||||
|
|
||||||
%% select password with salt
|
%% select password with salt
|
||||||
%% {authquery, "select password, salt from mqtt_user where username = '%u'"},
|
%% {authquery, "select password, salt from mqtt_user where username = '%u'"}.
|
||||||
|
|
||||||
%% sha256 with salt prefix
|
%% sha256 with salt prefix
|
||||||
%% {password_hash, {salt, sha256}},
|
%% {password_hash, {salt, sha256}}.
|
||||||
|
|
||||||
%% sha256 with salt suffix
|
%% sha256 with salt suffix
|
||||||
%% {password_hash, {sha256, salt}},
|
%% {password_hash, {sha256, salt}}.
|
||||||
|
|
||||||
%% Comment this query, the acl will be disabled. Notice: don't edit this query!
|
%% Comment this query, the acl will be disabled. Notice: don't edit this query!
|
||||||
{aclquery, "select allow, ipaddr, username, clientid, access, topic from mqtt_acl
|
{aclquery, "select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'"}.
|
||||||
where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'"},
|
|
||||||
|
|
||||||
%% If no rules matched, return...
|
%% If no rules matched, return...
|
||||||
{acl_nomatch, allow}
|
{acl_nomatch, allow}.
|
||||||
]}
|
|
||||||
].
|
|
||||||
|
|
||||||
Load emqttd_plugin_pgsql Plugin
|
Load Postgre Auth/ACL Plugin
|
||||||
-------------------------------
|
-----------------------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
./bin/emqttd_ctl plugins load emqttd_plugin_pgsql
|
./bin/emqttd_ctl plugins load emqttd_auth_pgsql
|
||||||
|
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
emqttd_plugin_redis - Redis Auth/ACL Plugin
|
emqttd_plugin_redis - Redis Auth/ACL Plugin
|
||||||
|
@ -385,58 +394,56 @@ emqttd_plugin_redis - Redis Auth/ACL Plugin
|
||||||
|
|
||||||
MQTT Authentication, ACL with Redis: https://github.com/emqtt/emqttd_plugin_redis
|
MQTT Authentication, ACL with Redis: https://github.com/emqtt/emqttd_plugin_redis
|
||||||
|
|
||||||
Configure emqttd_plugin_redis/etc/plugin.config
|
Configure Redis Auth/ACL Plugin
|
||||||
-----------------------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
etc/plugins/emqttd_auth_redis.conf:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
{redis_pool, [
|
||||||
{emqttd_plugin_redis, [
|
%% pool options
|
||||||
|
|
||||||
{eredis_pool, [
|
|
||||||
%% ecpool options
|
|
||||||
{pool_size, 8},
|
{pool_size, 8},
|
||||||
{auto_reconnect, 2},
|
{auto_reconnect, 2},
|
||||||
|
|
||||||
%% eredis options
|
%% redis options
|
||||||
{host, "127.0.0.1"},
|
{host, "127.0.0.1"},
|
||||||
{port, 6379},
|
{port, 6379},
|
||||||
{database, 0},
|
{database, 0},
|
||||||
{password, ""}
|
{password, ""}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% Variables: %u = username, %c = clientid
|
%% Variables: %u = username, %c = clientid
|
||||||
|
|
||||||
%% HMGET mqtt_user:%u is_superuser
|
%% HMGET mqtt_user:%u is_superuser
|
||||||
{supercmd, ["HGET", "mqtt_user:%u", "is_superuser"]},
|
{supercmd, ["HGET", "mqtt_user:%u", "is_superuser"]}.
|
||||||
|
|
||||||
%% HMGET mqtt_user:%u password
|
%% HMGET mqtt_user:%u password
|
||||||
{authcmd, ["HGET", "mqtt_user:%u", "password"]},
|
{authcmd, ["HGET", "mqtt_user:%u", "password"]}.
|
||||||
|
|
||||||
%% Password hash algorithm: plain, md5, sha, sha256, pbkdf2?
|
%% Password hash algorithm: plain, md5, sha, sha256, pbkdf2?
|
||||||
{password_hash, sha256},
|
{password_hash, sha256}.
|
||||||
|
|
||||||
%% SMEMBERS mqtt_acl:%u
|
%% SMEMBERS mqtt_acl:%u
|
||||||
{aclcmd, ["SMEMBERS", "mqtt_acl:%u"]},
|
{aclcmd, ["SMEMBERS", "mqtt_acl:%u"]}.
|
||||||
|
|
||||||
%% If no rules matched, return...
|
%% If no rules matched, return...
|
||||||
{acl_nomatch, deny},
|
{acl_nomatch, deny}.
|
||||||
|
|
||||||
%% Load Subscriptions form Redis when client connected.
|
%% Load Subscriptions form Redis when client connected.
|
||||||
{subcmd, ["HGETALL", "mqtt_subs:%u"]}
|
{subcmd, ["HGETALL", "mqtt_subs:%u"]}.
|
||||||
]}
|
|
||||||
].
|
|
||||||
|
|
||||||
User HASH
|
|
||||||
---------
|
Redis User HASH
|
||||||
|
---------------
|
||||||
|
|
||||||
Set a 'user' hash with 'password' field, for example::
|
Set a 'user' hash with 'password' field, for example::
|
||||||
|
|
||||||
HSET mqtt_user:<username> is_superuser 1
|
HSET mqtt_user:<username> is_superuser 1
|
||||||
HSET mqtt_user:<username> password "passwd"
|
HSET mqtt_user:<username> password "passwd"
|
||||||
|
|
||||||
ACL Rule SET
|
Redis ACL Rule SET
|
||||||
------------
|
------------------
|
||||||
|
|
||||||
The plugin uses a redis SET to store ACL rules::
|
The plugin uses a redis SET to store ACL rules::
|
||||||
|
|
||||||
|
@ -444,8 +451,8 @@ The plugin uses a redis SET to store ACL rules::
|
||||||
SADD mqtt_acl:<username> "subscribe topic2"
|
SADD mqtt_acl:<username> "subscribe topic2"
|
||||||
SADD mqtt_acl:<username> "pubsub topic3"
|
SADD mqtt_acl:<username> "pubsub topic3"
|
||||||
|
|
||||||
Subscription HASH
|
Redis Subscription HASH
|
||||||
-----------------
|
-----------------------
|
||||||
|
|
||||||
The plugin can store static subscriptions in a redis Hash::
|
The plugin can store static subscriptions in a redis Hash::
|
||||||
|
|
||||||
|
@ -453,12 +460,12 @@ The plugin can store static subscriptions in a redis Hash::
|
||||||
HSET mqtt_subs:<username> topic2 1
|
HSET mqtt_subs:<username> topic2 1
|
||||||
HSET mqtt_subs:<username> topic3 2
|
HSET mqtt_subs:<username> topic3 2
|
||||||
|
|
||||||
Load emqttd_plugin_redis Plugin
|
Load Redis Auth/ACL Plugin
|
||||||
-------------------------------
|
--------------------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
./bin/emqttd_ctl plugins load emqttd_plugin_redis
|
./bin/emqttd_ctl plugins load emqttd_auth_redis
|
||||||
|
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
emqttd_plugin_mongo - MongoDB Auth/ACL Plugin
|
emqttd_plugin_mongo - MongoDB Auth/ACL Plugin
|
||||||
|
@ -466,55 +473,51 @@ emqttd_plugin_mongo - MongoDB Auth/ACL Plugin
|
||||||
|
|
||||||
MQTT Authentication, ACL with MongoDB: https://github.com/emqtt/emqttd_plugin_mongo
|
MQTT Authentication, ACL with MongoDB: https://github.com/emqtt/emqttd_plugin_mongo
|
||||||
|
|
||||||
Configure emqttd_plugin_mongo/etc/plugin.config
|
Configure MongoDB Auth/ACL Plugin
|
||||||
-----------------------------------------------
|
---------------------------------
|
||||||
|
|
||||||
|
etc/plugins/emqttd_plugin_mongo.conf:
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
|
||||||
{emqttd_plugin_mongo, [
|
|
||||||
|
|
||||||
{mongo_pool, [
|
{mongo_pool, [
|
||||||
{pool_size, 8},
|
{pool_size, 8},
|
||||||
{auto_reconnect, 3},
|
{auto_reconnect, 3},
|
||||||
|
|
||||||
%% Mongodb Driver Opts
|
%% Mongodb Opts
|
||||||
{host, "localhost"},
|
{host, "localhost"},
|
||||||
{port, 27017},
|
{port, 27017},
|
||||||
%% {login, ""},
|
%% {login, ""},
|
||||||
%% {password, ""},
|
%% {password, ""},
|
||||||
{database, "mqtt"}
|
{database, "mqtt"}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% Variables: %u = username, %c = clientid
|
%% Variables: %u = username, %c = clientid
|
||||||
|
|
||||||
%% Superuser Query
|
%% Superuser Query
|
||||||
{superquery, [
|
{superquery, pool, [
|
||||||
{collection, "mqtt_user"},
|
{collection, "mqtt_user"},
|
||||||
{super_field, "is_superuser"},
|
{super_field, "is_superuser"},
|
||||||
{selector, {"username", "%u"}}
|
{selector, {"username", "%u"}}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% Authentication Query
|
%% Authentication Query
|
||||||
{authquery, [
|
{authquery, pool, [
|
||||||
{collection, "mqtt_user"},
|
{collection, "mqtt_user"},
|
||||||
{password_field, "password"},
|
{password_field, "password"},
|
||||||
%% Hash Algorithm: plain, md5, sha, sha256, pbkdf2?
|
%% Hash Algorithm: plain, md5, sha, sha256, pbkdf2?
|
||||||
{password_hash, sha256},
|
{password_hash, sha256},
|
||||||
{selector, {"username", "%u"}}
|
{selector, {"username", "%u"}}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% ACL Query: "%u" = username, "%c" = clientid
|
%% ACL Query: "%u" = username, "%c" = clientid
|
||||||
{aclquery, [
|
{aclquery, pool, [
|
||||||
{collection, "mqtt_acl"},
|
{collection, "mqtt_acl"},
|
||||||
{selector, {"username", "%u"}}
|
{selector, {"username", "%u"}}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
%% If no ACL rules matched, return...
|
%% If no ACL rules matched, return...
|
||||||
{acl_nomatch, deny}
|
{acl_nomatch, deny}.
|
||||||
|
|
||||||
]}
|
|
||||||
].
|
|
||||||
|
|
||||||
MongoDB Database
|
MongoDB Database
|
||||||
----------------
|
----------------
|
||||||
|
@ -526,8 +529,8 @@ MongoDB Database
|
||||||
db.createCollection("mqtt_acl")
|
db.createCollection("mqtt_acl")
|
||||||
db.mqtt_user.ensureIndex({"username":1})
|
db.mqtt_user.ensureIndex({"username":1})
|
||||||
|
|
||||||
User Collection
|
MongoDB User Collection
|
||||||
---------------
|
-----------------------
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -543,8 +546,8 @@ For example::
|
||||||
db.mqtt_user.insert({username: "test", password: "password hash", is_superuser: false})
|
db.mqtt_user.insert({username: "test", password: "password hash", is_superuser: false})
|
||||||
db.mqtt_user:insert({username: "root", is_superuser: true})
|
db.mqtt_user:insert({username: "root", is_superuser: true})
|
||||||
|
|
||||||
ACL Collection
|
MongoDB ACL Collection
|
||||||
--------------
|
----------------------
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -561,12 +564,34 @@ For example::
|
||||||
db.mqtt_acl.insert({username: "test", publish: ["t/1", "t/2"], subscribe: ["user/%u", "client/%c"]})
|
db.mqtt_acl.insert({username: "test", publish: ["t/1", "t/2"], subscribe: ["user/%u", "client/%c"]})
|
||||||
db.mqtt_acl.insert({username: "admin", pubsub: ["#"]})
|
db.mqtt_acl.insert({username: "admin", pubsub: ["#"]})
|
||||||
|
|
||||||
Load emqttd_plugin_mongo Plugin
|
Load MongoDB Auth/ACL Plugin
|
||||||
-------------------------------
|
----------------------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
./bin/emqttd_ctl plugins load emqttd_plugin_mongo
|
./bin/emqttd_ctl plugins load emqttd_auth_mongo
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
emqttd_sn: MQTT-SN Protocol
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
MQTT-SN Protocol/Gateway Plugin.
|
||||||
|
|
||||||
|
Configure MQTT-SN Plugin
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. NOTE:: UDP Port for MQTT-SN: 1884
|
||||||
|
|
||||||
|
etc/plugins/emqttd_sn.conf::
|
||||||
|
|
||||||
|
{listener, {1884, []}}.
|
||||||
|
|
||||||
|
Load MQTT-SN Plugin
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
./bin/emqttd_ctl plugins load emqttd_sn
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
emqttd_stomp - STOMP Protocol
|
emqttd_stomp - STOMP Protocol
|
||||||
|
@ -574,48 +599,41 @@ emqttd_stomp - STOMP Protocol
|
||||||
|
|
||||||
Support STOMP 1.0/1.1/1.2 clients to connect to emqttd broker and communicate with MQTT Clients.
|
Support STOMP 1.0/1.1/1.2 clients to connect to emqttd broker and communicate with MQTT Clients.
|
||||||
|
|
||||||
Configure emqttd_stomp/etc/plugin.config
|
Configure Stomp Plugin
|
||||||
----------------------------------------
|
----------------------
|
||||||
|
|
||||||
|
etc/plugins/emqttd_stomp.conf:
|
||||||
|
|
||||||
.. NOTE:: Default Port for STOMP Protocol: 61613
|
.. NOTE:: Default Port for STOMP Protocol: 61613
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
|
||||||
{emqttd_stomp, [
|
|
||||||
|
|
||||||
{default_user, [
|
{default_user, [
|
||||||
{login, "guest"},
|
{login, "guest"},
|
||||||
{passcode, "guest"}
|
{passcode, "guest"}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
{allow_anonymous, true},
|
{allow_anonymous, true}.
|
||||||
|
|
||||||
%%TODO: unused...
|
|
||||||
{frame, [
|
{frame, [
|
||||||
{max_headers, 10},
|
{max_headers, 10},
|
||||||
{max_header_length, 1024},
|
{max_header_length, 1024},
|
||||||
{max_body_length, 8192}
|
{max_body_length, 8192}
|
||||||
]},
|
]}.
|
||||||
|
|
||||||
{listeners, [
|
{listener, emqttd_stomp, 61613, [
|
||||||
{emqttd_stomp, 61613, [
|
|
||||||
{acceptors, 4},
|
{acceptors, 4},
|
||||||
{max_clients, 512}
|
{max_clients, 512}
|
||||||
]}
|
]}.
|
||||||
]}
|
|
||||||
|
|
||||||
]}
|
|
||||||
].
|
|
||||||
|
|
||||||
Load emqttd_stomp Plugin
|
Load Stomp Plugin
|
||||||
------------------------
|
-----------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
./bin/emqttd_ctl plugins load emqttd_stomp
|
./bin/emqttd_ctl plugins load emqttd_stomp
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
emqttd_sockjs - STOMP/SockJS Plugin
|
emqttd_sockjs - STOMP/SockJS Plugin
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
@ -629,18 +647,21 @@ Configure emqttd_sockjs
|
||||||
|
|
||||||
.. code-block:: erlang
|
.. code-block:: erlang
|
||||||
|
|
||||||
[
|
{sockjs, []}.
|
||||||
{emqttd_sockjs, [
|
|
||||||
|
|
||||||
{sockjs, []},
|
{cowboy_listener, {stomp_sockjs, 61616, 4}}.
|
||||||
|
|
||||||
{cowboy_listener, {stomp_sockjs, 61616, 4}},
|
|
||||||
|
|
||||||
|
%% TODO: unused...
|
||||||
|
{stomp, [
|
||||||
|
{frame, [
|
||||||
|
{max_headers, 10},
|
||||||
|
{max_header_length, 1024},
|
||||||
|
{max_body_length, 8192}
|
||||||
]}
|
]}
|
||||||
].
|
]}.
|
||||||
|
|
||||||
Load emqttd_sockjs Plugin
|
Load SockJS Plugin
|
||||||
-------------------------
|
------------------
|
||||||
|
|
||||||
.. NOTE:: emqttd_stomp Plugin required.
|
.. NOTE:: emqttd_stomp Plugin required.
|
||||||
|
|
||||||
|
@ -661,8 +682,8 @@ emqttd_recon - Recon Plugin
|
||||||
|
|
||||||
The plugin loads `recon`_ library on a running emqttd broker. Recon libray helps debug and optimize an Erlang application.
|
The plugin loads `recon`_ library on a running emqttd broker. Recon libray helps debug and optimize an Erlang application.
|
||||||
|
|
||||||
Load emqttd_recon Plugin
|
Load Recon Plugin
|
||||||
------------------------
|
-----------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
@ -689,8 +710,8 @@ Erlang Module Reloader for Development
|
||||||
|
|
||||||
.. NOTE:: Don't load the plugin in production!
|
.. NOTE:: Don't load the plugin in production!
|
||||||
|
|
||||||
Load emqttd_reloader Plugin
|
Load 'Reloader' Plugin
|
||||||
---------------------------
|
----------------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
@ -712,15 +733,22 @@ Plugin Development Guide
|
||||||
Create a Plugin Project
|
Create a Plugin Project
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Clone emqttd source from github.com::
|
Clone emqttd_plugin_template source from github.com::
|
||||||
|
|
||||||
git clone https://github.com/emqtt/emqttd.git
|
git clone https://github.com/emqtt/emqttd_plugin_template.git
|
||||||
|
|
||||||
Create a plugin project under 'plugins' folder::
|
Create a plugin project with erlang.mk and depends on 'emqttd' application, the 'Makefile'::
|
||||||
|
|
||||||
cd plugins && mkdir emqttd_my_plugin
|
PROJECT = emqttd_plugin_abc
|
||||||
|
PROJECT_DESCRIPTION = emqttd abc plugin
|
||||||
|
PROJECT_VERSION = 1.0
|
||||||
|
|
||||||
cd emqttd_my_plugin && rebar create-app appid=emqttd_my_plugin
|
DEPS = emqttd
|
||||||
|
dep_emqttd = git https://github.com/emqtt/emqttd emq20
|
||||||
|
|
||||||
|
COVER = true
|
||||||
|
|
||||||
|
include erlang.mk
|
||||||
|
|
||||||
Template Plugin: https://github.com/emqtt/emqttd_plugin_template
|
Template Plugin: https://github.com/emqtt/emqttd_plugin_template
|
||||||
|
|
||||||
|
@ -735,7 +763,7 @@ emqttd_auth_demo.erl - demo authentication module:
|
||||||
|
|
||||||
-behaviour(emqttd_auth_mod).
|
-behaviour(emqttd_auth_mod).
|
||||||
|
|
||||||
-include("../../../include/emqttd.hrl").
|
-include_lib("emqttd/include/emqttd.hrl").
|
||||||
|
|
||||||
-export([init/1, check/3, description/0]).
|
-export([init/1, check/3, description/0]).
|
||||||
|
|
||||||
|
@ -754,7 +782,7 @@ emqttd_acl_demo.erl - demo ACL module:
|
||||||
|
|
||||||
-module(emqttd_acl_demo).
|
-module(emqttd_acl_demo).
|
||||||
|
|
||||||
-include("../../../include/emqttd.hrl").
|
-include_lib("emqttd/include/emqttd.hrl").
|
||||||
|
|
||||||
%% ACL callbacks
|
%% ACL callbacks
|
||||||
-export([init/1, check_acl/2, reload_acl/1, description/0]).
|
-export([init/1, check_acl/2, reload_acl/1, description/0]).
|
||||||
|
@ -830,7 +858,7 @@ emqttd_cli_demo.erl:
|
||||||
|
|
||||||
-module(emqttd_cli_demo).
|
-module(emqttd_cli_demo).
|
||||||
|
|
||||||
-include("../../../include/emqttd_cli.hrl").
|
-include_lib("emqttd/include/emqttd_cli.hrl").
|
||||||
|
|
||||||
-export([cmd/1]).
|
-export([cmd/1]).
|
||||||
|
|
||||||
|
@ -850,13 +878,14 @@ There will be a new CLI after the plugin loaded::
|
||||||
|
|
||||||
./bin/emqttd_ctl cmd arg1 arg2
|
./bin/emqttd_ctl cmd arg1 arg2
|
||||||
|
|
||||||
|
|
||||||
.. _emqttd_dashboard: https://github.com/emqtt/emqttd_dashboard
|
.. _emqttd_dashboard: https://github.com/emqtt/emqttd_dashboard
|
||||||
|
.. _emqttd_auth_ldap: https://github.com/emqtt/emqttd_auth_ldap
|
||||||
.. _emqttd_auth_http: https://github.com/emqtt/emqttd_auth_http
|
.. _emqttd_auth_http: https://github.com/emqtt/emqttd_auth_http
|
||||||
.. _emqttd_plugin_mysql: https://github.com/emqtt/emqttd_plugin_mysql
|
.. _emqttd_auth_mysql: https://github.com/emqtt/emqttd_plugin_mysql
|
||||||
.. _emqttd_plugin_pgsql: https://github.com/emqtt/emqttd_plugin_pgsql
|
.. _emqttd_auth_pgsql: https://github.com/emqtt/emqttd_plugin_pgsql
|
||||||
.. _emqttd_plugin_redis: https://github.com/emqtt/emqttd_plugin_redis
|
.. _emqttd_auth_redis: https://github.com/emqtt/emqttd_plugin_redis
|
||||||
.. _emqttd_plugin_mongo: https://github.com/emqtt/emqttd_plugin_mongo
|
.. _emqttd_auth_mongo: https://github.com/emqtt/emqttd_plugin_mongo
|
||||||
|
.. _emqttd_sn: https://github.com/emqtt/emqttd_sn
|
||||||
.. _emqttd_stomp: https://github.com/emqtt/emqttd_stomp
|
.. _emqttd_stomp: https://github.com/emqtt/emqttd_stomp
|
||||||
.. _emqttd_sockjs: https://github.com/emqtt/emqttd_sockjs
|
.. _emqttd_sockjs: https://github.com/emqtt/emqttd_sockjs
|
||||||
.. _emqttd_recon: https://github.com/emqtt/emqttd_recon
|
.. _emqttd_recon: https://github.com/emqtt/emqttd_recon
|
||||||
|
|
Loading…
Reference in New Issue