From 4b8cd18f5dbebb162a233c2e58525762a8912426 Mon Sep 17 00:00:00 2001 From: Feng Lee Date: Mon, 9 Oct 2017 19:43:06 +0800 Subject: [PATCH] Merge with EMQ X project --- .gitignore | 4 +- .travis.yml | 1 + LICENSE-MPL-RabbitMQ | 455 +++++++++++++++++ Makefile | 31 +- {doc => docs}/.placeholder | 0 {doc => docs}/MQTT-SN_spec_v1.2.pdf | Bin {doc => docs}/README | 0 {doc => docs}/mqtt-v3.1.1.pdf | Bin erlang.mk | 2 +- etc/{emq.conf => emqx.conf} | 59 ++- include/{emqttd.hrl => emqx.hrl} | 2 +- include/{emqttd_cli.hrl => emqx_cli.hrl} | 0 ...{emqttd_internal.hrl => emqx_internal.hrl} | 22 +- .../{emqttd_protocol.hrl => emqx_mqtt.hrl} | 0 include/emqx_rest.hrl | 17 + include/{emqttd_trie.hrl => emqx_trie.hrl} | 0 priv/{emq.schema => emqx.schema} | 362 ++++++++------ src/emqttd.app.src | 12 - src/emqttd.erl | 187 ------- src/emqttd_app.erl | 242 --------- src/emqttd_sup.erl | 55 -- src/emqx.erl | 279 +++++++++++ ...ss_control.erl => emqx_access_control.erl} | 8 +- ...d_access_rule.erl => emqx_access_rule.erl} | 15 +- ...acl_internal.erl => emqx_acl_internal.erl} | 15 +- src/{emqttd_acl_mod.erl => emqx_acl_mod.erl} | 4 +- src/{emqttd_alarm.erl => emqx_alarm.erl} | 24 +- src/emqx_app.erl | 85 ++++ ...{emqttd_auth_mod.erl => emqx_auth_mod.erl} | 10 +- src/{emqttd_base62.erl => emqx_base62.erl} | 2 +- src/{emqttd_boot.erl => emqx_boot.erl} | 2 +- src/{emqttd_bridge.erl => emqx_bridge.erl} | 36 +- ...ttd_bridge_sup.erl => emqx_bridge_sup.erl} | 11 +- ...ge_sup_sup.erl => emqx_bridge_sup_sup.erl} | 14 +- src/{emqttd_broker.erl => emqx_broker.erl} | 26 +- src/{emqttd_cli.erl => emqx_cli.erl} | 91 ++-- ...ttd_cli_config.erl => emqx_cli_config.erl} | 25 +- src/{emqttd_client.erl => emqx_client.erl} | 68 +-- src/{emqttd_cm.erl => emqx_cm.erl} | 8 +- src/{emqttd_cm_sup.erl => emqx_cm_sup.erl} | 10 +- src/{emqttd_config.erl => emqx_config.erl} | 13 +- src/{emqttd_ctl.erl => emqx_ctl.erl} | 18 +- src/{emqttd_gc.erl => emqx_gc.erl} | 4 +- src/{emqttd_gen_mod.erl => emqx_gen_mod.erl} | 6 +- src/{emqttd_guid.erl => emqx_guid.erl} | 6 +- src/{emqttd_hooks.erl => emqx_hooks.erl} | 2 +- src/{emqttd_http.erl => emqx_http.erl} | 24 +- ...{emqttd_inflight.erl => emqx_inflight.erl} | 2 +- ...mqttd_keepalive.erl => emqx_keepalive.erl} | 2 +- ...qtt_backend.erl => emqx_lager_backend.erl} | 8 +- src/{emqttd_message.erl => emqx_message.erl} | 10 +- src/{emqttd_metrics.erl => emqx_metrics.erl} | 21 +- src/{emqttd_mgmt.erl => emqx_mgmt.erl} | 99 ++-- src/{emqttd_misc.erl => emqx_misc.erl} | 2 +- src/{emqttd_mod_sup.erl => emqx_mod_sup.erl} | 4 +- src/{emqttd_mqueue.erl => emqx_mqueue.erl} | 8 +- src/{emqttd_net.erl => emqx_net.erl} | 4 +- src/{emqttd_packet.erl => emqx_packet.erl} | 30 +- src/{emqttd_parser.erl => emqx_parser.erl} | 6 +- src/{emqttd_plugins.erl => emqx_plugins.erl} | 16 +- src/{emqttd_pmon.erl => emqx_pmon.erl} | 2 +- ...{emqttd_pool_sup.erl => emqx_pool_sup.erl} | 4 +- src/{emqttd_pooler.erl => emqx_pooler.erl} | 8 +- src/{priority_queue.erl => emqx_pqueue.erl} | 41 +- ...{emqttd_protocol.erl => emqx_protocol.erl} | 138 ++--- src/{emqttd_pubsub.erl => emqx_pubsub.erl} | 42 +- ...ttd_pubsub_sup.erl => emqx_pubsub_sup.erl} | 8 +- ...{emqttd_rest_api.erl => emqx_rest_api.erl} | 105 ++-- src/{emqttd_router.erl => emqx_router.erl} | 18 +- src/emqx_rpc.erl | 17 + ...ttd_serializer.erl => emqx_serializer.erl} | 30 +- src/{emqttd_server.erl => emqx_server.erl} | 70 +-- src/{emqttd_session.erl => emqx_session.erl} | 149 +++--- ...d_session_sup.erl => emqx_session_sup.erl} | 7 +- src/{emqttd_sm.erl => emqx_sm.erl} | 24 +- ...mqttd_sm_helper.erl => emqx_sm_helper.erl} | 6 +- src/{emqttd_sm_sup.erl => emqx_sm_sup.erl} | 12 +- src/emqx_ssl.erl | 259 ++++++++++ src/{emqttd_stats.erl => emqx_stats.erl} | 20 +- src/emqx_sup.erl | 83 ++++ src/{emqttd_sysmon.erl => emqx_sysmon.erl} | 21 +- ...ttd_sysmon_sup.erl => emqx_sysmon_sup.erl} | 10 +- src/{emqttd_time.erl => emqx_time.erl} | 2 +- src/{emqttd_topic.erl => emqx_topic.erl} | 15 +- src/{emqttd_trace.erl => emqx_trace.erl} | 5 +- ...mqttd_trace_sup.erl => emqx_trace_sup.erl} | 6 +- src/{emqttd_trie.erl => emqx_trie.erl} | 10 +- src/{emqttd_vm.erl => emqx_vm.erl} | 2 +- src/{emqttd_ws.erl => emqx_ws.erl} | 18 +- ...mqttd_ws_client.erl => emqx_ws_client.erl} | 66 +-- ..._client_sup.erl => emqx_ws_client_sup.erl} | 8 +- test/emqttd_inflight_SUITE.erl | 51 -- test/{emqttd_SUITE.erl => emqx_SUITE.erl} | 470 +++++++++++------- test/emqx_SUITE_data/acl.conf | 29 ++ test/emqx_SUITE_data/slave.config | 60 +++ ...access_SUITE.erl => emqx_access_SUITE.erl} | 48 +- test/emqx_access_SUITE_data/acl.conf | 16 + ...acl_test_mod.erl => emqx_acl_test_mod.erl} | 3 +- ...d.erl => emqx_auth_anonymous_test_mod.erl} | 4 +- ..._dashboard.erl => emqx_auth_dashboard.erl} | 5 +- ...config_SUITE.erl => emqx_config_SUITE.erl} | 0 test/emqx_inflight_SUITE.erl | 63 +++ ...mqttd_lib_SUITE.erl => emqx_lib_SUITE.erl} | 68 ++- ...d_mock_client.erl => emqx_mock_client.erl} | 36 +- ...mqttd_mod_SUITE.erl => emqx_mod_SUITE.erl} | 0 ...mqueue_SUITE.erl => emqx_mqueue_SUITE.erl} | 80 +-- ...mqttd_net_SUITE.erl => emqx_net_SUITE.erl} | 6 +- ...ocol_SUITE.erl => emqx_protocol_SUITE.erl} | 130 ++--- ...d_topic_SUITE.erl => emqx_topic_SUITE.erl} | 11 +- ...ttd_trie_SUITE.erl => emqx_trie_SUITE.erl} | 14 +- ...{emqttd_vm_SUITE.erl => emqx_vm_SUITE.erl} | 38 +- test/ws_client.erl | 77 +++ 112 files changed, 3063 insertions(+), 1821 deletions(-) create mode 100644 LICENSE-MPL-RabbitMQ rename {doc => docs}/.placeholder (100%) rename {doc => docs}/MQTT-SN_spec_v1.2.pdf (100%) rename {doc => docs}/README (100%) rename {doc => docs}/mqtt-v3.1.1.pdf (100%) rename etc/{emq.conf => emqx.conf} (93%) rename include/{emqttd.hrl => emqx.hrl} (99%) rename include/{emqttd_cli.hrl => emqx_cli.hrl} (100%) rename include/{emqttd_internal.hrl => emqx_internal.hrl} (68%) rename include/{emqttd_protocol.hrl => emqx_mqtt.hrl} (100%) create mode 100644 include/emqx_rest.hrl rename include/{emqttd_trie.hrl => emqx_trie.hrl} (100%) rename priv/{emq.schema => emqx.schema} (74%) delete mode 100644 src/emqttd.app.src delete mode 100644 src/emqttd.erl delete mode 100644 src/emqttd_app.erl delete mode 100644 src/emqttd_sup.erl create mode 100644 src/emqx.erl rename src/{emqttd_access_control.erl => emqx_access_control.erl} (97%) rename src/{emqttd_access_rule.erl => emqx_access_rule.erl} (94%) rename src/{emqttd_acl_internal.erl => emqx_acl_internal.erl} (92%) rename src/{emqttd_acl_mod.erl => emqx_acl_mod.erl} (96%) rename src/{emqttd_alarm.erl => emqx_alarm.erl} (87%) create mode 100644 src/emqx_app.erl rename src/{emqttd_auth_mod.erl => emqx_auth_mod.erl} (94%) rename src/{emqttd_base62.erl => emqx_base62.erl} (98%) rename src/{emqttd_boot.erl => emqx_boot.erl} (99%) rename src/{emqttd_bridge.erl => emqx_bridge.erl} (87%) rename src/{emqttd_bridge_sup.erl => emqx_bridge_sup.erl} (77%) rename src/{emqttd_bridge_sup_sup.erl => emqx_bridge_sup_sup.erl} (86%) rename src/{emqttd_broker.erl => emqx_broker.erl} (89%) rename src/{emqttd_cli.erl => emqx_cli.erl} (88%) rename src/{emqttd_cli_config.erl => emqx_cli_config.erl} (97%) rename src/{emqttd_client.erl => emqx_client.erl} (87%) rename src/{emqttd_cm.erl => emqx_cm.erl} (97%) rename src/{emqttd_cm_sup.erl => emqx_cm_sup.erl} (85%) rename src/{emqttd_config.erl => emqx_config.erl} (93%) rename src/{emqttd_ctl.erl => emqx_ctl.erl} (91%) rename src/{emqttd_gc.erl => emqx_gc.erl} (96%) rename src/{emqttd_gen_mod.erl => emqx_gen_mod.erl} (92%) rename src/{emqttd_guid.erl => emqx_guid.erl} (97%) rename src/{emqttd_hooks.erl => emqx_hooks.erl} (99%) rename src/{emqttd_http.erl => emqx_http.erl} (93%) rename src/{emqttd_inflight.erl => emqx_inflight.erl} (99%) rename src/{emqttd_keepalive.erl => emqx_keepalive.erl} (98%) rename src/{lager_emqtt_backend.erl => emqx_lager_backend.erl} (91%) rename src/{emqttd_message.erl => emqx_message.erl} (97%) rename src/{emqttd_metrics.erl => emqx_metrics.erl} (94%) rename src/{emqttd_mgmt.erl => emqx_mgmt.erl} (85%) rename src/{emqttd_misc.erl => emqx_misc.erl} (99%) rename src/{emqttd_mod_sup.erl => emqx_mod_sup.erl} (97%) rename src/{emqttd_mqueue.erl => emqx_mqueue.erl} (98%) rename src/{emqttd_net.erl => emqx_net.erl} (99%) rename src/{emqttd_packet.erl => emqx_packet.erl} (88%) rename src/{emqttd_parser.erl => emqx_parser.erl} (99%) rename src/{emqttd_plugins.erl => emqx_plugins.erl} (96%) rename src/{emqttd_pmon.erl => emqx_pmon.erl} (98%) rename src/{emqttd_pool_sup.erl => emqx_pool_sup.erl} (94%) rename src/{emqttd_pooler.erl => emqx_pooler.erl} (94%) rename src/{priority_queue.erl => emqx_pqueue.erl} (90%) rename src/{emqttd_protocol.erl => emqx_protocol.erl} (80%) rename src/{emqttd_pubsub.erl => emqx_pubsub.erl} (86%) rename src/{emqttd_pubsub_sup.erl => emqx_pubsub_sup.erl} (94%) rename src/{emqttd_rest_api.erl => emqx_rest_api.erl} (86%) rename src/{emqttd_router.erl => emqx_router.erl} (94%) create mode 100644 src/emqx_rpc.erl rename src/{emqttd_serializer.erl => emqx_serializer.erl} (96%) rename src/{emqttd_server.erl => emqx_server.erl} (82%) rename src/{emqttd_session.erl => emqx_session.erl} (86%) rename src/{emqttd_session_sup.erl => emqx_session_sup.erl} (91%) rename src/{emqttd_sm.erl => emqx_sm.erl} (94%) rename src/{emqttd_sm_helper.erl => emqx_sm_helper.erl} (97%) rename src/{emqttd_sm_sup.erl => emqx_sm_sup.erl} (84%) create mode 100644 src/emqx_ssl.erl rename src/{emqttd_stats.erl => emqx_stats.erl} (91%) create mode 100644 src/emqx_sup.erl rename src/{emqttd_sysmon.erl => emqx_sysmon.erl} (91%) rename src/{emqttd_sysmon_sup.erl => emqx_sysmon_sup.erl} (82%) rename src/{emqttd_time.erl => emqx_time.erl} (98%) rename src/{emqttd_topic.erl => emqx_topic.erl} (93%) rename src/{emqttd_trace.erl => emqx_trace.erl} (97%) rename src/{emqttd_trace_sup.erl => emqx_trace_sup.erl} (88%) rename src/{emqttd_trie.erl => emqx_trie.erl} (95%) rename src/{emqttd_vm.erl => emqx_vm.erl} (99%) rename src/{emqttd_ws.erl => emqx_ws.erl} (88%) rename src/{emqttd_ws_client.erl => emqx_ws_client.erl} (83%) rename src/{emqttd_ws_client_sup.erl => emqx_ws_client_sup.erl} (86%) delete mode 100644 test/emqttd_inflight_SUITE.erl rename test/{emqttd_SUITE.erl => emqx_SUITE.erl} (58%) create mode 100644 test/emqx_SUITE_data/acl.conf create mode 100644 test/emqx_SUITE_data/slave.config rename test/{emqttd_access_SUITE.erl => emqx_access_SUITE.erl} (85%) create mode 100644 test/emqx_access_SUITE_data/acl.conf rename test/{emqttd_acl_test_mod.erl => emqx_acl_test_mod.erl} (97%) rename test/{emqttd_auth_anonymous_test_mod.erl => emqx_auth_anonymous_test_mod.erl} (92%) rename test/{emqttd_auth_dashboard.erl => emqx_auth_dashboard.erl} (92%) rename test/{emqttd_config_SUITE.erl => emqx_config_SUITE.erl} (100%) create mode 100644 test/emqx_inflight_SUITE.erl rename test/{emqttd_lib_SUITE.erl => emqx_lib_SUITE.erl} (71%) rename test/{emqttd_mock_client.erl => emqx_mock_client.erl} (51%) rename test/{emqttd_mod_SUITE.erl => emqx_mod_SUITE.erl} (100%) rename test/{emqttd_mqueue_SUITE.erl => emqx_mqueue_SUITE.erl} (74%) rename test/{emqttd_net_SUITE.erl => emqx_net_SUITE.erl} (89%) rename test/{emqttd_protocol_SUITE.erl => emqx_protocol_SUITE.erl} (78%) rename test/{emqttd_topic_SUITE.erl => emqx_topic_SUITE.erl} (96%) rename test/{emqttd_trie_SUITE.erl => emqx_trie_SUITE.erl} (92%) rename test/{emqttd_vm_SUITE.erl => emqx_vm_SUITE.erl} (87%) create mode 100644 test/ws_client.erl diff --git a/.gitignore b/.gitignore index 0aa159fd7..d3fc9149b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,13 +17,13 @@ log/ *.so .erlang.mk/ cover/ -emqttd.d +emqx.d eunit.coverdata test/ct.cover.spec logs ct.coverdata .idea/ -emqttd.iml +emqx.iml _rel/ data/ _build diff --git a/.travis.yml b/.travis.yml index 2266ed9e3..6c41760ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: erlang otp_release: - 20.0 + - 20.1 script: - make diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ new file mode 100644 index 000000000..f1ba9a5ca --- /dev/null +++ b/LICENSE-MPL-RabbitMQ @@ -0,0 +1,455 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is RabbitMQ. + + The Initial Developer of the Original Code is Pivotal Software, Inc. + Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.'' + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] diff --git a/Makefile b/Makefile index 3ea8fff3d..21eacc064 100644 --- a/Makefile +++ b/Makefile @@ -1,32 +1,34 @@ -PROJECT = emqttd -PROJECT_DESCRIPTION = Erlang MQTT Broker -PROJECT_VERSION = 2.3 +PROJECT = emqx +PROJECT_DESCRIPTION = EMQ X Broker +PROJECT_VERSION = 2.4 -DEPS = goldrush gproc lager esockd ekka mochiweb pbkdf2 lager_syslog bcrypt clique jsx +NO_AUTOPATCH = gen_rpc cuttlefish + +DEPS = goldrush gproc gen_rpc lager esockd ekka mochiweb pbkdf2 lager_syslog bcrypt clique jsx dep_goldrush = git https://github.com/basho/goldrush 0.1.9 dep_gproc = git https://github.com/uwiger/gproc +dep_gen_rpc = git https://github.com/priestjim/gen_rpc dep_getopt = git https://github.com/jcomellas/getopt v0.8.2 dep_lager = git https://github.com/basho/lager master +dep_lager_syslog = git https://github.com/basho/lager_syslog +dep_jsx = git https://github.com/talentdeficit/jsx dep_esockd = git https://github.com/emqtt/esockd master dep_ekka = git https://github.com/emqtt/ekka master dep_mochiweb = git https://github.com/emqtt/mochiweb master dep_pbkdf2 = git https://github.com/emqtt/pbkdf2 2.0.1 -dep_lager_syslog = git https://github.com/basho/lager_syslog dep_bcrypt = git https://github.com/smarkets/erlang-bcrypt master dep_clique = git https://github.com/emqtt/clique -dep_jsx = git https://github.com/talentdeficit/jsx ERLC_OPTS += +debug_info ERLC_OPTS += +'{parse_transform, lager_transform}' -NO_AUTOPATCH = cuttlefish - BUILD_DEPS = cuttlefish dep_cuttlefish = git https://github.com/emqtt/cuttlefish -TEST_DEPS = emqttc +TEST_DEPS = websocket_client emqttc dep_emqttc = git https://github.com/emqtt/emqttc +dep_websocket_client = git https://github.com/jeremyong/websocket_client TEST_ERLC_OPTS += +debug_info TEST_ERLC_OPTS += +'{parse_transform, lager_transform}' @@ -34,11 +36,10 @@ TEST_ERLC_OPTS += +'{parse_transform, lager_transform}' EUNIT_OPTS = verbose # EUNIT_ERL_OPTS = -CT_SUITES = emqttd emqttd_access emqttd_lib emqttd_inflight emqttd_mod \ - emqttd_net emqttd_mqueue emqttd_protocol emqttd_topic \ - emqttd_trie emqttd_vm emqttd_config +CT_SUITES = emqx emqx_lib emqx_topic emqx_trie emqx_mqueue emqx_inflight \ +emqx_vm emqx_net emqx_protocol emqx_access emqx_config -CT_OPTS = -cover test/ct.cover.spec -erl_args -name emqttd_ct@127.0.0.1 +CT_OPTS = -cover test/ct.cover.spec -erl_args -name emqxct@127.0.0.1 COVER = true @@ -49,8 +50,6 @@ DIALYZER_OPTS := --verbose --statistics -Werror_handling \ include erlang.mk -app:: rebar.config - app.config:: - ./deps/cuttlefish/cuttlefish -l info -e etc/ -c etc/emq.conf -i priv/emq.schema -d data/ + ./deps/cuttlefish/cuttlefish -l info -e etc/ -c etc/emqx.conf -i priv/emqx.schema -d data/ diff --git a/doc/.placeholder b/docs/.placeholder similarity index 100% rename from doc/.placeholder rename to docs/.placeholder diff --git a/doc/MQTT-SN_spec_v1.2.pdf b/docs/MQTT-SN_spec_v1.2.pdf similarity index 100% rename from doc/MQTT-SN_spec_v1.2.pdf rename to docs/MQTT-SN_spec_v1.2.pdf diff --git a/doc/README b/docs/README similarity index 100% rename from doc/README rename to docs/README diff --git a/doc/mqtt-v3.1.1.pdf b/docs/mqtt-v3.1.1.pdf similarity index 100% rename from doc/mqtt-v3.1.1.pdf rename to docs/mqtt-v3.1.1.pdf diff --git a/erlang.mk b/erlang.mk index e348d4493..f38d22653 100644 --- a/erlang.mk +++ b/erlang.mk @@ -2174,7 +2174,7 @@ help:: CT_RUN = ct_run \ -no_auto_compile \ -noinput \ - -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(DEPS_DIR)/gen_rpc/_build/dev/lib/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ -logdir $(CURDIR)/logs diff --git a/etc/emq.conf b/etc/emqx.conf similarity index 93% rename from etc/emq.conf rename to etc/emqx.conf index 1c0859921..bcf92d751 100644 --- a/etc/emq.conf +++ b/etc/emqx.conf @@ -1,5 +1,5 @@ ##=================================================================== -## EMQ Configuration R2.3 +## EMQ X Configuration R2.4 ##=================================================================== ##-------------------------------------------------------------------- @@ -7,7 +7,7 @@ ##-------------------------------------------------------------------- ## Cluster name -cluster.name = emqcl +cluster.name = emqxcl ## Cluster discovery strategy: manual | static | mcast | dns | etcd | k8s cluster.discovery = manual @@ -70,10 +70,10 @@ cluster.autoclean = 5m ##-------------------------------------------------------------------- ## Node name -node.name = emq@127.0.0.1 +node.name = emqx@127.0.0.1 ## Cookie for distributed node -node.cookie = emqsecretcookie +node.cookie = emqxsecretcookie ## SMP support: enable, auto, disable node.smp = auto @@ -93,7 +93,7 @@ node.async_threads = 32 node.process_limit = 256000 ## Sets the maximum number of simultaneously existing ports for this system -node.max_ports = 65536 +node.max_ports = 256000 ## Set the distribution buffer busy limit (dist_buf_busy_limit) node.dist_buffer_size = 32MB @@ -113,7 +113,40 @@ node.dist_net_ticktime = 60 ## Distributed node port range node.dist_listen_min = 6369 -node.dist_listen_max = 6379 +node.dist_listen_max = 6369 + +##-------------------------------------------------------------------- +## RPC Args +##-------------------------------------------------------------------- + +## TCP server port. +rpc.tcp_server_port = 5369 + +## Default TCP port for outgoing connections +rpc.tcp_client_port = 5369 + +## Client connect timeout +rpc.connect_timeout = 5000 + +## Client and Server send timeout +rpc.send_timeout = 5000 + +## Authentication timeout +rpc.authentication_timeout = 5000 + +## Default receive timeout for call() functions +rpc.call_receive_timeout = 15000 + +## Socket keepalive configuration +rpc.socket_keepalive_idle = 7200 + +## Seconds between probes +rpc.socket_keepalive_interval = 75 + +## Probes lost to close the connection +rpc.socket_keepalive_count = 9 + +## TODO: sndbuf, rcvbuf and buffer ##-------------------------------------------------------------------- ## Log @@ -311,6 +344,9 @@ listener.tcp.external.acceptors = 16 ## Maximum number of concurrent clients listener.tcp.external.max_clients = 102400 +## TODO: +## listener.tcp.external.zone = external + #listener.tcp.external.mountpoint = external/ ## Rate Limit. Format is 'burst,rate', Unit is KB/Sec @@ -347,6 +383,8 @@ listener.tcp.internal.acceptors = 16 ## Maximum number of concurrent clients listener.tcp.internal.max_clients = 102400 +#listener.tcp.internal.zone = internal + #listener.tcp.external.mountpoint = internal/ ## Rate Limit. Format is 'burst,rate', Unit is KB/Sec @@ -375,7 +413,10 @@ listener.ssl.external = 8883 listener.ssl.external.acceptors = 16 ## Maximum number of concurrent clients -listener.ssl.external.max_clients = 1024 +listener.ssl.external.max_clients = 102400 + +## Authentication Zone +## listener.ssl.external.zone = external ## listener.ssl.external.mountpoint = inbound/ @@ -478,6 +519,8 @@ listener.ws.external.acceptors = 4 listener.ws.external.max_clients = 64 +## listener.ws.external.zone = external + listener.ws.external.access.1 = allow all ## TCP Options @@ -500,6 +543,8 @@ listener.wss.external.acceptors = 4 listener.wss.external.max_clients = 64 +## listener.wss.external.zone = external + listener.wss.external.access.1 = allow all ## SSL Options diff --git a/include/emqttd.hrl b/include/emqx.hrl similarity index 99% rename from include/emqttd.hrl rename to include/emqx.hrl index 508712512..7254805be 100644 --- a/include/emqttd.hrl +++ b/include/emqx.hrl @@ -24,7 +24,7 @@ -define(PROTOCOL_VERSION, "MQTT/5.0"). --define(ERTS_MINIMUM, "8.0"). +-define(ERTS_MINIMUM, "9.0"). %%-------------------------------------------------------------------- %% Sys/Queue/Share Topics' Prefix diff --git a/include/emqttd_cli.hrl b/include/emqx_cli.hrl similarity index 100% rename from include/emqttd_cli.hrl rename to include/emqx_cli.hrl diff --git a/include/emqttd_internal.hrl b/include/emqx_internal.hrl similarity index 68% rename from include/emqttd_internal.hrl rename to include/emqx_internal.hrl index 343be68e4..3b3378d0c 100644 --- a/include/emqttd_internal.hrl +++ b/include/emqx_internal.hrl @@ -35,19 +35,19 @@ -define(UNEXPECTED_REQ(Req, State), (begin - lager:error("Unexpected Request: ~p", [Req]), + lager:error("[~s] Unexpected Request: ~p", [?MODULE, Req]), {reply, {error, unexpected_request}, State} end)). -define(UNEXPECTED_MSG(Msg, State), (begin - lager:error("Unexpected Message: ~p", [Msg]), + lager:error("[~s] Unexpected Message: ~p", [?MODULE, Msg]), {noreply, State} end)). -define(UNEXPECTED_INFO(Info, State), (begin - lager:error("Unexpected Info: ~p", [Info]), + lager:error("[~s] Unexpected Info: ~p", [?MODULE, Info]), {noreply, State} end)). @@ -59,19 +59,3 @@ -define(FULLSWEEP_OPTS, [{fullsweep_after, 10}]). --define(SUCCESS, 0). %% Success --define(ERROR1, 101). %% badrpc --define(ERROR2, 102). %% Unknown error --define(ERROR3, 103). %% Username or password error --define(ERROR4, 104). %% Empty username or password --define(ERROR5, 105). %% User does not exist --define(ERROR6, 106). %% Admin can not be deleted --define(ERROR7, 107). %% Missing request parameter --define(ERROR8, 108). %% Request parameter type error --define(ERROR9, 109). %% Request parameter is not a json --define(ERROR10, 110). %% Plugin has been loaded --define(ERROR11, 111). %% Plugin has been loaded --define(ERROR12, 112). %% Client not online --define(ERROR13, 113). %% User already exist --define(ERROR14, 114). %% OldPassword error - diff --git a/include/emqttd_protocol.hrl b/include/emqx_mqtt.hrl similarity index 100% rename from include/emqttd_protocol.hrl rename to include/emqx_mqtt.hrl diff --git a/include/emqx_rest.hrl b/include/emqx_rest.hrl new file mode 100644 index 000000000..c1c6b219d --- /dev/null +++ b/include/emqx_rest.hrl @@ -0,0 +1,17 @@ + +-define(SUCCESS, 0). %% Success +-define(ERROR1, 101). %% badrpc +-define(ERROR2, 102). %% Unknown error +-define(ERROR3, 103). %% Username or password error +-define(ERROR4, 104). %% Empty username or password +-define(ERROR5, 105). %% User does not exist +-define(ERROR6, 106). %% Admin can not be deleted +-define(ERROR7, 107). %% Missing request parameter +-define(ERROR8, 108). %% Request parameter type error +-define(ERROR9, 109). %% Request parameter is not a json +-define(ERROR10, 110). %% Plugin has been loaded +-define(ERROR11, 111). %% Plugin has been loaded +-define(ERROR12, 112). %% Client not online +-define(ERROR13, 113). %% User already exist +-define(ERROR14, 114). %% OldPassword error + diff --git a/include/emqttd_trie.hrl b/include/emqx_trie.hrl similarity index 100% rename from include/emqttd_trie.hrl rename to include/emqx_trie.hrl diff --git a/priv/emq.schema b/priv/emqx.schema similarity index 74% rename from priv/emq.schema rename to priv/emqx.schema index ce4baf36b..82f940a36 100644 --- a/priv/emq.schema +++ b/priv/emqx.schema @@ -1,5 +1,5 @@ %%-*- mode: erlang -*- -%% EMQ R2.3 config mapping +%% EMQ X config mapping %%-------------------------------------------------------------------- %% Cluster @@ -7,7 +7,7 @@ %% @doc Cluster name {mapping, "cluster.name", "ekka.cluster_name", [ - {default, emqcl}, + {default, emqxcl}, {datatype, atom} ]}. @@ -165,12 +165,12 @@ end}. %% @doc Erlang node name {mapping, "node.name", "vm_args.-name", [ - {default, "emq@127.0.0.1"} + {default, "emqx@127.0.0.1"} ]}. %% @doc Secret cookie for distributed erlang node {mapping, "node.cookie", "vm_args.-setcookie", [ - {default, "emqsecretcookie"} + {default, "emqxsecretcookie"} ]}. %% @doc SMP Support @@ -302,6 +302,64 @@ end}. hidden ]}. +%%-------------------------------------------------------------------- +%% RPC Args +%%-------------------------------------------------------------------- + +%% RPC server port. +{mapping, "rpc.tcp_server_port", "gen_rpc.tcp_server_port", [ + {default, 5369}, + {datatype, integer} +]}. + +%% Default TCP port for outgoing connections +{mapping, "rpc.tcp_client_port", "gen_rpc.tcp_client_port", [ + {default, 5369}, + {datatype, integer} +]}. + +%% Client connect timeout +{mapping, "rpc.connect_timeout", "gen_rpc.connect_timeout", [ + {default, 5000}, + {datatype, integer} +]}. + +%% Client and Server send timeout +{mapping, "rpc.send_timeout", "gen_rpc.send_timeout", [ + {default, 5000}, + {datatype, integer} +]}. + +%% Authentication timeout +{mapping, "rpc.authentication_timeout", "gen_rpc.authentication_timeout", [ + {default, 5000}, + {datatype, integer} +]}. + +%% Default receive timeout for call() functions +{mapping, "rpc.call_receive_timeout", "gen_rpc.call_receive_timeout", [ + {default, 15000}, + {datatype, integer} +]}. + +%% Socket keepalive configuration +{mapping, "rpc.socket_keepalive_idle", "gen_rpc.socket_keepalive_idle", [ + {default, 7200}, + {datatype, integer} +]}. + +%% Seconds between probes +{mapping, "rpc.socket_keepalive_interval", "gen_rpc.socket_keepalive_interval", [ + {default, 75}, + {datatype, integer} +]}. + +%% Probes lost to close the connection +{mapping, "rpc.socket_keepalive_count", "gen_rpc.socket_keepalive_count", [ + {default, 9}, + {datatype, integer} +]}. + %%-------------------------------------------------------------------- %% Log %%-------------------------------------------------------------------- @@ -331,13 +389,17 @@ end}. {datatype, file} ]}. +{mapping, "log.info.file", "lager.handlers", [ + {datatype, file} +]}. + {mapping, "log.syslog", "lager.handlers", [ {default, off}, {datatype, flag} ]}. {mapping, "log.syslog.identity", "lager.handlers", [ - {default, "emqttd"}, + {default, "emqx"}, {datatype, string} ]}. @@ -366,7 +428,7 @@ end}. {translation, "lager.handlers", fun(Conf) -> - ErrorHandler = case cuttlefish:conf_get("log.error.file", Conf) of + ErrorHandler = case cuttlefish:conf_get("log.error.file", Conf, undefined) of undefined -> []; ErrorFilename -> [{lager_file_backend, [{file, ErrorFilename}, {level, error}, @@ -374,11 +436,19 @@ end}. {date, "$D0"}, {count, 5}]}] end, + InfoHandler = case cuttlefish:conf_get("log.info.file", Conf, undefined) of + undefined -> []; + InfoFilename -> [{lager_file_backend, [{file, InfoFilename}, + {level, info}, + {size, 10485760}, + {date, "$D0"}, + {count, 5}]}] + end, ConsoleLogLevel = cuttlefish:conf_get("log.console.level", Conf), ConsoleLogFile = cuttlefish:conf_get("log.console.file", Conf), - ConsoleHandler = {lager_console_backend, ConsoleLogLevel}, + ConsoleHandler = {lager_console_backend, [{level, ConsoleLogLevel}]}, ConsoleFileHandler = {lager_file_backend, [{file, ConsoleLogFile}, {level, ConsoleLogLevel}, {size, 10485760}, @@ -400,7 +470,7 @@ end}. cuttlefish:conf_get("log.syslog.level", Conf)]}] end, - ConsoleHandlers ++ ErrorHandler ++ SyslogHandler + ConsoleHandlers ++ ErrorHandler ++ InfoHandler ++SyslogHandler end }. @@ -435,25 +505,25 @@ end}. %%-------------------------------------------------------------------- %% @doc Allow Anonymous -{mapping, "mqtt.allow_anonymous", "emqttd.allow_anonymous", [ +{mapping, "mqtt.allow_anonymous", "emqx.allow_anonymous", [ {default, false}, {datatype, {enum, [true, false]}} ]}. %% @doc ACL nomatch -{mapping, "mqtt.acl_nomatch", "emqttd.acl_nomatch", [ +{mapping, "mqtt.acl_nomatch", "emqx.acl_nomatch", [ {default, allow}, {datatype, {enum, [allow, deny]}} ]}. %% @doc Default ACL File -{mapping, "mqtt.acl_file", "emqttd.acl_file", [ +{mapping, "mqtt.acl_file", "emqx.acl_file", [ {datatype, string}, hidden ]}. %% @doc Cache ACL for PUBLISH -{mapping, "mqtt.cache_acl", "emqttd.cache_acl", [ +{mapping, "mqtt.cache_acl", "emqx.cache_acl", [ {default, true}, {datatype, {enum, [true, false]}} ]}. @@ -463,13 +533,13 @@ end}. %%-------------------------------------------------------------------- %% @doc Set the Max ClientId Length Allowed. -{mapping, "mqtt.max_clientid_len", "emqttd.protocol", [ +{mapping, "mqtt.max_clientid_len", "emqx.protocol", [ {default, 1024}, {datatype, integer} ]}. %% @doc Max Packet Size Allowed, 64K by default. -{mapping, "mqtt.max_packet_size", "emqttd.protocol", [ +{mapping, "mqtt.max_packet_size", "emqx.protocol", [ {default, "64KB"}, {datatype, bytesize} ]}. @@ -480,13 +550,13 @@ end}. {datatype, float} ]}. -{translation, "emqttd.protocol", fun(Conf) -> +{translation, "emqx.protocol", fun(Conf) -> [{max_clientid_len, cuttlefish:conf_get("mqtt.max_clientid_len", Conf)}, {max_packet_size, cuttlefish:conf_get("mqtt.max_packet_size", Conf)}, {keepalive_backoff, cuttlefish:conf_get("mqtt.keepalive_backoff", Conf)}] end}. -{mapping, "mqtt.websocket_protocol_header", "emqttd.websocket_protocol_header", [ +{mapping, "mqtt.websocket_protocol_header", "emqx.websocket_protocol_header", [ {default, on}, {datatype, flag} ]}. @@ -496,7 +566,7 @@ end}. %%-------------------------------------------------------------------- %% @doc Force the client to GC: integer -{mapping, "mqtt.conn.force_gc_count", "emqttd.conn_force_gc_count", [ +{mapping, "mqtt.conn.force_gc_count", "emqx.conn_force_gc_count", [ {datatype, integer} ]}. @@ -505,24 +575,24 @@ end}. %%-------------------------------------------------------------------- %% @doc Max Publish Rate of Message -{mapping, "mqtt.client.max_publish_rate", "emqttd.client", [ +{mapping, "mqtt.client.max_publish_rate", "emqx.client", [ {default, 0}, {datatype, integer} ]}. %% @doc Client Idle Timeout. -{mapping, "mqtt.client.idle_timeout", "emqttd.client", [ +{mapping, "mqtt.client.idle_timeout", "emqx.client", [ {default, "30s"}, {datatype, {duration, ms}} ]}. %% @doc Enable Stats of Client. -{mapping, "mqtt.client.enable_stats", "emqttd.client", [ +{mapping, "mqtt.client.enable_stats", "emqx.client", [ {default, off}, {datatype, flag} ]}. -{translation, "emqttd.client", fun(Conf) -> +{translation, "emqx.client", fun(Conf) -> [{max_publish_rate, cuttlefish:conf_get("mqtt.client.max_publish_rate", Conf)}, {client_idle_timeout, cuttlefish:conf_get("mqtt.client.idle_timeout", Conf)}, {client_enable_stats, cuttlefish:conf_get("mqtt.client.enable_stats", Conf)}] @@ -533,61 +603,61 @@ end}. %%-------------------------------------------------------------------- %% @doc Max Number of Subscriptions Allowed -{mapping, "mqtt.session.max_subscriptions", "emqttd.session", [ +{mapping, "mqtt.session.max_subscriptions", "emqx.session", [ {default, 0}, {datatype, integer} ]}. %% @doc Upgrade QoS? -{mapping, "mqtt.session.upgrade_qos", "emqttd.session", [ +{mapping, "mqtt.session.upgrade_qos", "emqx.session", [ {default, off}, {datatype, flag} ]}. %% @doc Max number of QoS 1 and 2 messages that can be “inflight” at one time. %% 0 means no limit -{mapping, "mqtt.session.max_inflight", "emqttd.session", [ +{mapping, "mqtt.session.max_inflight", "emqx.session", [ {default, 100}, {datatype, integer} ]}. %% @doc Retry interval for redelivering QoS1/2 messages. -{mapping, "mqtt.session.retry_interval", "emqttd.session", [ +{mapping, "mqtt.session.retry_interval", "emqx.session", [ {default, "20s"}, {datatype, {duration, ms}} ]}. %% @doc Max Packets that Awaiting PUBREL, 0 means no limit -{mapping, "mqtt.session.max_awaiting_rel", "emqttd.session", [ +{mapping, "mqtt.session.max_awaiting_rel", "emqx.session", [ {default, 0}, {datatype, integer} ]}. %% @doc Awaiting PUBREL Timeout -{mapping, "mqtt.session.await_rel_timeout", "emqttd.session", [ +{mapping, "mqtt.session.await_rel_timeout", "emqx.session", [ {default, "20s"}, {datatype, {duration, ms}} ]}. %% @doc Enable Stats -{mapping, "mqtt.session.enable_stats", "emqttd.session", [ +{mapping, "mqtt.session.enable_stats", "emqx.session", [ {default, off}, {datatype, flag} ]}. %% @doc Session Expiry Interval -{mapping, "mqtt.session.expiry_interval", "emqttd.session", [ +{mapping, "mqtt.session.expiry_interval", "emqx.session", [ {default, "2h"}, {datatype, {duration, ms}} ]}. %% @doc Ignore message from self publish -{mapping, "mqtt.session.ignore_loop_deliver", "emqttd.session", [ +{mapping, "mqtt.session.ignore_loop_deliver", "emqx.session", [ {default, false}, {datatype, {enum, [true, false]}} ]}. -{translation, "emqttd.session", fun(Conf) -> +{translation, "emqx.session", fun(Conf) -> [{max_subscriptions, cuttlefish:conf_get("mqtt.session.max_subscriptions", Conf)}, {upgrade_qos, cuttlefish:conf_get("mqtt.session.upgrade_qos", Conf)}, {max_inflight, cuttlefish:conf_get("mqtt.session.max_inflight", Conf)}, @@ -604,42 +674,42 @@ end}. %%-------------------------------------------------------------------- %% @doc Type: simple | priority -{mapping, "mqtt.mqueue.type", "emqttd.mqueue", [ +{mapping, "mqtt.mqueue.type", "emqx.mqueue", [ {default, simple}, {datatype, atom} ]}. %% @doc Topic Priority: 0~255, Default is 0 -{mapping, "mqtt.mqueue.priority", "emqttd.mqueue", [ +{mapping, "mqtt.mqueue.priority", "emqx.mqueue", [ {default, ""}, {datatype, string} ]}. %% @doc Max queue length. Enqueued messages when persistent client disconnected, or inflight window is full. 0 means no limit. -{mapping, "mqtt.mqueue.max_length", "emqttd.mqueue", [ +{mapping, "mqtt.mqueue.max_length", "emqx.mqueue", [ {default, 0}, {datatype, integer} ]}. %% @doc Low-water mark of queued messages -{mapping, "mqtt.mqueue.low_watermark", "emqttd.mqueue", [ +{mapping, "mqtt.mqueue.low_watermark", "emqx.mqueue", [ {default, "20%"}, {datatype, {percent, float}} ]}. %% @doc High-water mark of queued messages -{mapping, "mqtt.mqueue.high_watermark", "emqttd.mqueue", [ +{mapping, "mqtt.mqueue.high_watermark", "emqx.mqueue", [ {default, "60%"}, {datatype, {percent, float}} ]}. %% @doc Queue Qos0 messages? -{mapping, "mqtt.mqueue.store_qos0", "emqttd.mqueue", [ +{mapping, "mqtt.mqueue.store_qos0", "emqx.mqueue", [ {default, true}, {datatype, {enum, [true, false]}} ]}. -{translation, "emqttd.mqueue", fun(Conf) -> +{translation, "emqx.mqueue", fun(Conf) -> Opts = [{type, cuttlefish:conf_get("mqtt.mqueue.type", Conf, simple)}, {max_length, cuttlefish:conf_get("mqtt.mqueue.max_length", Conf)}, {low_watermark, cuttlefish:conf_get("mqtt.mqueue.low_watermark", Conf)}, @@ -658,7 +728,7 @@ end}. %% MQTT Broker %%-------------------------------------------------------------------- -{mapping, "mqtt.broker.sys_interval", "emqttd.broker_sys_interval", [ +{mapping, "mqtt.broker.sys_interval", "emqx.broker_sys_interval", [ {default, 60}, {datatype, integer} ]}. @@ -667,22 +737,22 @@ end}. %% MQTT PubSub %%-------------------------------------------------------------------- -{mapping, "mqtt.pubsub.pool_size", "emqttd.pubsub", [ +{mapping, "mqtt.pubsub.pool_size", "emqx.pubsub", [ {default, 8}, {datatype, integer} ]}. -{mapping, "mqtt.pubsub.by_clientid", "emqttd.pubsub", [ +{mapping, "mqtt.pubsub.by_clientid", "emqx.pubsub", [ {default, true}, {datatype, {enum, [true, false]}} ]}. -{mapping, "mqtt.pubsub.async", "emqttd.pubsub", [ +{mapping, "mqtt.pubsub.async", "emqx.pubsub", [ {default, true}, {datatype, {enum, [true, false]}} ]}. -{translation, "emqttd.pubsub", fun(Conf) -> +{translation, "emqx.pubsub", fun(Conf) -> [{pool_size, cuttlefish:conf_get("mqtt.pubsub.pool_size", Conf)}, {by_clientid, cuttlefish:conf_get("mqtt.pubsub.by_clientid", Conf)}, {async, cuttlefish:conf_get("mqtt.pubsub.async", Conf)}] @@ -692,17 +762,17 @@ end}. %% MQTT Bridge %%-------------------------------------------------------------------- -{mapping, "mqtt.bridge.max_queue_len", "emqttd.bridge", [ +{mapping, "mqtt.bridge.max_queue_len", "emqx.bridge", [ {default, 10000}, {datatype, integer} ]}. -{mapping, "mqtt.bridge.ping_down_interval", "emqttd.bridge", [ +{mapping, "mqtt.bridge.ping_down_interval", "emqx.bridge", [ {default, 1}, {datatype, integer} ]}. -{translation, "emqttd.bridge", fun(Conf) -> +{translation, "emqx.bridge", fun(Conf) -> [{max_queue_len, cuttlefish:conf_get("mqtt.bridge.max_queue_len", Conf)}, {ping_down_interval, cuttlefish:conf_get("mqtt.bridge.ping_down_interval", Conf)}] end}. @@ -711,11 +781,11 @@ end}. %% MQTT Plugins %%------------------------------------------------------------------- -{mapping, "mqtt.plugins.etc_dir", "emqttd.plugins_etc_dir", [ +{mapping, "mqtt.plugins.etc_dir", "emqx.plugins_etc_dir", [ {datatype, string} ]}. -{mapping, "mqtt.plugins.loaded_file", "emqttd.plugins_loaded_file", [ +{mapping, "mqtt.plugins.loaded_file", "emqx.plugins_loaded_file", [ {datatype, string} ]}. @@ -726,73 +796,73 @@ end}. %%-------------------------------------------------------------------- %% TCP Listeners -{mapping, "listener.tcp.$name", "emqttd.listeners", [ +{mapping, "listener.tcp.$name", "emqx.listeners", [ {datatype, [integer, ip]} ]}. -{mapping, "listener.tcp.$name.acceptors", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.acceptors", "emqx.listeners", [ {default, 8}, {datatype, integer} ]}. -{mapping, "listener.tcp.$name.max_clients", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.max_clients", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.tcp.$name.zone", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.zone", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.tcp.$name.mountpoint", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.mountpoint", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.tcp.$name.rate_limit", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.rate_limit", "emqx.listeners", [ {default, undefined}, {datatype, string} ]}. -{mapping, "listener.tcp.$name.access.$id", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.access.$id", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.tcp.$name.proxy_protocol", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.proxy_protocol", "emqx.listeners", [ %%{default, off}, {datatype, flag} ]}. -{mapping, "listener.tcp.$name.proxy_protocol_timeout", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.proxy_protocol_timeout", "emqx.listeners", [ %%{default, "5s"}, {datatype, {duration, ms}} ]}. -{mapping, "listener.tcp.$name.backlog", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.backlog", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.tcp.$name.recbuf", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.recbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.tcp.$name.sndbuf", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.sndbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.tcp.$name.buffer", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.buffer", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.tcp.$name.tune_buffer", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden ]}. -{mapping, "listener.tcp.$name.nodelay", "emqttd.listeners", [ +{mapping, "listener.tcp.$name.nodelay", "emqx.listeners", [ {datatype, {enum, [true, false]}}, hidden ]}. @@ -800,186 +870,186 @@ end}. %%-------------------------------------------------------------------- %% SSL Listeners -{mapping, "listener.ssl.$name", "emqttd.listeners", [ +{mapping, "listener.ssl.$name", "emqx.listeners", [ {datatype, [integer, ip]} ]}. -{mapping, "listener.ssl.$name.acceptors", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.acceptors", "emqx.listeners", [ {default, 8}, {datatype, integer} ]}. -{mapping, "listener.ssl.$name.max_clients", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.max_clients", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.ssl.$name.zone", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.zone", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.mountpoint", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.mountpoint", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.rate_limit", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.rate_limit", "emqx.listeners", [ {default, undefined}, {datatype, string} ]}. -{mapping, "listener.ssl.$name.access.$id", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.access.$id", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.proxy_protocol", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.proxy_protocol", "emqx.listeners", [ %%{default, off}, {datatype, flag} ]}. -{mapping, "listener.ssl.$name.proxy_protocol_timeout", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.proxy_protocol_timeout", "emqx.listeners", [ %%{default, "5s"}, {datatype, {duration, ms}} ]}. -{mapping, "listener.ssl.$name.backlog", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.backlog", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.ssl.$name.recbuf", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.recbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.ssl.$name.sndbuf", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.sndbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.ssl.$name.buffer", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.buffer", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.ssl.$name.tune_buffer", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden ]}. -{mapping, "listener.ssl.$name.nodelay", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.nodelay", "emqx.listeners", [ {datatype, {enum, [true, false]}}, hidden ]}. -{mapping, "listener.ssl.$name.tls_versions", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.tls_versions", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.ciphers", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.ciphers", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.handshake_timeout", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.handshake_timeout", "emqx.listeners", [ {default, "15s"}, {datatype, {duration, ms}} ]}. -{mapping, "listener.ssl.$name.dhfile", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.dhfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.keyfile", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.keyfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.certfile", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.certfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.cacertfile", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.cacertfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ssl.$name.verify", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.verify", "emqx.listeners", [ {datatype, atom} ]}. -{mapping, "listener.ssl.$name.fail_if_no_peer_cert", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.fail_if_no_peer_cert", "emqx.listeners", [ {datatype, {enum, [true, false]}} ]}. -{mapping, "listener.ssl.$name.secure_renegotiate", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.secure_renegotiate", "emqx.listeners", [ {datatype, flag} ]}. -{mapping, "listener.ssl.$name.reuse_sessions", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.reuse_sessions", "emqx.listeners", [ {default, on}, {datatype, flag} ]}. -{mapping, "listener.ssl.$name.honor_cipher_order", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.honor_cipher_order", "emqx.listeners", [ {datatype, flag} ]}. -{mapping, "listener.ssl.$name.peer_cert_as_username", "emqttd.listeners", [ +{mapping, "listener.ssl.$name.peer_cert_as_username", "emqx.listeners", [ {datatype, {enum, [cn, dn]}} ]}. %%-------------------------------------------------------------------- %% MQTT/WebSocket Listeners -{mapping, "listener.ws.$name", "emqttd.listeners", [ +{mapping, "listener.ws.$name", "emqx.listeners", [ {datatype, [integer, ip]} ]}. -{mapping, "listener.ws.$name.acceptors", "emqttd.listeners", [ +{mapping, "listener.ws.$name.acceptors", "emqx.listeners", [ {default, 8}, {datatype, integer} ]}. -{mapping, "listener.ws.$name.max_clients", "emqttd.listeners", [ +{mapping, "listener.ws.$name.max_clients", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.ws.$name.rate_limit", "emqttd.listeners", [ +{mapping, "listener.ws.$name.rate_limit", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ws.$name.zone", "emqttd.listeners", [ +{mapping, "listener.ws.$name.zone", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ws.$name.access.$id", "emqttd.listeners", [ +{mapping, "listener.ws.$name.access.$id", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.ws.$name.backlog", "emqttd.listeners", [ +{mapping, "listener.ws.$name.backlog", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.ws.$name.recbuf", "emqttd.listeners", [ +{mapping, "listener.ws.$name.recbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.ws.$name.sndbuf", "emqttd.listeners", [ +{mapping, "listener.ws.$name.sndbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.ws.$name.buffer", "emqttd.listeners", [ +{mapping, "listener.ws.$name.buffer", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.ws.$name.tune_buffer", "emqttd.listeners", [ +{mapping, "listener.ws.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden ]}. -{mapping, "listener.ws.$name.nodelay", "emqttd.listeners", [ +{mapping, "listener.ws.$name.nodelay", "emqx.listeners", [ {datatype, {enum, [true, false]}}, hidden ]}. @@ -987,92 +1057,92 @@ end}. %%-------------------------------------------------------------------- %% MQTT/WebSocket/SSL Listeners -{mapping, "listener.wss.$name", "emqttd.listeners", [ +{mapping, "listener.wss.$name", "emqx.listeners", [ {datatype, [integer, ip]} ]}. -{mapping, "listener.wss.$name.acceptors", "emqttd.listeners", [ +{mapping, "listener.wss.$name.acceptors", "emqx.listeners", [ {default, 8}, {datatype, integer} ]}. -{mapping, "listener.wss.$name.max_clients", "emqttd.listeners", [ +{mapping, "listener.wss.$name.max_clients", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.wss.$name.zone", "emqttd.listeners", [ +{mapping, "listener.wss.$name.zone", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.mountpoint", "emqttd.listeners", [ +{mapping, "listener.wss.$name.mountpoint", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.rate_limit", "emqttd.listeners", [ +{mapping, "listener.wss.$name.rate_limit", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.access.$id", "emqttd.listeners", [ +{mapping, "listener.wss.$name.access.$id", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.backlog", "emqttd.listeners", [ +{mapping, "listener.wss.$name.backlog", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.wss.$name.recbuf", "emqttd.listeners", [ +{mapping, "listener.wss.$name.recbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.wss.$name.sndbuf", "emqttd.listeners", [ +{mapping, "listener.wss.$name.sndbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.wss.$name.buffer", "emqttd.listeners", [ +{mapping, "listener.wss.$name.buffer", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.wss.$name.tune_buffer", "emqttd.listeners", [ +{mapping, "listener.wss.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden ]}. -{mapping, "listener.wss.$name.nodelay", "emqttd.listeners", [ +{mapping, "listener.wss.$name.nodelay", "emqx.listeners", [ {datatype, {enum, [true, false]}}, hidden ]}. -{mapping, "listener.wss.$name.handshake_timeout", "emqttd.listeners", [ +{mapping, "listener.wss.$name.handshake_timeout", "emqx.listeners", [ {default, "15s"}, {datatype, {duration, ms}} ]}. -{mapping, "listener.wss.$name.keyfile", "emqttd.listeners", [ +{mapping, "listener.wss.$name.keyfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.certfile", "emqttd.listeners", [ +{mapping, "listener.wss.$name.certfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.cacertfile", "emqttd.listeners", [ +{mapping, "listener.wss.$name.cacertfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.wss.$name.verify", "emqttd.listeners", [ +{mapping, "listener.wss.$name.verify", "emqx.listeners", [ {datatype, atom} ]}. -{mapping, "listener.wss.$name.fail_if_no_peer_cert", "emqttd.listeners", [ +{mapping, "listener.wss.$name.fail_if_no_peer_cert", "emqx.listeners", [ {datatype, {enum, [true, false]}} ]}. -{translation, "emqttd.listeners", fun(Conf) -> +{translation, "emqx.listeners", fun(Conf) -> Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end, @@ -1188,79 +1258,79 @@ end}. %%-------------------------------------------------------------------- %% MQTT REST API Listeners -{mapping, "listener.api.$name", "emqttd.listeners", [ +{mapping, "listener.api.$name", "emqx.listeners", [ {datatype, [integer, ip]} ]}. -{mapping, "listener.api.$name.acceptors", "emqttd.listeners", [ +{mapping, "listener.api.$name.acceptors", "emqx.listeners", [ {default, 8}, {datatype, integer} ]}. -{mapping, "listener.api.$name.max_clients", "emqttd.listeners", [ +{mapping, "listener.api.$name.max_clients", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.api.$name.rate_limit", "emqttd.listeners", [ +{mapping, "listener.api.$name.rate_limit", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.api.$name.access.$id", "emqttd.listeners", [ +{mapping, "listener.api.$name.access.$id", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.api.$name.backlog", "emqttd.listeners", [ +{mapping, "listener.api.$name.backlog", "emqx.listeners", [ {default, 1024}, {datatype, integer} ]}. -{mapping, "listener.api.$name.recbuf", "emqttd.listeners", [ +{mapping, "listener.api.$name.recbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.api.$name.sndbuf", "emqttd.listeners", [ +{mapping, "listener.api.$name.sndbuf", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.api.$name.buffer", "emqttd.listeners", [ +{mapping, "listener.api.$name.buffer", "emqx.listeners", [ {datatype, bytesize}, hidden ]}. -{mapping, "listener.api.$name.tune_buffer", "emqttd.listeners", [ +{mapping, "listener.api.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden ]}. -{mapping, "listener.api.$name.nodelay", "emqttd.listeners", [ +{mapping, "listener.api.$name.nodelay", "emqx.listeners", [ {datatype, {enum, [true, false]}}, hidden ]}. -{mapping, "listener.api.$name.handshake_timeout", "emqttd.listeners", [ +{mapping, "listener.api.$name.handshake_timeout", "emqx.listeners", [ {datatype, {duration, ms}} ]}. -{mapping, "listener.api.$name.keyfile", "emqttd.listeners", [ +{mapping, "listener.api.$name.keyfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.api.$name.certfile", "emqttd.listeners", [ +{mapping, "listener.api.$name.certfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.api.$name.cacertfile", "emqttd.listeners", [ +{mapping, "listener.api.$name.cacertfile", "emqx.listeners", [ {datatype, string} ]}. -{mapping, "listener.api.$name.verify", "emqttd.listeners", [ +{mapping, "listener.api.$name.verify", "emqx.listeners", [ {datatype, atom} ]}. -{mapping, "listener.api.$name.fail_if_no_peer_cert", "emqttd.listeners", [ +{mapping, "listener.api.$name.fail_if_no_peer_cert", "emqx.listeners", [ {datatype, {enum, [true, false]}} ]}. @@ -1270,36 +1340,36 @@ end}. %% @doc Long GC, don't monitor in production mode for: %% https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421 -{mapping, "sysmon.long_gc", "emqttd.sysmon", [ +{mapping, "sysmon.long_gc", "emqx.sysmon", [ {default, false}, {datatype, {enum, [true, false]}} ]}. %% @doc Long Schedule(ms) -{mapping, "sysmon.long_schedule", "emqttd.sysmon", [ +{mapping, "sysmon.long_schedule", "emqx.sysmon", [ {default, 1000}, {datatype, integer} ]}. %% @doc Large Heap -{mapping, "sysmon.large_heap", "emqttd.sysmon", [ +{mapping, "sysmon.large_heap", "emqx.sysmon", [ {default, "8MB"}, {datatype, bytesize} ]}. %% @doc Monitor Busy Port -{mapping, "sysmon.busy_port", "emqttd.sysmon", [ +{mapping, "sysmon.busy_port", "emqx.sysmon", [ {default, false}, {datatype, {enum, [true, false]}} ]}. %% @doc Monitor Busy Dist Port -{mapping, "sysmon.busy_dist_port", "emqttd.sysmon", [ +{mapping, "sysmon.busy_dist_port", "emqx.sysmon", [ {default, true}, {datatype, {enum, [true, false]}} ]}. -{translation, "emqttd.sysmon", fun(Conf) -> +{translation, "emqx.sysmon", fun(Conf) -> [{long_gc, cuttlefish:conf_get("sysmon.long_gc", Conf)}, {long_schedule, cuttlefish:conf_get("sysmon.long_schedule", Conf)}, {large_heap, cuttlefish:conf_get("sysmon.large_heap", Conf)}, diff --git a/src/emqttd.app.src b/src/emqttd.app.src deleted file mode 100644 index 0b85fe0f0..000000000 --- a/src/emqttd.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application,emqttd, - [{description,"Erlang MQTT Broker"}, - {vsn,"2.3"}, - {modules,[]}, - {registered,[emqttd_sup]}, - {applications,[kernel,stdlib,gproc,lager,esockd,mochiweb, - lager_syslog,pbkdf2,bcrypt]}, - {env,[]}, - {mod,{emqttd_app,[]}}, - {maintainers,["Feng Lee "]}, - {licenses,["Apache-2.0"]}, - {links,[{"Github","https://github.com/emqtt/emqttd"}]}]}. diff --git a/src/emqttd.erl b/src/emqttd.erl deleted file mode 100644 index d4cdd8437..000000000 --- a/src/emqttd.erl +++ /dev/null @@ -1,187 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - -%% @doc EMQ Main Module. - --module(emqttd). - --author("Feng Lee "). - --include("emqttd.hrl"). - --include("emqttd_protocol.hrl"). - --export([start/0, env/1, env/2, is_running/1, stop/0]). - -%% PubSub API --export([subscribe/1, subscribe/2, subscribe/3, publish/1, - unsubscribe/1, unsubscribe/2]). - -%% PubSub Management API --export([setqos/3, topics/0, subscriptions/1, subscribers/1, - is_subscribed/2, subscriber_down/1]). - -%% Hooks API --export([hook/4, hook/3, unhook/2, run_hooks/2, run_hooks/3]). - -%% Debug API --export([dump/0]). - -%% Shutdown and reboot --export([shutdown/0, shutdown/1, reboot/0]). - --type(subscriber() :: pid() | binary()). - --type(suboption() :: local | {qos, non_neg_integer()} | {share, {'$queue' | binary()}}). - --type(pubsub_error() :: {error, {already_subscribed, binary()} - | {subscription_not_found, binary()}}). - --export_type([subscriber/0, suboption/0, pubsub_error/0]). - --define(APP, ?MODULE). - -%%-------------------------------------------------------------------- -%% Bootstrap, environment, configuration, is_running... -%%-------------------------------------------------------------------- - -%% @doc Start emqttd application. --spec(start() -> ok | {error, any()}). -start() -> application:start(?APP). - -%% @doc Stop emqttd application. --spec(stop() -> ok | {error, any()}). -stop() -> application:stop(?APP). - -%% @doc Environment --spec(env(Key:: atom()) -> {ok, any()} | undefined). -env(Key) -> application:get_env(?APP, Key). - -%% @doc Get environment --spec(env(Key:: atom(), Default:: any()) -> undefined | any()). -env(Key, Default) -> application:get_env(?APP, Key, Default). - -%% @doc Is running? --spec(is_running(node()) -> boolean()). -is_running(Node) -> - case rpc:call(Node, erlang, whereis, [?APP]) of - {badrpc, _} -> false; - undefined -> false; - Pid when is_pid(Pid) -> true - end. - -%%-------------------------------------------------------------------- -%% PubSub APIs -%%-------------------------------------------------------------------- - -%% @doc Subscribe --spec(subscribe(iodata()) -> ok | {error, any()}). -subscribe(Topic) -> - subscribe(Topic, self()). - --spec(subscribe(iodata(), subscriber()) -> ok | {error, any()}). -subscribe(Topic, Subscriber) -> - subscribe(Topic, Subscriber, []). - --spec(subscribe(iodata(), subscriber(), [suboption()]) -> ok | pubsub_error()). -subscribe(Topic, Subscriber, Options) -> - emqttd_server:subscribe(iolist_to_binary(Topic), Subscriber, Options). - -%% @doc Publish MQTT Message --spec(publish(mqtt_message()) -> {ok, mqtt_delivery()} | ignore). -publish(Msg) -> - emqttd_server:publish(Msg). - -%% @doc Unsubscribe --spec(unsubscribe(iodata()) -> ok | pubsub_error()). -unsubscribe(Topic) -> - unsubscribe(Topic, self()). - --spec(unsubscribe(iodata(), subscriber()) -> ok | pubsub_error()). -unsubscribe(Topic, Subscriber) -> - emqttd_server:unsubscribe(iolist_to_binary(Topic), Subscriber). - --spec(setqos(binary(), subscriber(), mqtt_qos()) -> ok). -setqos(Topic, Subscriber, Qos) -> - emqttd_server:setqos(iolist_to_binary(Topic), Subscriber, Qos). - --spec(topics() -> [binary()]). -topics() -> emqttd_router:topics(). - --spec(subscribers(iodata()) -> list(subscriber())). -subscribers(Topic) -> - emqttd_server:subscribers(iolist_to_binary(Topic)). - --spec(subscriptions(subscriber()) -> [{binary(), binary(), list(suboption())}]). -subscriptions(Subscriber) -> - emqttd_server:subscriptions(Subscriber). - --spec(is_subscribed(iodata(), subscriber()) -> boolean()). -is_subscribed(Topic, Subscriber) -> - emqttd_server:is_subscribed(iolist_to_binary(Topic), Subscriber). - --spec(subscriber_down(subscriber()) -> ok). -subscriber_down(Subscriber) -> - emqttd_server:subscriber_down(Subscriber). - -%%-------------------------------------------------------------------- -%% Hooks API -%%-------------------------------------------------------------------- - --spec(hook(atom(), function() | {emqttd_hooks:hooktag(), function()}, list(any())) - -> ok | {error, any()}). -hook(Hook, TagFunction, InitArgs) -> - emqttd_hooks:add(Hook, TagFunction, InitArgs). - --spec(hook(atom(), function() | {emqttd_hooks:hooktag(), function()}, list(any()), integer()) - -> ok | {error, any()}). -hook(Hook, TagFunction, InitArgs, Priority) -> - emqttd_hooks:add(Hook, TagFunction, InitArgs, Priority). - --spec(unhook(atom(), function() | {emqttd_hooks:hooktag(), function()}) - -> ok | {error, any()}). -unhook(Hook, TagFunction) -> - emqttd_hooks:delete(Hook, TagFunction). - --spec(run_hooks(atom(), list(any())) -> ok | stop). -run_hooks(Hook, Args) -> - emqttd_hooks:run(Hook, Args). - --spec(run_hooks(atom(), list(any()), any()) -> {ok | stop, any()}). -run_hooks(Hook, Args, Acc) -> - emqttd_hooks:run(Hook, Args, Acc). - -%%-------------------------------------------------------------------- -%% Shutdown and reboot -%%-------------------------------------------------------------------- - -shutdown() -> - shutdown(normal). - -shutdown(Reason) -> - lager:error("EMQ shutdown for ~s", [Reason]), - emqttd_plugins:unload(), - lists:foreach(fun application:stop/1, [emqttd, ekka, mochiweb, esockd, gproc]). - -reboot() -> - lists:foreach(fun application:start/1, [gproc, esockd, mochiweb, ekka, emqttd]). - -%%-------------------------------------------------------------------- -%% Debug -%%-------------------------------------------------------------------- - -dump() -> lists:append([emqttd_server:dump(), emqttd_router:dump()]). - diff --git a/src/emqttd_app.erl b/src/emqttd_app.erl deleted file mode 100644 index 1e99cb951..000000000 --- a/src/emqttd_app.erl +++ /dev/null @@ -1,242 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqttd_app). - --behaviour(application). - --author("Feng Lee "). - --include("emqttd_cli.hrl"). - --include("emqttd_protocol.hrl"). - -%% Application callbacks --export([start/2, stop/1]). - --export([start_listener/1, stop_listener/1, restart_listener/1]). - --type(listener() :: {atom(), esockd:listen_on(), [esockd:option()]}). - --define(APP, emqttd). - -%%-------------------------------------------------------------------- -%% Application Callbacks -%%-------------------------------------------------------------------- - -start(_Type, _Args) -> - print_banner(), - ekka:start(), - {ok, Sup} = emqttd_sup:start_link(), - start_servers(Sup), - emqttd_cli:load(), - register_acl_mod(), - start_autocluster(), - register(emqttd, self()), - print_vsn(), - {ok, Sup}. - --spec(stop(State :: term()) -> term()). -stop(_State) -> - catch stop_listeners(). - -%%-------------------------------------------------------------------- -%% Print Banner -%%-------------------------------------------------------------------- - -print_banner() -> - ?PRINT("starting ~s on node '~s'~n", [?APP, node()]). - -print_vsn() -> - {ok, Vsn} = application:get_key(vsn), - ?PRINT("~s ~s is running now~n", [?APP, Vsn]). - -%%-------------------------------------------------------------------- -%% Start Servers -%%-------------------------------------------------------------------- - -start_servers(Sup) -> - Servers = [{"emqttd ctl", emqttd_ctl}, - {"emqttd hook", emqttd_hooks}, - {"emqttd router", emqttd_router}, - {"emqttd pubsub", {supervisor, emqttd_pubsub_sup}}, - {"emqttd stats", emqttd_stats}, - {"emqttd metrics", emqttd_metrics}, - {"emqttd pooler", {supervisor, emqttd_pooler}}, - {"emqttd trace", {supervisor, emqttd_trace_sup}}, - {"emqttd client manager", {supervisor, emqttd_cm_sup}}, - {"emqttd session manager", {supervisor, emqttd_sm_sup}}, - {"emqttd session supervisor", {supervisor, emqttd_session_sup}}, - {"emqttd wsclient supervisor", {supervisor, emqttd_ws_client_sup}}, - {"emqttd broker", emqttd_broker}, - {"emqttd alarm", emqttd_alarm}, - {"emqttd mod supervisor", emqttd_mod_sup}, - {"emqttd bridge supervisor", {supervisor, emqttd_bridge_sup_sup}}, - {"emqttd access control", emqttd_access_control}, - {"emqttd system monitor", {supervisor, emqttd_sysmon_sup}}], - [start_server(Sup, Server) || Server <- Servers]. - -start_server(_Sup, {Name, F}) when is_function(F) -> - ?PRINT("~s is starting...", [Name]), - F(), - ?PRINT_MSG("[ok]~n"); - -start_server(Sup, {Name, Server}) -> - ?PRINT("~s is starting...", [Name]), - start_child(Sup, Server), - ?PRINT_MSG("[ok]~n"); - -start_server(Sup, {Name, Server, Opts}) -> - ?PRINT("~s is starting...", [ Name]), - start_child(Sup, Server, Opts), - ?PRINT_MSG("[ok]~n"). - -start_child(Sup, {supervisor, Module}) -> - supervisor:start_child(Sup, supervisor_spec(Module)); - -start_child(Sup, Module) when is_atom(Module) -> - {ok, _ChiId} = supervisor:start_child(Sup, worker_spec(Module)). - -start_child(Sup, {supervisor, Module}, Opts) -> - supervisor:start_child(Sup, supervisor_spec(Module, Opts)); - -start_child(Sup, Module, Opts) when is_atom(Module) -> - supervisor:start_child(Sup, worker_spec(Module, Opts)). - -supervisor_spec(Module) when is_atom(Module) -> - supervisor_spec(Module, start_link, []). - -supervisor_spec(Module, Opts) -> - supervisor_spec(Module, start_link, [Opts]). - -supervisor_spec(M, F, A) -> - {M, {M, F, A}, permanent, infinity, supervisor, [M]}. - -worker_spec(Module) when is_atom(Module) -> - worker_spec(Module, start_link, []). - -worker_spec(Module, Opts) when is_atom(Module) -> - worker_spec(Module, start_link, [Opts]). - -worker_spec(M, F, A) -> - {M, {M, F, A}, permanent, 10000, worker, [M]}. - -%%-------------------------------------------------------------------- -%% Register default ACL File -%%-------------------------------------------------------------------- - -register_acl_mod() -> - case emqttd:env(acl_file) of - {ok, File} -> emqttd_access_control:register_mod(acl, emqttd_acl_internal, [File]); - undefined -> ok - end. - -%%-------------------------------------------------------------------- -%% Autocluster -%%-------------------------------------------------------------------- - -start_autocluster() -> - ekka:callback(prepare, fun emqttd:shutdown/1), - ekka:callback(reboot, fun emqttd:reboot/0), - ekka:autocluster(?APP, fun after_autocluster/0). - -after_autocluster() -> - emqttd_plugins:init(), - emqttd_plugins:load(), - start_listeners(). - -%%-------------------------------------------------------------------- -%% Start Listeners -%%-------------------------------------------------------------------- - -%% @doc Start Listeners of the broker. --spec(start_listeners() -> any()). -start_listeners() -> lists:foreach(fun start_listener/1, emqttd:env(listeners, [])). - -%% Start mqtt listener --spec(start_listener(listener()) -> any()). -start_listener({tcp, ListenOn, Opts}) -> - start_listener('mqtt:tcp', ListenOn, Opts); - -%% Start mqtt(SSL) listener -start_listener({ssl, ListenOn, Opts}) -> - start_listener('mqtt:ssl', ListenOn, Opts); - -%% Start http listener -start_listener({Proto, ListenOn, Opts}) when Proto == http; Proto == ws -> - mochiweb:start_http('mqtt:ws', ListenOn, Opts, {emqttd_ws, handle_request, []}); - -%% Start https listener -start_listener({Proto, ListenOn, Opts}) when Proto == https; Proto == wss -> - mochiweb:start_http('mqtt:wss', ListenOn, Opts, {emqttd_ws, handle_request, []}); - -start_listener({Proto, ListenOn, Opts}) when Proto == api -> - mochiweb:start_http('mqtt:api', ListenOn, Opts, emqttd_http:http_handler()). - -start_listener(Proto, ListenOn, Opts) -> - Env = lists:append(emqttd:env(client, []), emqttd:env(protocol, [])), - MFArgs = {emqttd_client, start_link, [Env]}, - {ok, _} = esockd:open(Proto, ListenOn, merge_sockopts(Opts), MFArgs). - -merge_sockopts(Options) -> - SockOpts = emqttd_misc:merge_opts( - ?MQTT_SOCKOPTS, proplists:get_value(sockopts, Options, [])), - emqttd_misc:merge_opts(Options, [{sockopts, SockOpts}]). - -%%-------------------------------------------------------------------- -%% Stop Listeners -%%-------------------------------------------------------------------- - -%% @doc Stop Listeners -stop_listeners() -> lists:foreach(fun stop_listener/1, emqttd:env(listeners, [])). - -%% @private -stop_listener({tcp, ListenOn, _Opts}) -> - esockd:close('mqtt:tcp', ListenOn); -stop_listener({ssl, ListenOn, _Opts}) -> - esockd:close('mqtt:ssl', ListenOn); -stop_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws -> - mochiweb:stop_http('mqtt:ws', ListenOn); -stop_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss -> - mochiweb:stop_http('mqtt:wss', ListenOn); -stop_listener({Proto, ListenOn, _Opts}) when Proto == api -> - mochiweb:stop_http('mqtt:api', ListenOn); -stop_listener({Proto, ListenOn, _Opts}) -> - esockd:close(Proto, ListenOn). - -%% @doc Restart Listeners -restart_listener({tcp, ListenOn, _Opts}) -> - esockd:reopen('mqtt:tcp', ListenOn); -restart_listener({ssl, ListenOn, _Opts}) -> - esockd:reopen('mqtt:ssl', ListenOn); -restart_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws -> - mochiweb:restart_http('mqtt:ws', ListenOn); -restart_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss -> - mochiweb:restart_http('mqtt:wss', ListenOn); -restart_listener({Proto, ListenOn, _Opts}) when Proto == api -> - mochiweb:restart_http('mqtt:api', ListenOn); -restart_listener({Proto, ListenOn, _Opts}) -> - esockd:reopen(Proto, ListenOn). - - --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). -merge_sockopts_test_() -> - Opts = [{acceptors, 16}, {max_clients, 512}], - ?_assert(merge_sockopts(Opts) == [{sockopts, ?MQTT_SOCKOPTS} | Opts]). - --endif. - diff --git a/src/emqttd_sup.erl b/src/emqttd_sup.erl deleted file mode 100644 index e38d20d65..000000000 --- a/src/emqttd_sup.erl +++ /dev/null @@ -1,55 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqttd_sup). - --behaviour(supervisor). - --author("Feng Lee "). - --include("emqttd.hrl"). - -%% API --export([start_link/0, start_child/1, start_child/2]). - -%% Supervisor callbacks --export([init/1]). - -%% Helper macro for declaring children of supervisor --define(CHILD(Mod, Type), {Mod, {Mod, start_link, []}, - permanent, 5000, Type, [Mod]}). - -%%-------------------------------------------------------------------- -%% API -%%-------------------------------------------------------------------- - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -start_child(ChildSpec) when is_tuple(ChildSpec) -> - supervisor:start_child(?MODULE, ChildSpec). - --spec(start_child(Mod::atom(), Type :: worker | supervisor) -> {ok, pid()}). -start_child(Mod, Type) when is_atom(Mod) and is_atom(Type) -> - supervisor:start_child(?MODULE, ?CHILD(Mod, Type)). - -%%-------------------------------------------------------------------- -%% Supervisor callbacks -%%-------------------------------------------------------------------- - -init([]) -> - {ok, {{one_for_all, 0, 1}, []}}. - diff --git a/src/emqx.erl b/src/emqx.erl new file mode 100644 index 000000000..66c368cf3 --- /dev/null +++ b/src/emqx.erl @@ -0,0 +1,279 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +%% @doc EMQ X Main Module. + +-module(emqx). + +-author("Feng Lee "). + +-include("emqx.hrl"). + +-include("emqx_mqtt.hrl"). + +%% Start/Stop Application +-export([start/0, env/1, env/2, is_running/1, stop/0]). + +%% Start/Stop Listeners +-export([start_listeners/0, start_listener/1, listeners/0, + stop_listeners/0, stop_listener/1, + restart_listeners/0, restart_listener/1]). + +%% PubSub API +-export([subscribe/1, subscribe/2, subscribe/3, publish/1, + unsubscribe/1, unsubscribe/2]). + +%% PubSub Management API +-export([setqos/3, topics/0, subscriptions/1, subscribers/1, + is_subscribed/2, subscriber_down/1]). + +%% Hooks API +-export([hook/4, hook/3, unhook/2, run_hooks/2, run_hooks/3]). + +%% Debug API +-export([dump/0]). + +%% Shutdown and reboot +-export([shutdown/0, shutdown/1, reboot/0]). + +-type(listener() :: {atom(), esockd:listen_on(), [esockd:option()]}). + +-type(subscriber() :: pid() | binary()). + +-type(suboption() :: local | {qos, non_neg_integer()} | {share, {'$queue' | binary()}}). + +-export_type([subscriber/0, suboption/0]). + +-define(APP, ?MODULE). + +%%-------------------------------------------------------------------- +%% Bootstrap, environment, configuration, is_running... +%%-------------------------------------------------------------------- + +%% @doc Start emqx application. +-spec(start() -> ok | {error, any()}). +start() -> application:start(?APP). + +%% @doc Stop emqx application. +-spec(stop() -> ok | {error, any()}). +stop() -> application:stop(?APP). + +%% @doc Get Environment +-spec(env(Key:: atom()) -> {ok, any()} | undefined). +env(Key) -> application:get_env(?APP, Key). + +%% @doc Get environment with default +-spec(env(Key:: atom(), Default:: any()) -> undefined | any()). +env(Key, Default) -> application:get_env(?APP, Key, Default). + +%% @doc Is running? +-spec(is_running(node()) -> boolean()). +is_running(Node) -> + case rpc:call(Node, erlang, whereis, [?APP]) of + {badrpc, _} -> false; + undefined -> false; + Pid when is_pid(Pid) -> true + end. + +%%-------------------------------------------------------------------- +%% Start/Stop Listeners +%%-------------------------------------------------------------------- + +%% @doc Start Listeners. +-spec(start_listeners() -> ok). +start_listeners() -> lists:foreach(fun start_listener/1, env(listeners, [])). + +%% Start mqtt listener +-spec(start_listener(listener()) -> {ok, pid()} | {error, any()}). +start_listener({tcp, ListenOn, Opts}) -> + start_listener('mqtt:tcp', ListenOn, Opts); + +%% Start mqtt(SSL) listener +start_listener({ssl, ListenOn, Opts}) -> + start_listener('mqtt:ssl', ListenOn, Opts); + +%% Start http listener +start_listener({Proto, ListenOn, Opts}) when Proto == http; Proto == ws -> + {ok, _} = mochiweb:start_http('mqtt:ws', ListenOn, Opts, {emqx_ws, handle_request, []}); + +%% Start https listener +start_listener({Proto, ListenOn, Opts}) when Proto == https; Proto == wss -> + {ok, _} = mochiweb:start_http('mqtt:wss', ListenOn, Opts, {emqx_ws, handle_request, []}); + +start_listener({Proto, ListenOn, Opts}) when Proto == api -> + {ok, _} = mochiweb:start_http('mqtt:api', ListenOn, Opts, emqx_http:http_handler()). + +start_listener(Proto, ListenOn, Opts) -> + Env = lists:append(emqx:env(client, []), emqx:env(protocol, [])), + MFArgs = {emqx_client, start_link, [Env]}, + {ok, _} = esockd:open(Proto, ListenOn, merge_sockopts(Opts), MFArgs). + +listeners() -> + [Listener || Listener = {{Proto, _}, _Pid} <- esockd:listeners(), is_mqtt(Proto)]. + +is_mqtt('mqtt:tcp') -> true; +is_mqtt('mqtt:ssl') -> true; +is_mqtt('mqtt:ws') -> true; +is_mqtt('mqtt:wss') -> true; +is_mqtt(_Proto) -> false. + +%% @doc Stop Listeners +-spec(stop_listeners() -> ok). +stop_listeners() -> lists:foreach(fun stop_listener/1, env(listeners, [])). + +-spec(stop_listener(listener()) -> ok | {error, any()}). +stop_listener({tcp, ListenOn, _Opts}) -> + esockd:close('mqtt:tcp', ListenOn); +stop_listener({ssl, ListenOn, _Opts}) -> + esockd:close('mqtt:ssl', ListenOn); +stop_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws -> + mochiweb:stop_http('mqtt:ws', ListenOn); +stop_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss -> + mochiweb:stop_http('mqtt:wss', ListenOn); +stop_listener({Proto, ListenOn, _Opts}) when Proto == api -> + mochiweb:stop_http('mqtt:api', ListenOn); +stop_listener({Proto, ListenOn, _Opts}) -> + esockd:close(Proto, ListenOn). + +%% @doc Restart Listeners +-spec(restart_listeners() -> ok). +restart_listeners() -> lists:foreach(fun restart_listener/1, env(listeners, [])). + +-spec(restart_listener(listener()) -> any()). +restart_listener({tcp, ListenOn, _Opts}) -> + esockd:reopen('mqtt:tcp', ListenOn); +restart_listener({ssl, ListenOn, _Opts}) -> + esockd:reopen('mqtt:ssl', ListenOn); +restart_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws -> + mochiweb:restart_http('mqtt:ws', ListenOn); +restart_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss -> + mochiweb:restart_http('mqtt:wss', ListenOn); +restart_listener({Proto, ListenOn, _Opts}) when Proto == api -> + mochiweb:restart_http('mqtt:api', ListenOn); +restart_listener({Proto, ListenOn, _Opts}) -> + esockd:reopen(Proto, ListenOn). + +merge_sockopts(Options) -> + SockOpts = emqx_misc:merge_opts( + ?MQTT_SOCKOPTS, proplists:get_value(sockopts, Options, [])), + emqx_misc:merge_opts(Options, [{sockopts, SockOpts}]). + +%%-------------------------------------------------------------------- +%% PubSub APIs +%%-------------------------------------------------------------------- + +%% @doc Subscribe +-spec(subscribe(iodata()) -> ok | {error, any()}). +subscribe(Topic) -> + subscribe(Topic, self()). + +-spec(subscribe(iodata(), subscriber()) -> ok | {error, any()}). +subscribe(Topic, Subscriber) -> + subscribe(Topic, Subscriber, []). + +-spec(subscribe(iodata(), subscriber(), [suboption()]) -> ok | {error, term()}). +subscribe(Topic, Subscriber, Options) -> + emqx_server:subscribe(iolist_to_binary(Topic), Subscriber, Options). + +%% @doc Publish MQTT Message +-spec(publish(mqtt_message()) -> {ok, mqtt_delivery()} | ignore). +publish(Msg) -> + emqx_server:publish(Msg). + +%% @doc Unsubscribe +-spec(unsubscribe(iodata()) -> ok | {error, term()}). +unsubscribe(Topic) -> + unsubscribe(Topic, self()). + +-spec(unsubscribe(iodata(), subscriber()) -> ok | {error, term()}). +unsubscribe(Topic, Subscriber) -> + emqx_server:unsubscribe(iolist_to_binary(Topic), Subscriber). + +%%-------------------------------------------------------------------- +%% PubSub Management API +%%-------------------------------------------------------------------- + +-spec(setqos(binary(), subscriber(), mqtt_qos()) -> ok). +setqos(Topic, Subscriber, Qos) -> + emqx_server:setqos(iolist_to_binary(Topic), Subscriber, Qos). + +-spec(topics() -> [binary()]). +topics() -> emqx_router:topics(). + +-spec(subscribers(iodata()) -> list(subscriber())). +subscribers(Topic) -> + emqx_server:subscribers(iolist_to_binary(Topic)). + +-spec(subscriptions(subscriber()) -> [{binary(), binary(), list(suboption())}]). +subscriptions(Subscriber) -> + emqx_server:subscriptions(Subscriber). + +-spec(is_subscribed(iodata(), subscriber()) -> boolean()). +is_subscribed(Topic, Subscriber) -> + emqx_server:is_subscribed(iolist_to_binary(Topic), Subscriber). + +-spec(subscriber_down(subscriber()) -> ok). +subscriber_down(Subscriber) -> + emqx_server:subscriber_down(Subscriber). + +%%-------------------------------------------------------------------- +%% Hooks API +%%-------------------------------------------------------------------- + +-spec(hook(atom(), function() | {emqx_hooks:hooktag(), function()}, list(any())) + -> ok | {error, any()}). +hook(Hook, TagFunction, InitArgs) -> + emqx_hooks:add(Hook, TagFunction, InitArgs). + +-spec(hook(atom(), function() | {emqx_hooks:hooktag(), function()}, list(any()), integer()) + -> ok | {error, any()}). +hook(Hook, TagFunction, InitArgs, Priority) -> + emqx_hooks:add(Hook, TagFunction, InitArgs, Priority). + +-spec(unhook(atom(), function() | {emqx_hooks:hooktag(), function()}) + -> ok | {error, any()}). +unhook(Hook, TagFunction) -> + emqx_hooks:delete(Hook, TagFunction). + +-spec(run_hooks(atom(), list(any())) -> ok | stop). +run_hooks(Hook, Args) -> + emqx_hooks:run(Hook, Args). + +-spec(run_hooks(atom(), list(any()), any()) -> {ok | stop, any()}). +run_hooks(Hook, Args, Acc) -> + emqx_hooks:run(Hook, Args, Acc). + +%%-------------------------------------------------------------------- +%% Shutdown and reboot +%%-------------------------------------------------------------------- + +shutdown() -> + shutdown(normal). + +shutdown(Reason) -> + lager:error("EMQ shutdown for ~s", [Reason]), + emqx_plugins:unload(), + lists:foreach(fun application:stop/1, [emqx, ekka, mochiweb, esockd, gproc]). + +reboot() -> + lists:foreach(fun application:start/1, [gproc, esockd, mochiweb, ekka, emqx]). + +%%-------------------------------------------------------------------- +%% Debug +%%-------------------------------------------------------------------- + +dump() -> lists:append([emqx_server:dump(), emqx_router:dump()]). + diff --git a/src/emqttd_access_control.erl b/src/emqx_access_control.erl similarity index 97% rename from src/emqttd_access_control.erl rename to src/emqx_access_control.erl index 6cfcc03cf..2515689fa 100644 --- a/src/emqttd_access_control.erl +++ b/src/emqx_access_control.erl @@ -14,13 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_access_control). +-module(emqx_access_control). -behaviour(gen_server). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). %% API Function Exports -export([start_link/0, auth/2, check_acl/3, reload_acl/0, lookup_mods/1, @@ -52,7 +52,7 @@ start_link() -> auth(Client, Password) when is_record(Client, mqtt_client) -> auth(Client, Password, lookup_mods(auth)). auth(_Client, _Password, []) -> - case emqttd:env(allow_anonymous, false) of + case emqx:env(allow_anonymous, false) of true -> ok; false -> {error, "No auth module to check!"} end; @@ -74,7 +74,7 @@ check_acl(Client, PubSub, Topic) when ?PS(PubSub) -> check_acl(Client, PubSub, Topic, lookup_mods(acl)). check_acl(_Client, _PubSub, _Topic, []) -> - emqttd:env(acl_nomatch, allow); + emqx:env(acl_nomatch, allow); check_acl(Client, PubSub, Topic, [{Mod, State, _Seq}|AclMods]) -> case Mod:check_acl({Client, PubSub, Topic}, State) of allow -> allow; diff --git a/src/emqttd_access_rule.erl b/src/emqx_access_rule.erl similarity index 94% rename from src/emqttd_access_rule.erl rename to src/emqx_access_rule.erl index 73718fd3a..294ba06ab 100644 --- a/src/emqttd_access_rule.erl +++ b/src/emqx_access_rule.erl @@ -14,12 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_access_rule). +-module(emqx_access_rule). -author("Feng Lee "). --include("emqttd.hrl"). - +-include("emqx.hrl"). -type(who() :: all | binary() | {ipaddr, esockd_cidr:cidr_string()} | @@ -69,9 +68,9 @@ compile(who, {'or', Conds}) when is_list(Conds) -> {'or', [compile(who, Cond) || Cond <- Conds]}; compile(topic, {eq, Topic}) -> - {eq, emqttd_topic:words(bin(Topic))}; + {eq, emqx_topic:words(bin(Topic))}; compile(topic, Topic) -> - Words = emqttd_topic:words(bin(Topic)), + Words = emqx_topic:words(bin(Topic)), case 'pattern?'(Words) of true -> {pattern, Words}; false -> Words @@ -126,12 +125,12 @@ match_topics(_Client, _Topic, []) -> false; match_topics(Client, Topic, [{pattern, PatternFilter}|Filters]) -> TopicFilter = feed_var(Client, PatternFilter), - case match_topic(emqttd_topic:words(Topic), TopicFilter) of + case match_topic(emqx_topic:words(Topic), TopicFilter) of true -> true; false -> match_topics(Client, Topic, Filters) end; match_topics(Client, Topic, [TopicFilter|Filters]) -> - case match_topic(emqttd_topic:words(Topic), TopicFilter) of + case match_topic(emqx_topic:words(Topic), TopicFilter) of true -> true; false -> match_topics(Client, Topic, Filters) end. @@ -139,7 +138,7 @@ match_topics(Client, Topic, [TopicFilter|Filters]) -> match_topic(Topic, {eq, TopicFilter}) -> Topic =:= TopicFilter; match_topic(Topic, TopicFilter) -> - emqttd_topic:match(Topic, TopicFilter). + emqx_topic:match(Topic, TopicFilter). feed_var(Client, Pattern) -> feed_var(Client, Pattern, []). diff --git a/src/emqttd_acl_internal.erl b/src/emqx_acl_internal.erl similarity index 92% rename from src/emqttd_acl_internal.erl rename to src/emqx_acl_internal.erl index 5305985c4..3b146eb38 100644 --- a/src/emqttd_acl_internal.erl +++ b/src/emqx_acl_internal.erl @@ -14,14 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_acl_internal). +-module(emqx_acl_internal). --behaviour(emqttd_acl_mod). +-behaviour(emqx_acl_mod). -author("Feng Lee "). --include("emqttd.hrl"). --include("emqttd_cli.hrl"). +-include("emqx.hrl"). + +-include("emqx_cli.hrl"). -export([all_rules/0]). @@ -37,7 +38,7 @@ %%-------------------------------------------------------------------- %% @doc Read all rules --spec(all_rules() -> list(emqttd_access_rule:rule())). +-spec(all_rules() -> list(emqx_access_rule:rule())). all_rules() -> case ets:lookup(?ACL_RULE_TAB, all_rules) of [] -> []; @@ -58,7 +59,7 @@ init([File]) -> load_rules_from_file(#state{config = AclFile}) -> {ok, Terms} = file:consult(AclFile), - Rules = [emqttd_access_rule:compile(Term) || Term <- Terms], + Rules = [emqx_access_rule:compile(Term) || Term <- Terms], lists:foreach(fun(PubSub) -> ets:insert(?ACL_RULE_TAB, {PubSub, lists:filter(fun(Rule) -> filter(PubSub, Rule) end, Rules)}) @@ -103,7 +104,7 @@ match(_Client, _Topic, []) -> nomatch; match(Client, Topic, [Rule|Rules]) -> - case emqttd_access_rule:match(Client, Topic, Rule) of + case emqx_access_rule:match(Client, Topic, Rule) of nomatch -> match(Client, Topic, Rules); {matched, AllowDeny} -> {matched, AllowDeny} end. diff --git a/src/emqttd_acl_mod.erl b/src/emqx_acl_mod.erl similarity index 96% rename from src/emqttd_acl_mod.erl rename to src/emqx_acl_mod.erl index 12e949afe..6ce338209 100644 --- a/src/emqttd_acl_mod.erl +++ b/src/emqx_acl_mod.erl @@ -14,11 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_acl_mod). +-module(emqx_acl_mod). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). %%-------------------------------------------------------------------- %% ACL behavihour diff --git a/src/emqttd_alarm.erl b/src/emqx_alarm.erl similarity index 87% rename from src/emqttd_alarm.erl rename to src/emqx_alarm.erl index 1467797c7..e0c99dc00 100644 --- a/src/emqttd_alarm.erl +++ b/src/emqx_alarm.erl @@ -14,13 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_alarm). +-module(emqx_alarm). -author("Feng Lee "). -behaviour(gen_event). --include("emqttd.hrl"). +-include("emqx.hrl"). -define(ALARM_MGR, ?MODULE). @@ -82,7 +82,7 @@ delete_alarm_handler(Module) when is_atom(Module) -> %%-------------------------------------------------------------------- init(_) -> {ok, []}. - + handle_event({set_alarm, Alarm = #mqtt_alarm{id = AlarmId, severity = Severity, title = Title, @@ -92,13 +92,13 @@ handle_event({set_alarm, Alarm = #mqtt_alarm{id = AlarmId, {severity, Severity}, {title, iolist_to_binary(Title)}, {summary, iolist_to_binary(Summary)}, - {ts, emqttd_time:now_secs(TS)}]), - emqttd:publish(alarm_msg(alert, AlarmId, Json)), + {ts, emqx_time:now_secs(TS)}]), + emqx:publish(alarm_msg(alert, AlarmId, Json)), {ok, [Alarm#mqtt_alarm{timestamp = TS} | Alarms]}; handle_event({clear_alarm, AlarmId}, Alarms) -> - Json = mochijson2:encode([{id, AlarmId}, {ts, emqttd_time:now_secs()}]), - emqttd:publish(alarm_msg(clear, AlarmId, Json)), + Json = mochijson2:encode([{id, AlarmId}, {ts, emqx_time:now_secs()}]), + emqx:publish(alarm_msg(clear, AlarmId, Json)), {ok, lists:keydelete(AlarmId, 2, Alarms), hibernate}; handle_event(_, Alarms)-> @@ -127,14 +127,12 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- alarm_msg(Type, AlarmId, Json) -> - Msg = emqttd_message:make(alarm, - topic(Type, AlarmId), - iolist_to_binary(Json)), - emqttd_message:set_flag(sys, Msg). + Msg = emqx_message:make(alarm, topic(Type, AlarmId), iolist_to_binary(Json)), + emqx_message:set_flag(sys, Msg). topic(alert, AlarmId) -> - emqttd_topic:systop(<<"alarms/", AlarmId/binary, "/alert">>); + emqx_topic:systop(<<"alarms/", AlarmId/binary, "/alert">>); topic(clear, AlarmId) -> - emqttd_topic:systop(<<"alarms/", AlarmId/binary, "/clear">>). + emqx_topic:systop(<<"alarms/", AlarmId/binary, "/clear">>). diff --git a/src/emqx_app.erl b/src/emqx_app.erl new file mode 100644 index 000000000..a3066f7de --- /dev/null +++ b/src/emqx_app.erl @@ -0,0 +1,85 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_app). + +-behaviour(application). + +-author("Feng Lee "). + +-include("emqx_cli.hrl"). + +-include("emqx_mqtt.hrl"). + +%% Application callbacks +-export([start/2, stop/1]). + +-define(APP, emqx). + +%%-------------------------------------------------------------------- +%% Application Callbacks +%%-------------------------------------------------------------------- + +start(_Type, _Args) -> + print_banner(), + ekka:start(), + {ok, Sup} = emqx_sup:start_link(), + ok = emqx_cli:load(), + ok = register_acl_mod(), + start_autocluster(), + register(emqx, self()), + print_vsn(), + {ok, Sup}. + +-spec(stop(State :: term()) -> term()). +stop(_State) -> + catch emqx:stop_listeners(). + +%%-------------------------------------------------------------------- +%% Print Banner +%%-------------------------------------------------------------------- + +print_banner() -> + ?PRINT("Starting ~s on node ~s~n", [?APP, node()]). + +print_vsn() -> + {ok, Vsn} = application:get_key(vsn), + ?PRINT("~s ~s is running now!~n", [?APP, Vsn]). + +%%-------------------------------------------------------------------- +%% Register default ACL File +%%-------------------------------------------------------------------- + +register_acl_mod() -> + case emqx:env(acl_file) of + {ok, File} -> emqx_access_control:register_mod(acl, emqx_acl_internal, [File]); + undefined -> ok + end. + +%%-------------------------------------------------------------------- +%% Autocluster +%%-------------------------------------------------------------------- + +start_autocluster() -> + ekka:callback(prepare, fun emqx:shutdown/1), + ekka:callback(reboot, fun emqx:reboot/0), + ekka:autocluster(?APP, fun after_autocluster/0). + +after_autocluster() -> + emqx_plugins:init(), + emqx_plugins:load(), + emqx:start_listeners(). + diff --git a/src/emqttd_auth_mod.erl b/src/emqx_auth_mod.erl similarity index 94% rename from src/emqttd_auth_mod.erl rename to src/emqx_auth_mod.erl index c94578c46..ca6219c90 100644 --- a/src/emqttd_auth_mod.erl +++ b/src/emqx_auth_mod.erl @@ -14,11 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_auth_mod). +-module(emqx_auth_mod). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). -export([passwd_hash/2]). @@ -35,7 +35,7 @@ -callback(check(Client :: mqtt_client(), Password :: binary(), State :: any()) - -> ok | | {ok, boolean()} | ignore | {error, string()}). + -> ok | {ok, boolean()} | ignore | {error, string()}). -callback(description() -> string()). @@ -63,12 +63,12 @@ passwd_hash(sha256, Password) -> passwd_hash(pbkdf2, {Salt, Password, Macfun, Iterations, Dklen}) -> case pbkdf2:pbkdf2(Macfun, Password, Salt, Iterations, Dklen) of {ok, Hexstring} -> pbkdf2:to_hex(Hexstring); - {error, Error} -> lager:error("PasswdHash with pbkdf2 error:~p", [Error]), error + {error, Error} -> lager:error("PasswdHash with pbkdf2 error:~p", [Error]), <<>> end; passwd_hash(bcrypt, {Salt, Password}) -> case bcrypt:hashpw(Password, Salt) of {ok, HashPassword} -> list_to_binary(HashPassword); - {error, Error}-> lager:error("PasswdHash with bcrypt error:~p", [Error]), error + {error, Error}-> lager:error("PasswdHash with bcrypt error:~p", [Error]), <<>> end. hexstring(<>) -> diff --git a/src/emqttd_base62.erl b/src/emqx_base62.erl similarity index 98% rename from src/emqttd_base62.erl rename to src/emqx_base62.erl index 481488fb9..58c1b7b40 100644 --- a/src/emqttd_base62.erl +++ b/src/emqx_base62.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_base62). +-module(emqx_base62). -author("Feng Lee "). diff --git a/src/emqttd_boot.erl b/src/emqx_boot.erl similarity index 99% rename from src/emqttd_boot.erl rename to src/emqx_boot.erl index d7a6d311e..fdd2e1a71 100644 --- a/src/emqttd_boot.erl +++ b/src/emqx_boot.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_boot). +-module(emqx_boot). -author("Feng Lee "). diff --git a/src/emqttd_bridge.erl b/src/emqx_bridge.erl similarity index 87% rename from src/emqttd_bridge.erl rename to src/emqx_bridge.erl index 49b5a95d0..5bdebf519 100644 --- a/src/emqttd_bridge.erl +++ b/src/emqx_bridge.erl @@ -14,17 +14,17 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_bridge). - --behaviour(gen_server2). +-module(emqx_bridge). -author("Feng Lee "). --include("emqttd.hrl"). +-behaviour(gen_server2). --include("emqttd_protocol.hrl"). +-include("emqx.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_mqtt.hrl"). + +-include("emqx_internal.hrl"). %% API Function Exports -export([start_link/5]). @@ -37,14 +37,16 @@ -record(state, {pool, id, node, subtopic, + qos = ?QOS_0, topic_suffix = <<>>, topic_prefix = <<>>, - mqueue :: emqttd_mqueue:mqueue(), + mqueue :: emqx_mqueue:mqueue(), max_queue_len = 10000, ping_down_interval = ?PING_DOWN_INTERVAL, status = up}). --type(option() :: {topic_suffix, binary()} | +-type(option() :: {qos, mqtt_qos()} | + {topic_suffix, binary()} | {topic_prefix, binary()} | {max_queue_len, pos_integer()} | {ping_down_interval, pos_integer()}). @@ -72,11 +74,11 @@ init([Pool, Id, Node, Topic, Options]) -> true -> true = erlang:monitor_node(Node, true), Share = iolist_to_binary(["$bridge:", atom_to_list(Node), ":", Topic]), - emqttd:subscribe(Topic, self(), [local, {share, Share}, {qos, ?QOS_0}]), + emqx_server:subscribe(Topic, self(), [local, {share, Share}, {qos, ?QOS_0}]), State = parse_opts(Options, #state{node = Node, subtopic = Topic}), - MQueue = emqttd_mqueue:new(qname(Node, Topic), - [{max_len, State#state.max_queue_len}], - emqttd_alarm:alarm_fun()), + MQueue = emqx_mqueue:new(qname(Node, Topic), + [{max_len, State#state.max_queue_len}], + emqx_alarm:alarm_fun()), {ok, State#state{pool = Pool, id = Id, mqueue = MQueue}, hibernate, {backoff, 1000, 1000, 10000}}; false -> @@ -85,6 +87,8 @@ init([Pool, Id, Node, Topic, Options]) -> parse_opts([], State) -> State; +parse_opts([{qos, Qos} | Opts], State) -> + parse_opts(Opts, State#state{qos = Qos}); parse_opts([{topic_suffix, Suffix} | Opts], State) -> parse_opts(Opts, State#state{topic_suffix= Suffix}); parse_opts([{topic_prefix, Prefix} | Opts], State) -> @@ -108,10 +112,10 @@ handle_cast(Msg, State) -> ?UNEXPECTED_MSG(Msg, State). handle_info({dispatch, _Topic, Msg}, State = #state{mqueue = MQ, status = down}) -> - {noreply, State#state{mqueue = emqttd_mqueue:in(Msg, MQ)}}; + {noreply, State#state{mqueue = emqx_mqueue:in(Msg, MQ)}}; handle_info({dispatch, _Topic, Msg}, State = #state{node = Node, status = up}) -> - rpc:cast(Node, emqttd, publish, [transform(Msg, State)]), + emqx_rpc:cast(Node, emqx, publish, [transform(Msg, State)]), {noreply, State, hibernate}; handle_info({nodedown, Node}, State = #state{node = Node, ping_down_interval = Interval}) -> @@ -121,7 +125,7 @@ handle_info({nodedown, Node}, State = #state{node = Node, ping_down_interval = I handle_info({nodeup, Node}, State = #state{node = Node}) -> %% TODO: Really fast?? - case emqttd:is_running(Node) of + case emqx:is_running(Node) of true -> lager:warning("Bridge Node Up: ~p", [Node]), {noreply, dequeue(State#state{status = up})}; @@ -160,7 +164,7 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- dequeue(State = #state{mqueue = MQ}) -> - case emqttd_mqueue:out(MQ) of + case emqx_mqueue:out(MQ) of {empty, MQ1} -> State#state{mqueue = MQ1}; {{value, Msg}, MQ1} -> diff --git a/src/emqttd_bridge_sup.erl b/src/emqx_bridge_sup.erl similarity index 77% rename from src/emqttd_bridge_sup.erl rename to src/emqx_bridge_sup.erl index d28b2274c..dcfb09a6c 100644 --- a/src/emqttd_bridge_sup.erl +++ b/src/emqx_bridge_sup.erl @@ -14,7 +14,9 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_bridge_sup). +-module(emqx_bridge_sup). + +-author("Feng Lee "). -export([start_link/3]). @@ -23,8 +25,9 @@ %%-------------------------------------------------------------------- %% @doc Start bridge pool supervisor --spec(start_link(atom(), binary(), [emqttd_bridge:option()]) -> {ok, pid()} | {error, any()}). +-spec(start_link(atom(), binary(), [emqx_bridge:option()]) -> + {ok, pid()} | {error, any()}). start_link(Node, Topic, Options) -> - MFA = {emqttd_bridge, start_link, [Node, Topic, Options]}, - emqttd_pool_sup:start_link({bridge, Node, Topic}, random, MFA). + MFA = {emqx_bridge, start_link, [Node, Topic, Options]}, + emqx_pool_sup:start_link({bridge, Node, Topic}, random, MFA). diff --git a/src/emqttd_bridge_sup_sup.erl b/src/emqx_bridge_sup_sup.erl similarity index 86% rename from src/emqttd_bridge_sup_sup.erl rename to src/emqx_bridge_sup_sup.erl index 1d47bd003..d3f5d6bc5 100644 --- a/src/emqttd_bridge_sup_sup.erl +++ b/src/emqx_bridge_sup_sup.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_bridge_sup_sup). +-module(emqx_bridge_sup_sup). -behavior(supervisor). @@ -44,12 +44,12 @@ bridges() -> start_bridge(Node, Topic) when is_atom(Node) andalso is_binary(Topic) -> start_bridge(Node, Topic, []). --spec(start_bridge(atom(), binary(), [emqttd_bridge:option()]) -> {ok, pid()} | {error, any()}). +-spec(start_bridge(atom(), binary(), [emqx_bridge:option()]) -> {ok, pid()} | {error, any()}). start_bridge(Node, _Topic, _Options) when Node =:= node() -> {error, bridge_to_self}; start_bridge(Node, Topic, Options) when is_atom(Node) andalso is_binary(Topic) -> - {ok, BridgeEnv} = emqttd:env(bridge), - Options1 = emqttd_misc:merge_opts(BridgeEnv, Options), + {ok, BridgeEnv} = emqx:env(bridge), + Options1 = emqx_misc:merge_opts(BridgeEnv, Options), supervisor:start_child(?MODULE, bridge_spec(Node, Topic, Options1)). %% @doc Stop a bridge @@ -66,10 +66,10 @@ stop_bridge(Node, Topic) when is_atom(Node) andalso is_binary(Topic) -> %%-------------------------------------------------------------------- init([]) -> - {ok, {{one_for_one, 10, 100}, []}}. + {ok, {{one_for_one, 10, 3600}, []}}. bridge_spec(Node, Topic, Options) -> {?CHILD_ID(Node, Topic), - {emqttd_bridge_sup, start_link, [Node, Topic, Options]}, - permanent, infinity, supervisor, [emqttd_bridge_sup]}. + {emqx_bridge_sup, start_link, [Node, Topic, Options]}, + permanent, infinity, supervisor, [emqx_bridge_sup]}. diff --git a/src/emqttd_broker.erl b/src/emqx_broker.erl similarity index 89% rename from src/emqttd_broker.erl rename to src/emqx_broker.erl index 9f939a45e..dd59c2f11 100644 --- a/src/emqttd_broker.erl +++ b/src/emqx_broker.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_broker). +-module(emqx_broker). -behaviour(gen_server). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). %% API Function Exports -export([start_link/0]). @@ -42,7 +42,7 @@ -record(state, {started_at, sys_interval, heartbeat, ticker, version, sysdescr}). --define(APP, emqttd). +-define(APP, emqx). -define(SERVER, ?MODULE). @@ -60,7 +60,7 @@ %% API %%-------------------------------------------------------------------- -%% @doc Start emqttd broker +%% @doc Start the broker -spec(start_link() -> {ok, pid()} | ignore | {error, any()}). start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). @@ -107,7 +107,7 @@ datetime() -> %% @doc Start a tick timer start_tick(Msg) -> - start_tick(timer:seconds(emqttd:env(broker_sys_interval, 60)), Msg). + start_tick(timer:seconds(emqx:env(broker_sys_interval, 60)), Msg). start_tick(0, _Msg) -> undefined; @@ -125,7 +125,7 @@ stop_tick(TRef) -> %%-------------------------------------------------------------------- init([]) -> - emqttd_time:seed(), + emqx_time:seed(), ets:new(?BROKER_TAB, [set, public, named_table]), % Tick {ok, #state{started_at = os:timestamp(), @@ -172,16 +172,16 @@ code_change(_OldVsn, State, _Extra) -> retain(brokers) -> Payload = list_to_binary(string:join([atom_to_list(N) || N <- ekka_mnesia:running_nodes()], ",")), - Msg = emqttd_message:make(broker, <<"$SYS/brokers">>, Payload), - emqttd:publish(emqttd_message:set_flag(sys, emqttd_message:set_flag(retain, Msg))). + Msg = emqx_message:make(broker, <<"$SYS/brokers">>, Payload), + emqx:publish(emqx_message:set_flag(sys, emqx_message:set_flag(retain, Msg))). retain(Topic, Payload) when is_binary(Payload) -> - Msg = emqttd_message:make(broker, emqttd_topic:systop(Topic), Payload), - emqttd:publish(emqttd_message:set_flag(sys, emqttd_message:set_flag(retain, Msg))). + Msg = emqx_message:make(broker, emqx_topic:systop(Topic), Payload), + emqx:publish(emqx_message:set_flag(sys, emqx_message:set_flag(retain, Msg))). publish(Topic, Payload) when is_binary(Payload) -> - Msg = emqttd_message:make(broker, emqttd_topic:systop(Topic), Payload), - emqttd:publish(emqttd_message:set_flag(sys, Msg)). + Msg = emqx_message:make(broker, emqx_topic:systop(Topic), Payload), + emqx:publish(emqx_message:set_flag(sys, Msg)). uptime(#state{started_at = Ts}) -> Secs = timer:now_diff(os:timestamp(), Ts) div 1000000, diff --git a/src/emqttd_cli.erl b/src/emqx_cli.erl similarity index 88% rename from src/emqttd_cli.erl rename to src/emqx_cli.erl index a4029d46f..37f9a904a 100644 --- a/src/emqttd_cli.erl +++ b/src/emqx_cli.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_cli). +-module(emqx_cli). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_cli.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_cli.hrl"). -import(lists, [foreach/2]). @@ -44,12 +44,13 @@ -define(MAX_LIMIT, 10000). --define(APP, emqttd). +-define(APP, emqx). +-spec(load() -> ok). load() -> Cmds = [Fun || {Fun, _} <- ?MODULE:module_info(exports), is_cmd(Fun)], - [emqttd_ctl:register_cmd(Cmd, {?MODULE, Cmd}, []) || Cmd <- Cmds], - emqttd_cli_config:register_config(). + lists:foreach(fun(Cmd) -> emqx_ctl:register_cmd(Cmd, {?MODULE, Cmd}, []) end, Cmds), + emqx_cli_config:register_config(). is_cmd(Fun) -> not lists:member(Fun, [init, load, module_info]). @@ -66,9 +67,9 @@ status([]) -> ?PRINT("Node ~p is ~p~n", [node(), InternalStatus]), case lists:keysearch(?APP, 1, application:which_applications()) of false -> - ?PRINT_MSG("emqttd is not running~n"); + ?PRINT("~s is not running~n", [?APP]); {value, {?APP, _Desc, Vsn}} -> - ?PRINT("emqttd ~s is running~n", [Vsn]) + ?PRINT("~s ~s is running~n", [?APP, Vsn]) end; status(_) -> ?PRINT_CMD("status", "Show broker status"). @@ -79,21 +80,21 @@ status(_) -> broker([]) -> Funs = [sysdescr, version, uptime, datetime], foreach(fun(Fun) -> - ?PRINT("~-10s: ~s~n", [Fun, emqttd_broker:Fun()]) + ?PRINT("~-10s: ~s~n", [Fun, emqx_broker:Fun()]) end, Funs); broker(["stats"]) -> foreach(fun({Stat, Val}) -> ?PRINT("~-20s: ~w~n", [Stat, Val]) - end, emqttd_stats:getstats()); + end, emqx_stats:getstats()); broker(["metrics"]) -> foreach(fun({Metric, Val}) -> ?PRINT("~-24s: ~w~n", [Metric, Val]) - end, lists:sort(emqttd_metrics:all())); + end, lists:sort(emqx_metrics:all())); broker(["pubsub"]) -> - Pubsubs = supervisor:which_children(emqttd_pubsub_sup:pubsub_pool()), + Pubsubs = supervisor:which_children(emqx_pubsub_sup:pubsub_pool()), foreach(fun({{_, Id}, Pid, _, _}) -> ProcInfo = erlang:process_info(Pid, ?PROC_INFOKEYS), ?PRINT("pubsub: ~w~n", [Id]), @@ -154,9 +155,9 @@ cluster(_) -> %%-------------------------------------------------------------------- %% @doc Users usage -users(Args) -> emq_auth_username:cli(Args). +users(Args) -> emqx_auth_username:cli(Args). -acl(["reload"]) -> emqttd_access_control:reload_acl(); +acl(["reload"]) -> emqx_access_control:reload_acl(); acl(_) -> ?USAGE([{"acl reload", "reload etc/acl.conf"}]). %%-------------------------------------------------------------------- @@ -169,7 +170,7 @@ clients(["show", ClientId]) -> if_client(ClientId, fun print/1); clients(["kick", ClientId]) -> - if_client(ClientId, fun(#mqtt_client{client_pid = Pid}) -> emqttd_client:kick(Pid) end); + if_client(ClientId, fun(#mqtt_client{client_pid = Pid}) -> emqx_client:kick(Pid) end); clients(_) -> ?USAGE([{"clients list", "List all clients"}, @@ -177,7 +178,7 @@ clients(_) -> {"clients kick ", "Kick out a client"}]). if_client(ClientId, Fun) -> - case emqttd_cm:lookup(bin(ClientId)) of + case emqx_cm:lookup(bin(ClientId)) of undefined -> ?PRINT_MSG("Not Found.~n"); Client -> Fun(Client) end. @@ -214,7 +215,7 @@ sessions(_) -> %% @doc Routes Command routes(["list"]) -> - Routes = emqttd_router:dump(), + Routes = emqx_router:dump(), foreach(fun print/1, Routes); routes(["show", Topic]) -> @@ -228,7 +229,7 @@ routes(_) -> %% @doc Topics Command topics(["list"]) -> - lists:foreach(fun(Topic) -> ?PRINT("~s~n", [Topic]) end, emqttd:topics()); + lists:foreach(fun(Topic) -> ?PRINT("~s~n", [Topic]) end, emqx:topics()); topics(["show", Topic]) -> print(mnesia:dirty_read(mqtt_route, bin(Topic))); @@ -251,26 +252,25 @@ subscriptions(["show", ClientId]) -> subscriptions(["add", ClientId, Topic, QoS]) -> Add = fun(IntQos) -> - case emqttd:subscribe(bin(Topic), bin(ClientId), [{qos, IntQos}]) of + case emqx:subscribe(bin(Topic), bin(ClientId), [{qos, IntQos}]) of ok -> ?PRINT_MSG("ok~n"); + {error, already_existed} -> + ?PRINT_MSG("Error: already existed~n"); {error, Reason} -> ?PRINT("Error: ~p~n", [Reason]) end end, if_valid_qos(QoS, Add); - - subscriptions(["del", ClientId]) -> - Ok = emqttd:subscriber_down(bin(ClientId)), + Ok = emqx_server:subscriber_down(bin(ClientId)), ?PRINT("~p~n", [Ok]); subscriptions(["del", ClientId, Topic]) -> - Ok = emqttd:unsubscribe(bin(Topic), bin(ClientId)), + Ok = emqx:unsubscribe(bin(Topic), bin(ClientId)), ?PRINT("~p~n", [Ok]); - subscriptions(_) -> ?USAGE([{"subscriptions list", "List all subscriptions"}, {"subscriptions show ", "Show subscriptions of a client"}, @@ -278,7 +278,7 @@ subscriptions(_) -> {"subscriptions del ", "Delete static subscriptions manually"}, {"subscriptions del ", "Delete a static subscription manually"}]). -% if_could_print(Tab, Fun) -> +%if_could_print(Tab, Fun) -> % case mnesia:table_info(Tab, size) of % Size when Size >= ?MAX_LIMIT -> % ?PRINT("Could not list, too many ~ss: ~p~n", [Tab, Size]); @@ -296,10 +296,10 @@ if_valid_qos(QoS, Fun) -> end. plugins(["list"]) -> - foreach(fun print/1, emqttd_plugins:list()); + foreach(fun print/1, emqx_plugins:list()); plugins(["load", Name]) -> - case emqttd_plugins:load(list_to_atom(Name)) of + case emqx_plugins:load(list_to_atom(Name)) of {ok, StartedApps} -> ?PRINT("Start apps: ~p~nPlugin ~s loaded successfully.~n", [StartedApps, Name]); {error, Reason} -> @@ -307,7 +307,7 @@ plugins(["load", Name]) -> end; plugins(["unload", Name]) -> - case emqttd_plugins:unload(list_to_atom(Name)) of + case emqx_plugins:unload(list_to_atom(Name)) of ok -> ?PRINT("Plugin ~s unloaded successfully.~n", [Name]); {error, Reason} -> @@ -325,31 +325,32 @@ plugins(_) -> bridges(["list"]) -> foreach(fun({Node, Topic, _Pid}) -> ?PRINT("bridge: ~s--~s-->~s~n", [node(), Topic, Node]) - end, emqttd_bridge_sup_sup:bridges()); + end, emqx_bridge_sup_sup:bridges()); bridges(["options"]) -> ?PRINT_MSG("Options:~n"), + ?PRINT_MSG(" qos = 0 | 1 | 2~n"), ?PRINT_MSG(" prefix = string~n"), ?PRINT_MSG(" suffix = string~n"), ?PRINT_MSG(" queue = integer~n"), ?PRINT_MSG("Example:~n"), - ?PRINT_MSG(" prefix=abc/,suffix=/yxz,queue=1000~n"); + ?PRINT_MSG(" qos=2,prefix=abc/,suffix=/yxz,queue=1000~n"); bridges(["start", SNode, Topic]) -> - case emqttd_bridge_sup_sup:start_bridge(list_to_atom(SNode), list_to_binary(Topic)) of + case emqx_bridge_sup_sup:start_bridge(list_to_atom(SNode), list_to_binary(Topic)) of {ok, _} -> ?PRINT_MSG("bridge is started.~n"); {error, Error} -> ?PRINT("error: ~p~n", [Error]) end; bridges(["start", SNode, Topic, OptStr]) -> Opts = parse_opts(bridge, OptStr), - case emqttd_bridge_sup_sup:start_bridge(list_to_atom(SNode), list_to_binary(Topic), Opts) of + case emqx_bridge_sup_sup:start_bridge(list_to_atom(SNode), list_to_binary(Topic), Opts) of {ok, _} -> ?PRINT_MSG("bridge is started.~n"); {error, Error} -> ?PRINT("error: ~p~n", [Error]) end; bridges(["stop", SNode, Topic]) -> - case emqttd_bridge_sup_sup:stop_bridge(list_to_atom(SNode), list_to_binary(Topic)) of + case emqx_bridge_sup_sup:stop_bridge(list_to_atom(SNode), list_to_binary(Topic)) of ok -> ?PRINT_MSG("bridge is stopped.~n"); {error, Error} -> ?PRINT("error: ~p~n", [Error]) end; @@ -365,6 +366,8 @@ parse_opts(Cmd, OptStr) -> Tokens = string:tokens(OptStr, ","), [parse_opt(Cmd, list_to_atom(Opt), Val) || [Opt, Val] <- [string:tokens(S, "=") || S <- Tokens]]. +parse_opt(bridge, qos, Qos) -> + {qos, list_to_integer(Qos)}; parse_opt(bridge, suffix, Suffix) -> {topic_suffix, bin(Suffix)}; parse_opt(bridge, prefix, Prefix) -> @@ -384,7 +387,7 @@ vm(["all"]) -> [vm([Name]) || Name <- ["load", "memory", "process", "io", "ports"]]; vm(["load"]) -> - [?PRINT("cpu/~-20s: ~s~n", [L, V]) || {L, V} <- emqttd_vm:loads()]; + [?PRINT("cpu/~-20s: ~s~n", [L, V]) || {L, V} <- emqx_vm:loads()]; vm(["memory"]) -> [?PRINT("memory/~-17s: ~w~n", [Cat, Val]) || {Cat, Val} <- erlang:memory()]; @@ -428,7 +431,7 @@ mnesia(_) -> trace(["list"]) -> foreach(fun({{Who, Name}, LogFile}) -> ?PRINT("trace ~s ~s -> ~s~n", [Who, Name, LogFile]) - end, emqttd_trace:all_traces()); + end, emqx_trace:all_traces()); trace(["client", ClientId, "off"]) -> trace_off(client, ClientId); @@ -450,7 +453,7 @@ trace(_) -> {"trace topic off", "Stop tracing a Topic"}]). trace_on(Who, Name, LogFile) -> - case emqttd_trace:start_trace({Who, iolist_to_binary(Name)}, LogFile) of + case emqx_trace:start_trace({Who, iolist_to_binary(Name)}, LogFile) of ok -> ?PRINT("trace ~s ~s successfully.~n", [Who, Name]); {error, Error} -> @@ -458,7 +461,7 @@ trace_on(Who, Name, LogFile) -> end. trace_off(Who, Name) -> - case emqttd_trace:stop_trace({Who, iolist_to_binary(Name)}) of + case emqx_trace:stop_trace({Who, iolist_to_binary(Name)}) of ok -> ?PRINT("stop tracing ~s ~s successfully.~n", [Who, Name]); {error, Error} -> @@ -485,7 +488,7 @@ listeners(["restart", Proto, ListenOn]) -> [Port] -> list_to_integer(Port); [IP, Port] -> {IP, list_to_integer(Port)} end, - case emqttd_app:restart_listener({list_to_atom(Proto), ListenOn1, []}) of + case emqx:restart_listener({list_to_atom(Proto), ListenOn1, []}) of {ok, _Pid} -> io:format("Restart ~s listener on ~s successfully.~n", [Proto, ListenOn]); {error, Error} -> @@ -497,7 +500,7 @@ listeners(["stop", Proto, ListenOn]) -> [Port] -> list_to_integer(Port); [IP, Port] -> {IP, list_to_integer(Port)} end, - case emqttd_app:stop_listener({list_to_atom(Proto), ListenOn1, []}) of + case emqx:stop_listener({list_to_atom(Proto), ListenOn1, []}) of ok -> io:format("Stop ~s listener on ~s successfully.~n", [Proto, ListenOn]); {error, Error} -> @@ -548,8 +551,8 @@ print(#mqtt_plugin{name = Name, version = Ver, descr = Descr, active = Active}) print(#mqtt_client{client_id = ClientId, clean_sess = CleanSess, username = Username, peername = Peername, connected_at = ConnectedAt}) -> ?PRINT("Client(~s, clean_sess=~s, username=~s, peername=~s, connected_at=~p)~n", - [ClientId, CleanSess, Username, emqttd_net:format(Peername), - emqttd_time:now_secs(ConnectedAt)]); + [ClientId, CleanSess, Username, emqx_net:format(Peername), + emqx_time:now_secs(ConnectedAt)]); %% print(#mqtt_topic{topic = Topic, flags = Flags}) -> %% ?PRINT("~s: ~s~n", [Topic, string:join([atom_to_list(F) || F <- Flags], ",")]); @@ -563,7 +566,7 @@ print({Topic, Node}) -> ?PRINT("~s -> ~s~n", [Topic, Node]); print({ClientId, _ClientPid, _Persistent, SessInfo}) -> - Data = lists:append(SessInfo, emqttd_stats:get_session_stats(ClientId)), + Data = lists:append(SessInfo, emqx_stats:get_session_stats(ClientId)), InfoKeys = [clean_sess, subscriptions, max_inflight, @@ -589,7 +592,7 @@ print(subscription, {Sub, Topic}) -> ?PRINT("~s -> ~s~n", [Sub, Topic]). format(created_at, Val) -> - emqttd_time:now_secs(Val); + emqx_time:now_secs(Val); format(_, Val) -> Val. diff --git a/src/emqttd_cli_config.erl b/src/emqx_cli_config.erl similarity index 97% rename from src/emqttd_cli_config.erl rename to src/emqx_cli_config.erl index 1ce0de49c..a2167d2c6 100644 --- a/src/emqttd_cli_config.erl +++ b/src/emqx_cli_config.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module (emqttd_cli_config). +-module (emqx_cli_config). -export ([register_config_cli/0, register_config/0, @@ -26,8 +26,9 @@ read_config/1, write_config/2]). --define(APP, emqttd). --define(TAB, emqttd_config). +-define(APP, emqx). + +-define(TAB, emqx_config). register_config() -> application:start(clique), @@ -40,7 +41,7 @@ create_config_tab() -> case ets:info(?TAB, name) of undefined -> ets:new(?TAB, [named_table, public]), - {ok, PluginsEtcDir} = emqttd:env(plugins_etc_dir), + {ok, PluginsEtcDir} = emqx:env(plugins_etc_dir), Files = filelib:wildcard("*.conf", PluginsEtcDir), lists:foreach(fun(File) -> [FileName | _] = string:tokens(File, "."), @@ -173,7 +174,7 @@ protocol_config_callback(_App, websocket_protocol_header, Value) -> application:set_env(?APP, websocket_protocol_header, Value), " successfully\n"; protocol_config_callback(App, Key, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(Key, 1, Env, {Key, Value})), " successfully\n". @@ -215,15 +216,15 @@ client_config_callback([_, AppStr, KeyStr], Value) -> client_config_callback(l2a(AppStr), l2a(KeyStr), Value). client_config_callback(App, idle_timeout, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(client_idle_timeout, 1, Env, {client_idle_timeout, Value})), " successfully\n"; client_config_callback(App, enable_stats, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(client_enable_stats, 1, Env, {client_enable_stats, Value})), " successfully\n"; client_config_callback(App, Key, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(Key, 1, Env, {Key, Value})), " successfully\n". @@ -262,7 +263,7 @@ register_session_config() -> session_config_callback([_, AppStr, KeyStr], Value) -> session_config_callback(l2a(AppStr), l2a(KeyStr), Value). session_config_callback(App, Key, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(Key, 1, Env, {Key, Value})), " successfully\n". @@ -298,15 +299,15 @@ queue_config_callback([_, AppStr, KeyStr], Value) -> queue_config_callback(l2a(AppStr), l2a(KeyStr), Value). queue_config_callback(App, low_watermark, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(low_watermark, 1, Env, {low_watermark, Value})), " successfully\n"; queue_config_callback(App, high_watermark, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(high_watermark, 1, Env, {high_watermark, Value})), " successfully\n"; queue_config_callback(App, Key, Value) -> - {ok, Env} = emqttd:env(App), + {ok, Env} = emqx:env(App), application:set_env(?APP, App, lists:keyreplace(Key, 1, Env, {Key, Value})), " successfully\n". diff --git a/src/emqttd_client.erl b/src/emqx_client.erl similarity index 87% rename from src/emqttd_client.erl rename to src/emqx_client.erl index 6631b4566..5a16d1897 100644 --- a/src/emqttd_client.erl +++ b/src/emqx_client.erl @@ -16,17 +16,17 @@ %% @doc MQTT/TCP Connection. --module(emqttd_client). +-module(emqx_client). -behaviour(gen_server2). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -import(proplists, [get_value/2, get_value/3]). @@ -114,11 +114,11 @@ do_init(Conn, Env, Peername) -> SendFun = send_fun(Conn, Peername), RateLimit = get_value(rate_limit, Conn:opts()), PacketSize = get_value(max_packet_size, Env, ?MAX_PACKET_SIZE), - Parser = emqttd_parser:initial_state(PacketSize), - ProtoState = emqttd_protocol:init(Conn, Peername, SendFun, Env), + Parser = emqx_parser:initial_state(PacketSize), + ProtoState = emqx_protocol:init(Conn, Peername, SendFun, Env), EnableStats = get_value(client_enable_stats, Env, false), IdleTimout = get_value(client_idle_timeout, Env, 30000), - ForceGcCount = emqttd_gc:conn_max_gc_count(), + ForceGcCount = emqx_gc:conn_max_gc_count(), State = run_socket(#client_state{connection = Conn, peername = Peername, await_recv = false, @@ -136,9 +136,9 @@ do_init(Conn, Env, Peername) -> send_fun(Conn, Peername) -> Self = self(), fun(Packet) -> - Data = emqttd_serializer:serialize(Packet), + Data = emqx_serializer:serialize(Packet), ?LOG(debug, "SEND ~p", [Data], #client_state{peername = Peername}), - emqttd_metrics:inc('bytes/sent', iolist_size(Data)), + emqx_metrics:inc('bytes/sent', iolist_size(Data)), try Conn:async_send(Data) of true -> ok catch @@ -153,17 +153,17 @@ prioritise_info(Msg, _Len, _State) -> case Msg of {redeliver, _} -> 5; _ -> 0 end. handle_pre_hibernate(State) -> - {hibernate, emqttd_gc:reset_conn_gc_count(#client_state.force_gc_count, emit_stats(State))}. + {hibernate, emqx_gc:reset_conn_gc_count(#client_state.force_gc_count, emit_stats(State))}. handle_call(info, From, State = #client_state{proto_state = ProtoState}) -> - ProtoInfo = emqttd_protocol:info(ProtoState), + ProtoInfo = emqx_protocol:info(ProtoState), ClientInfo = ?record_to_proplist(client_state, State, ?INFO_KEYS), {reply, Stats, _, _} = handle_call(stats, From, State), reply(lists:append([ClientInfo, ProtoInfo, Stats]), State); handle_call(stats, _From, State = #client_state{proto_state = ProtoState}) -> - reply(lists:append([emqttd_misc:proc_stats(), - emqttd_protocol:stats(ProtoState), + reply(lists:append([emqx_misc:proc_stats(), + emqx_protocol:stats(ProtoState), sock_stats(State)]), State); handle_call(kick, _From, State) -> @@ -176,7 +176,7 @@ handle_call(get_rate_limit, _From, State = #client_state{rate_limit = Rl}) -> reply(Rl, State); handle_call(session, _From, State = #client_state{proto_state = ProtoState}) -> - reply(emqttd_protocol:session(ProtoState), State); + reply(emqx_protocol:session(ProtoState), State); handle_call({clean_acl_cache, Topic}, _From, State) -> erase({acl, publish, Topic}), @@ -191,13 +191,13 @@ handle_cast(Msg, State) -> handle_info({subscribe, TopicTable}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:subscribe(TopicTable, ProtoState) + emqx_protocol:subscribe(TopicTable, ProtoState) end, State); handle_info({unsubscribe, Topics}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:unsubscribe(Topics, ProtoState) + emqx_protocol:unsubscribe(Topics, ProtoState) end, State); %% Asynchronous SUBACK @@ -205,19 +205,23 @@ handle_info({suback, PacketId, GrantedQos}, State) -> with_proto( fun(ProtoState) -> Packet = ?SUBACK_PACKET(PacketId, GrantedQos), - emqttd_protocol:send(Packet, ProtoState) + emqx_protocol:send(Packet, ProtoState) end, State); +%% Fastlane +handle_info({dispatch, _Topic, Message}, State) -> + handle_info({deliver, Message#mqtt_message{qos = ?QOS_0}}, State); + handle_info({deliver, Message}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:send(Message, ProtoState) + emqx_protocol:send(Message, ProtoState) end, State); handle_info({redeliver, {?PUBREL, PacketId}}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:pubrel(PacketId, ProtoState) + emqx_protocol:pubrel(PacketId, ProtoState) end, State); handle_info(emit_stats, State) -> @@ -240,7 +244,7 @@ handle_info(activate_sock, State) -> handle_info({inet_async, _Sock, _Ref, {ok, Data}}, State) -> Size = iolist_size(Data), ?LOG(debug, "RECV ~p", [Data], State), - emqttd_metrics:inc('bytes/received', Size), + emqx_metrics:inc('bytes/received', Size), received(Data, rate_limit(Size, State#client_state{await_recv = false})); handle_info({inet_async, _Sock, _Ref, {error, Reason}}, State) -> @@ -260,7 +264,7 @@ handle_info({keepalive, start, Interval}, State = #client_state{connection = Con {error, Error} -> {error, Error} end end, - case emqttd_keepalive:start(StatFun, Interval, {keepalive, check}) of + case emqx_keepalive:start(StatFun, Interval, {keepalive, check}) of {ok, KeepAlive} -> {noreply, State#client_state{keepalive = KeepAlive}, hibernate}; {error, Error} -> @@ -269,7 +273,7 @@ handle_info({keepalive, start, Interval}, State = #client_state{connection = Con end; handle_info({keepalive, check}, State = #client_state{keepalive = KeepAlive}) -> - case emqttd_keepalive:check(KeepAlive) of + case emqx_keepalive:check(KeepAlive) of {ok, KeepAlive1} -> {noreply, State#client_state{keepalive = KeepAlive1}, hibernate}; {error, timeout} -> @@ -289,14 +293,14 @@ terminate(Reason, State = #client_state{connection = Conn, ?LOG(debug, "Terminated for ~p", [Reason], State), Conn:fast_close(), - emqttd_keepalive:cancel(KeepAlive), + emqx_keepalive:cancel(KeepAlive), case {ProtoState, Reason} of {undefined, _} -> ok; {_, {shutdown, Error}} -> - emqttd_protocol:shutdown(Error, ProtoState); + emqx_protocol:shutdown(Error, ProtoState); {_, Reason} -> - emqttd_protocol:shutdown(Reason, ProtoState) + emqx_protocol:shutdown(Reason, ProtoState) end. code_change(_OldVsn, State, _Extra) -> @@ -314,14 +318,14 @@ received(Bytes, State = #client_state{parser = Parser, packet_size = PacketSize, proto_state = ProtoState, idle_timeout = IdleTimeout}) -> - case catch emqttd_parser:parse(Bytes, Parser) of + case catch emqx_parser:parse(Bytes, Parser) of {more, NewParser} -> {noreply, run_socket(State#client_state{parser = NewParser}), IdleTimeout}; {ok, Packet, Rest} -> - emqttd_metrics:received(Packet), - case emqttd_protocol:received(Packet, ProtoState) of + emqx_metrics:received(Packet), + case emqx_protocol:received(Packet, ProtoState) of {ok, ProtoState1} -> - received(Rest, State#client_state{parser = emqttd_parser:initial_state(PacketSize), + received(Rest, State#client_state{parser = emqx_parser:initial_state(PacketSize), proto_state = ProtoState1}); {error, Error} -> ?LOG(error, "Protocol error - ~p", [Error], State), @@ -365,7 +369,7 @@ with_proto(Fun, State = #client_state{proto_state = ProtoState}) -> {noreply, State#client_state{proto_state = ProtoState1}, hibernate}. emit_stats(State = #client_state{proto_state = ProtoState}) -> - emit_stats(emqttd_protocol:clientid(ProtoState), State). + emit_stats(emqx_protocol:clientid(ProtoState), State). emit_stats(_ClientId, State = #client_state{enable_stats = false}) -> State; @@ -373,7 +377,7 @@ emit_stats(undefined, State) -> State; emit_stats(ClientId, State) -> {reply, Stats, _, _} = handle_call(stats, undefined, State), - emqttd_stats:set_client_stats(ClientId, Stats), + emqx_stats:set_client_stats(ClientId, Stats), State. sock_stats(#client_state{connection = Conn}) -> @@ -390,5 +394,5 @@ stop(Reason, State) -> gc(State = #client_state{connection = Conn}) -> Cb = fun() -> Conn:gc(), emit_stats(State) end, - emqttd_gc:maybe_force_gc(#client_state.force_gc_count, State, Cb). + emqx_gc:maybe_force_gc(#client_state.force_gc_count, State, Cb). diff --git a/src/emqttd_cm.erl b/src/emqx_cm.erl similarity index 97% rename from src/emqttd_cm.erl rename to src/emqx_cm.erl index 2e57ebe5b..f56ce2929 100644 --- a/src/emqttd_cm.erl +++ b/src/emqx_cm.erl @@ -16,15 +16,15 @@ %% @doc MQTT Client Manager --module(emqttd_cm). +-module(emqx_cm). -behaviour(gen_server2). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). %% API Exports -export([start_link/3]). @@ -123,7 +123,7 @@ handle_info({'DOWN', MRef, process, DownPid, _Reason}, State) -> {ok, {ClientId, DownPid}} -> case lookup_proc(ClientId) of DownPid -> - emqttd_stats:del_client_stats(ClientId), + emqx_stats:del_client_stats(ClientId), ets:delete(mqtt_client, ClientId); _ -> ignore diff --git a/src/emqttd_cm_sup.erl b/src/emqx_cm_sup.erl similarity index 85% rename from src/emqttd_cm_sup.erl rename to src/emqx_cm_sup.erl index fc01ea649..704b0e1fd 100644 --- a/src/emqttd_cm_sup.erl +++ b/src/emqx_cm_sup.erl @@ -16,13 +16,13 @@ %% @doc Client Manager Supervisor. --module(emqttd_cm_sup). +-module(emqx_cm_sup). -behaviour(supervisor). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). %% API -export([start_link/0]). @@ -30,7 +30,7 @@ %% Supervisor callbacks -export([init/1]). --define(CM, emqttd_cm). +-define(CM, emqx_cm). -define(TAB, mqtt_client). @@ -42,8 +42,8 @@ init([]) -> create_client_tab(), %% CM Pool Sup - MFA = {?CM, start_link, [emqttd_stats:statsfun('clients/count', 'clients/max')]}, - PoolSup = emqttd_pool_sup:spec([?CM, hash, erlang:system_info(schedulers), MFA]), + MFA = {?CM, start_link, [emqx_stats:statsfun('clients/count', 'clients/max')]}, + PoolSup = emqx_pool_sup:spec([?CM, hash, erlang:system_info(schedulers), MFA]), {ok, {{one_for_all, 10, 3600}, [PoolSup]}}. diff --git a/src/emqttd_config.erl b/src/emqx_config.erl similarity index 93% rename from src/emqttd_config.erl rename to src/emqx_config.erl index deaaa77d1..c36cdc8c3 100644 --- a/src/emqttd_config.erl +++ b/src/emqx_config.erl @@ -23,7 +23,7 @@ %% 3. Store in data/app.config? %% --module(emqttd_config). +-module(emqx_config). -export([read/1, write/2, dump/2, reload/1, get/2, get/3, set/3]). @@ -57,7 +57,7 @@ write(App, Terms) -> Schema = cuttlefish_schema:files([Path]), case cuttlefish_generator:map(Schema, Configs) of [{App, Configs1}] -> - emqttd_cli_config:write_config(App, Configs), + emqx_cli_config:write_config(App, Configs), lists:foreach(fun({Key, Val}) -> application:set_env(App, Key, Val) end, Configs1); _ -> error @@ -70,25 +70,25 @@ dump(_App, _Terms) -> -spec(set(atom(), list(), list()) -> ok). set(App, Par, Val) -> - emqttd_cli_config:run(["config", + emqx_cli_config:run(["config", "set", lists:concat([Par, "=", Val]), lists:concat(["--app=", App])]). -spec(get(atom(), list()) -> undefined | {ok, term()}). get(App, Par) -> - case emqttd_cli_config:get_cfg(App, Par) of + case emqx_cli_config:get_cfg(App, Par) of undefined -> undefined; Val -> {ok, Val} end. -spec(get(atom(), list(), atom()) -> term()). get(App, Par, Def) -> - emqttd_cli_config:get_cfg(App, Par, Def). + emqx_cli_config:get_cfg(App, Par, Def). read_(App) -> - Configs = emqttd_cli_config:read_config(App), + Configs = emqx_cli_config:read_config(App), Path = lists:concat([code:priv_dir(App), "/", App, ".schema"]), case filelib:is_file(Path) of false -> @@ -112,3 +112,4 @@ read_(App) -> end, [], Configs), RequiredCfg ++ OptionalCfg end. + diff --git a/src/emqttd_ctl.erl b/src/emqx_ctl.erl similarity index 91% rename from src/emqttd_ctl.erl rename to src/emqx_ctl.erl index 77769e3c8..565c08ff1 100644 --- a/src/emqttd_ctl.erl +++ b/src/emqx_ctl.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_ctl). +-module(emqx_ctl). -behaviour(gen_server). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_cli.hrl"). +-include("emqx_cli.hrl"). -define(SERVER, ?MODULE). @@ -69,13 +69,13 @@ run([]) -> usage(), ok; run(["help"]) -> usage(), ok; run(["set"] = CmdS) when length(CmdS) =:= 1 -> - emqttd_cli_config:set_usage(), ok; + emqx_cli_config:set_usage(), ok; run(["set" | _] = CmdS) -> - emqttd_cli_config:run(["config" | CmdS]), ok; + emqx_cli_config:run(["config" | CmdS]), ok; run(["show" | _] = CmdS) -> - emqttd_cli_config:run(["config" | CmdS]), ok; + emqx_cli_config:run(["config" | CmdS]), ok; run([CmdS|Args]) -> case lookup(list_to_atom(CmdS)) of @@ -161,14 +161,14 @@ next_seq(State = #state{seq = Seq}) -> register_cmd_test_() -> {setup, fun() -> - {ok, InitState} = emqttd_ctl:init([]), + {ok, InitState} = emqx_ctl:init([]), InitState end, fun(State) -> - ok = emqttd_ctl:terminate(shutdown, State) + ok = emqx_ctl:terminate(shutdown, State) end, fun(State = #state{seq = Seq}) -> - emqttd_ctl:handle_cast({register_cmd, test0, {?MODULE, test0}, []}, State), + emqx_ctl:handle_cast({register_cmd, test0, {?MODULE, test0}, []}, State), [?_assertMatch([{{0,test0},{?MODULE, test0}, []}], ets:lookup(?CMD_TAB, {Seq,test0}))] end }. diff --git a/src/emqttd_gc.erl b/src/emqx_gc.erl similarity index 96% rename from src/emqttd_gc.erl rename to src/emqx_gc.erl index 75545a77f..a0b702db0 100644 --- a/src/emqttd_gc.erl +++ b/src/emqx_gc.erl @@ -16,7 +16,7 @@ %% GC Utility functions. --module(emqttd_gc). +-module(emqx_gc). -author("Feng Lee "). @@ -25,7 +25,7 @@ -spec(conn_max_gc_count() -> integer()). conn_max_gc_count() -> - case emqttd:env(conn_force_gc_count) of + case emqx:env(conn_force_gc_count) of {ok, I} when I > 0 -> I + rand:uniform(I); {ok, I} when I =< 0 -> undefined; undefined -> undefined diff --git a/src/emqttd_gen_mod.erl b/src/emqx_gen_mod.erl similarity index 92% rename from src/emqttd_gen_mod.erl rename to src/emqx_gen_mod.erl index 824b65f4c..24c0036b8 100644 --- a/src/emqttd_gen_mod.erl +++ b/src/emqx_gen_mod.erl @@ -14,14 +14,10 @@ %% limitations under the License. %%-------------------------------------------------------------------- -%% @doc emqttd gen_mod behaviour - --module(emqttd_gen_mod). +-module(emqx_gen_mod). -author("Feng Lee "). --include("emqttd.hrl"). - -ifdef(use_specs). -callback(load(Opts :: any()) -> ok | {error, any()}). diff --git a/src/emqttd_guid.erl b/src/emqx_guid.erl similarity index 97% rename from src/emqttd_guid.erl rename to src/emqx_guid.erl index 24199fa01..163fa277f 100644 --- a/src/emqttd_guid.erl +++ b/src/emqx_guid.erl @@ -28,7 +28,7 @@ %% %% @end --module(emqttd_guid). +-module(emqx_guid). -export([gen/0, new/0, timestamp/1, to_hexstr/1, from_hexstr/1, to_base62/1, from_base62/1]). @@ -128,8 +128,8 @@ from_hexstr(S) -> I = list_to_integer(binary_to_list(S), 16), <>. to_base62(<>) -> - emqttd_base62:encode(I). + emqx_base62:encode(I). from_base62(S) -> - I = emqttd_base62:decode(S), <>. + I = emqx_base62:decode(S), <>. diff --git a/src/emqttd_hooks.erl b/src/emqx_hooks.erl similarity index 99% rename from src/emqttd_hooks.erl rename to src/emqx_hooks.erl index 693a67ff7..da152675e 100644 --- a/src/emqttd_hooks.erl +++ b/src/emqx_hooks.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_hooks). +-module(emqx_hooks). -behaviour(gen_server). diff --git a/src/emqttd_http.erl b/src/emqx_http.erl similarity index 93% rename from src/emqttd_http.erl rename to src/emqx_http.erl index f62329ada..109c1e6ee 100644 --- a/src/emqttd_http.erl +++ b/src/emqx_http.erl @@ -16,19 +16,21 @@ %% @doc HTTP publish API and websocket client. --module(emqttd_http). +-module(emqx_http). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). -import(proplists, [get_value/2, get_value/3]). -export([http_handler/0, handle_request/2, http_api/0, inner_handle_request/2]). --include("emqttd_internal.hrl"). +-include("emqx_rest.hrl"). + +-include("emqx_internal.hrl"). -record(state, {dispatch}). @@ -38,7 +40,7 @@ http_handler() -> {?MODULE, handle_request, [State]}. http_api() -> - Attr = emqttd_rest_api:module_info(attributes), + Attr = emqx_rest_api:module_info(attributes), [{Regexp, Method, Function, Args} || {http_api, [{Regexp, Method, Function, Args}]} <- Attr]. %%-------------------------------------------------------------------- @@ -51,7 +53,7 @@ handle_request(Req, State) -> handle_request("/status", Req, Req:get(method)); "/" -> handle_request("/", Req, Req:get(method)); - "/api/v2/auth" -> + "/api/v2/auth" -> %%TODO: Security Issue! handle_request(Path, Req, State); _ -> if_authorized(Req, fun() -> handle_request(Path, Req, State) end) @@ -67,11 +69,11 @@ handle_request("/api/v2/" ++ Url, Req, #state{dispatch = Dispatch}) -> handle_request("/status", Req, Method) when Method =:= 'HEAD'; Method =:= 'GET' -> {InternalStatus, _ProvidedStatus} = init:get_status(), - AppStatus = case lists:keysearch(emqttd, 1, application:which_applications()) of + AppStatus = case lists:keysearch(emqx, 1, application:which_applications()) of false -> not_running; {value, _Val} -> running end, - Status = io_lib:format("Node ~s is ~s~nemqttd is ~s", + Status = io_lib:format("Node ~s is ~s~nemqx is ~s", [node(), InternalStatus, AppStatus]), Req:ok({"text/plain", iolist_to_binary(Status)}); @@ -95,8 +97,8 @@ dispatcher(APIs) -> {true, true} -> {match, [MatchList]} = re:run(Url, Regexp, [global, {capture, all_but_first, list}]), Args = lists:append([[Method, Params], MatchList]), - lager:debug("Mod:~p, Fun:~p, Args:~p", [emqttd_rest_api, Function, Args]), - case catch apply(emqttd_rest_api, Function, Args) of + lager:debug("Mod:~p, Fun:~p, Args:~p", [emqx_rest_api, Function, Args]), + case catch apply(emqx_rest_api, Function, Args) of {ok, Data} -> respond(Req, 200, [{code, ?SUCCESS}, {result, Data}]); {error, Error} -> @@ -132,7 +134,7 @@ authorized(Req) -> false; "Basic " ++ BasicAuth -> {Username, Password} = user_passwd(BasicAuth), - case emqttd_mgmt:check_user(Username, Password) of + case emq_mgmt:check_user(Username, Password) of ok -> true; {error, Reason} -> diff --git a/src/emqttd_inflight.erl b/src/emqx_inflight.erl similarity index 99% rename from src/emqttd_inflight.erl rename to src/emqx_inflight.erl index bb9af390b..146780253 100644 --- a/src/emqttd_inflight.erl +++ b/src/emqx_inflight.erl @@ -16,7 +16,7 @@ %% @doc Inflight Window that wraps the gb_trees. --module(emqttd_inflight). +-module(emqx_inflight). -author("Feng Lee "). diff --git a/src/emqttd_keepalive.erl b/src/emqx_keepalive.erl similarity index 98% rename from src/emqttd_keepalive.erl rename to src/emqx_keepalive.erl index 5d26ea8a6..44dac454c 100644 --- a/src/emqttd_keepalive.erl +++ b/src/emqx_keepalive.erl @@ -16,7 +16,7 @@ %% @doc Client Keepalive --module(emqttd_keepalive). +-module(emqx_keepalive). -author("Feng Lee "). diff --git a/src/lager_emqtt_backend.erl b/src/emqx_lager_backend.erl similarity index 91% rename from src/lager_emqtt_backend.erl rename to src/emqx_lager_backend.erl index 69c1aece4..45e3891d6 100644 --- a/src/lager_emqtt_backend.erl +++ b/src/emqx_lager_backend.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(lager_emqtt_backend). +-module(emqx_lager_backend). -author("Feng Lee "). @@ -79,10 +79,10 @@ publish_log(Message, State = #state{formatter = Formatter, format_config = FormatConfig}) -> Severity = lager_msg:severity(Message), Payload = Formatter:format(Message, FormatConfig), - Msg = emqttd_message:make(log, topic(Severity), iolist_to_binary(Payload)), - emqttd:publish(emqttd_message:set_flag(sys, Msg)), + Msg = emqx_message:make(log, topic(Severity), iolist_to_binary(Payload)), + emqx:publish(emqx_message:set_flag(sys, Msg)), {ok, State}. topic(Severity) -> - emqttd_topic:systop(list_to_binary(lists:concat(['logs/', Severity]))). + emqx_topic:systop(list_to_binary(lists:concat(['logs/', Severity]))). diff --git a/src/emqttd_message.erl b/src/emqx_message.erl similarity index 97% rename from src/emqttd_message.erl rename to src/emqx_message.erl index 4c3bea0d8..858a73000 100644 --- a/src/emqttd_message.erl +++ b/src/emqx_message.erl @@ -16,13 +16,13 @@ %% @doc MQTT Message Functions --module(emqttd_message). +-module(emqx_message). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). -export([make/3, make/4, from_packet/1, from_packet/2, from_packet/3, to_packet/1]). @@ -91,9 +91,9 @@ from_packet(Username, ClientId, Packet) -> Msg = from_packet(Packet), Msg#mqtt_message{from = {ClientId, Username}}. -msgid() -> emqttd_guid:gen(). +msgid() -> emqx_guid:gen(). -%% @doc Message to packet +%% @doc Message to Packet -spec(to_packet(mqtt_message()) -> mqtt_packet()). to_packet(#mqtt_message{pktid = PkgId, qos = Qos, diff --git a/src/emqttd_metrics.erl b/src/emqx_metrics.erl similarity index 94% rename from src/emqttd_metrics.erl rename to src/emqx_metrics.erl index c21d274a0..032969234 100644 --- a/src/emqttd_metrics.erl +++ b/src/emqx_metrics.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_metrics). +-module(emqx_metrics). -behaviour(gen_server). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). -define(SERVER, ?MODULE). @@ -89,7 +89,8 @@ {counter, 'messages/qos2/sent'}, % QoS2 Messages sent {counter, 'messages/qos2/dropped'}, % QoS2 Messages dropped {gauge, 'messages/retained'}, % Messagea retained - {counter, 'messages/dropped'} % Messages dropped + {counter, 'messages/dropped'}, % Messages dropped + {counter, 'messages/forward'} % Messages forward ]). %%-------------------------------------------------------------------- @@ -242,7 +243,7 @@ key(counter, Metric) -> %%-------------------------------------------------------------------- init([]) -> - emqttd_time:seed(), + emqx_time:seed(), Metrics = ?SYSTOP_BYTES ++ ?SYSTOP_PACKETS ++ ?SYSTOP_MESSAGES, % Create metrics table ets:new(?METRIC_TAB, [set, public, named_table, {write_concurrency, true}]), @@ -251,7 +252,7 @@ init([]) -> % $SYS Topics for metrics % [ok = emqttd:create(topic, metric_topic(Topic)) || {_, Topic} <- Metrics], % Tick to publish metrics - {ok, #state{tick = emqttd_broker:start_tick(tick)}, hibernate}. + {ok, #state{tick = emqx_broker:start_tick(tick)}, hibernate}. handle_call(_Req, _From, State) -> {reply, error, State}. @@ -268,7 +269,7 @@ handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, #state{tick = TRef}) -> - emqttd_broker:stop_tick(TRef). + emqx_broker:stop_tick(TRef). code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -278,8 +279,8 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- publish(Metric, Val) -> - Msg = emqttd_message:make(metrics, metric_topic(Metric), bin(Val)), - emqttd:publish(emqttd_message:set_flag(sys, Msg)). + Msg = emqx_message:make(metrics, metric_topic(Metric), bin(Val)), + emqx:publish(emqx_message:set_flag(sys, Msg)). create_metric({gauge, Name}) -> ets:insert(?METRIC_TAB, {{Name, 0}, 0}); @@ -289,7 +290,7 @@ create_metric({counter, Name}) -> ets:insert(?METRIC_TAB, [{{Name, I}, 0} || I <- Schedulers]). metric_topic(Metric) -> - emqttd_topic:systop(list_to_binary(lists:concat(['metrics/', Metric]))). + emqx_topic:systop(list_to_binary(lists:concat(['metrics/', Metric]))). bin(I) when is_integer(I) -> list_to_binary(integer_to_list(I)). diff --git a/src/emqttd_mgmt.erl b/src/emqx_mgmt.erl similarity index 85% rename from src/emqttd_mgmt.erl rename to src/emqx_mgmt.erl index 2c671f3bd..3d1141018 100644 --- a/src/emqttd_mgmt.erl +++ b/src/emqx_mgmt.erl @@ -14,15 +14,17 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_mgmt). +-module(emqx_mgmt). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). + +-include("emqx_rest.hrl"). -include_lib("stdlib/include/qlc.hrl"). @@ -61,7 +63,7 @@ brokers() -> [{Node, broker(Node)} || Node <- ekka_mnesia:running_nodes()]. broker(Node) when Node =:= node() -> - emqttd_broker:info(); + emqx_broker:info(); broker(Node) -> rpc_call(Node, broker, [Node]). @@ -69,7 +71,7 @@ metrics() -> [{Node, metrics(Node)} || Node <- ekka_mnesia:running_nodes()]. metrics(Node) when Node =:= node() -> - emqttd_metrics:all(); + emqx_metrics:all(); metrics(Node) -> rpc_call(Node, metrics, [Node]). @@ -77,7 +79,7 @@ stats() -> [{Node, stats(Node)} || Node <- ekka_mnesia:running_nodes()]. stats(Node) when Node =:= node() -> - emqttd_stats:getstats(); + emqx_stats:getstats(); stats(Node) -> rpc_call(Node, stats, [Node]). @@ -85,7 +87,7 @@ plugins() -> [{Node, plugins(Node)} || Node <- ekka_mnesia:running_nodes()]. plugins(Node) when Node =:= node() -> - emqttd_plugins:list(Node); + emqx_plugins:list(Node); plugins(Node) -> rpc_call(Node, plugins, [Node]). @@ -111,8 +113,8 @@ nodes_info() -> [node_info(Node) || Node <- Running] ++ DownNodes. node_info(Node) when Node =:= node() -> - CpuInfo = [{K, list_to_binary(V)} || {K, V} <- emqttd_vm:loads()], - Memory = emqttd_vm:get_memory(), + CpuInfo = [{K, list_to_binary(V)} || {K, V} <- emqx_vm:loads()], + Memory = emqx_vm:get_memory(), OtpRel = "R" ++ erlang:system_info(otp_release) ++ "/" ++ erlang:system_info(version), [{name, node()}, {otp_release, list_to_binary(OtpRel)}, @@ -133,17 +135,17 @@ stop_node(Node) -> %% plugins %%-------------------------------------------------------- plugin_list(Node) when Node =:= node() -> - emqttd_plugins:list(); + emqx_plugins:list(); plugin_list(Node) -> rpc_call(Node, plugin_list, [Node]). plugin_load(Node, PluginName) when Node =:= node() -> - emqttd_plugins:load(PluginName); + emqx_plugins:load(PluginName); plugin_load(Node, PluginName) -> rpc_call(Node, plugin_load, [Node, PluginName]). plugin_unload(Node, PluginName) when Node =:= node() -> - emqttd_plugins:unload(PluginName); + emqx_plugins:unload(PluginName); plugin_unload(Node, PluginName) -> rpc_call(Node, plugin_unload, [Node, PluginName]). @@ -189,7 +191,7 @@ route(Key) -> route_list(Key, 1, 20). %% alarm %%-------------------------------------------------------- alarm_list() -> - emqttd_alarm:get_alarms(). + emqx_alarm:get_alarms(). query_table(Qh, PageNo, PageSize, TotalNum) -> Cursor = qlc:cursor(Qh), @@ -220,8 +222,8 @@ lookup_table(LookupFun, _PageNo, _PageSize) -> publish({ClientId, Topic, Payload, Qos, Retain}) -> case validate(topic, Topic) of true -> - Msg = emqttd_message:make(ClientId, Qos, Topic, Payload), - emqttd:publish(Msg#mqtt_message{retain = Retain}), + Msg = emqx_message:make(ClientId, Qos, Topic, Payload), + emqx:publish(Msg#mqtt_message{retain = Retain}), ok; false -> {error, format_error(Topic, "validate topic: ${0} fail")} @@ -230,11 +232,11 @@ publish({ClientId, Topic, Payload, Qos, Retain}) -> subscribe({ClientId, Topic, Qos}) -> case validate(topic, Topic) of true -> - case emqttd_sm:lookup_session(ClientId) of + case emqx_sm:lookup_session(ClientId) of undefined -> {error, format_error(ClientId, "Clientid: ${0} not found")}; #mqtt_session{sess_pid = SessPid} -> - emqttd_session:subscribe(SessPid, [{Topic, [{qos, Qos}]}]), + emqx_session:subscribe(SessPid, [{Topic, [{qos, Qos}]}]), ok end; false -> @@ -244,16 +246,53 @@ subscribe({ClientId, Topic, Qos}) -> unsubscribe({ClientId, Topic}) -> case validate(topic, Topic) of true -> - case emqttd_sm:lookup_session(ClientId) of + case emqx_sm:lookup_session(ClientId) of undefined -> {error, format_error(ClientId, "Clientid: ${0} not found")}; #mqtt_session{sess_pid = SessPid} -> - emqttd_session:unsubscribe(SessPid, [{Topic, []}]), + emqx_session:unsubscribe(SessPid, [{Topic, []}]), ok end; false -> {error, format_error(Topic, "validate topic: ${0} fail")} end. + +% publish(Messages) -> +% lists:foldl( +% fun({ClientId, Topic, Payload, Qos, Retain}, {Success, Failed}) -> +% case validate(topic, Topic) of +% true -> +% Msg = emqx_message:make(ClientId, Qos, Topic, Payload), +% emqx:publish(Msg#mqtt_message{retain = Retain}), +% {[[{topic, Topic}]| Success], Failed}; +% false -> +% {Success, [[{topic, Topic}]| Failed]} +% end +% end, {[], []}, Messages). + +% subscribers(Subscribers) -> +% lists:foldl( +% fun({ClientId, Topic, Qos}, {Success, Failed}) -> +% case emqx_sm:lookup_session(ClientId) of +% undefined -> +% {Success, [[{client_id, ClientId}]|Failed]}; +% #mqtt_session{sess_pid = SessPid} -> +% emqx_session:subscribe(SessPid, [{Topic, [{qos, Qos}]}]), +% {[[{client_id, ClientId}]| Success], Failed} +% end +% end,{[], []}, Subscribers). + +% unsubscribers(UnSubscribers)-> +% lists:foldl( +% fun({ClientId, Topic}, {Success, Failed}) -> +% case emqx_sm:lookup_session(ClientId) of +% undefined -> +% {Success, [[{client_id, ClientId}]|Failed]}; +% #mqtt_session{sess_pid = SessPid} -> +% emqx_session:unsubscriber(SessPid, [{Topic, []}]), +% {[[{client_id, ClientId}]| Success], Failed} +% end +% end, {[], []}, UnSubscribers). %%-------------------------------------------------------------------- %% manager API @@ -263,9 +302,9 @@ kick_client(ClientId) -> lists:any(fun(Item) -> Item =:= ok end, Result). kick_client(Node, ClientId) when Node =:= node() -> - case emqttd_cm:lookup(ClientId) of + case emqx_cm:lookup(ClientId) of undefined -> error; - #mqtt_client{client_pid = Pid}-> emqttd_client:kick(Pid) + #mqtt_client{client_pid = Pid}-> emqx_client:kick(Pid) end; kick_client(Node, ClientId) -> rpc_call(Node, kick_client, [Node, ClientId]). @@ -276,9 +315,9 @@ clean_acl_cache(ClientId, Topic) -> lists:any(fun(Item) -> Item =:= ok end, Result). clean_acl_cache(Node, ClientId, Topic) when Node =:= node() -> - case emqttd_cm:lookup(ClientId) of + case emqx_cm:lookup(ClientId) of undefined -> error; - #mqtt_client{client_pid = Pid}-> emqttd_client:clean_acl_cache(Pid, Topic) + #mqtt_client{client_pid = Pid}-> emqx_client:clean_acl_cache(Pid, Topic) end; clean_acl_cache(Node, ClientId, Topic) -> rpc_call(Node, clean_acl_cache, [Node, ClientId, Topic]). @@ -287,14 +326,14 @@ clean_acl_cache(Node, ClientId, Topic) -> %% Config ENV %%-------------------------------------------------------------------- modify_config(App, Terms) -> - emqttd_config:write(App, Terms). + emqx_config:write(App, Terms). modify_config(App, Key, Value) -> Result = [modify_config(Node, App, Key, Value) || Node <- ekka_mnesia:running_nodes()], lists:any(fun(Item) -> Item =:= ok end, Result). modify_config(Node, App, Key, Value) when Node =:= node() -> - emqttd_config:set(App, Key, Value); + emqx_config:set(App, Key, Value); modify_config(Node, App, Key, Value) -> rpc_call(Node, modify_config, [Node, App, Key, Value]). @@ -302,17 +341,17 @@ get_configs() -> [{Node, get_config(Node)} || Node <- ekka_mnesia:running_nodes()]. get_config(Node) when Node =:= node()-> - emqttd_cli_config:all_cfgs(); + emqx_cli_config:all_cfgs(); get_config(Node) -> rpc_call(Node, get_config, [Node]). get_plugin_config(PluginName) -> - emqttd_config:read(PluginName). + emqx_config:read(PluginName). get_plugin_config(Node, PluginName) -> rpc_call(Node, get_plugin_config, [PluginName]). modify_plugin_config(PluginName, Terms) -> - emqttd_config:write(PluginName, Terms). + emqx_config:write(PluginName, Terms). modify_plugin_config(Node, PluginName, Terms) -> rpc_call(Node, modify_plugin_config, [PluginName, Terms]). @@ -428,7 +467,7 @@ validate(qos, Qos) -> (Qos >= ?QOS_0) and (Qos =< ?QOS_2); validate(topic, Topic) -> - emqttd_topic:validate({name, Topic}). + emqx_topic:validate({name, Topic}). client_list(ClientId, PageNo, PageSize) when ?EMPTY_KEY(ClientId) -> TotalNum = ets:info(mqtt_client, size), diff --git a/src/emqttd_misc.erl b/src/emqx_misc.erl similarity index 99% rename from src/emqttd_misc.erl rename to src/emqx_misc.erl index e60d27d4f..444b0de61 100644 --- a/src/emqttd_misc.erl +++ b/src/emqx_misc.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_misc). +-module(emqx_misc). -author("Feng Lee "). diff --git a/src/emqttd_mod_sup.erl b/src/emqx_mod_sup.erl similarity index 97% rename from src/emqttd_mod_sup.erl rename to src/emqx_mod_sup.erl index 586d5af1a..a3f4f19ff 100644 --- a/src/emqttd_mod_sup.erl +++ b/src/emqx_mod_sup.erl @@ -14,11 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_mod_sup). +-module(emqx_mod_sup). -behaviour(supervisor). --include("emqttd.hrl"). +-include("emqx.hrl"). %% API -export([start_link/0, start_child/1, start_child/2, stop_child/1]). diff --git a/src/emqttd_mqueue.erl b/src/emqx_mqueue.erl similarity index 98% rename from src/emqttd_mqueue.erl rename to src/emqx_mqueue.erl index 08e620a37..82cdc30b1 100644 --- a/src/emqttd_mqueue.erl +++ b/src/emqx_mqueue.erl @@ -41,13 +41,13 @@ %% %% @end --module(emqttd_mqueue). +-module(emqx_mqueue). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). -import(proplists, [get_value/3]). @@ -58,7 +58,7 @@ -define(HIGH_WM, 0.6). --define(PQUEUE, priority_queue). +-define(PQUEUE, emqx_pqueue). -type(priority() :: {iolist(), pos_integer()}). diff --git a/src/emqttd_net.erl b/src/emqx_net.erl similarity index 99% rename from src/emqttd_net.erl rename to src/emqx_net.erl index 1f246a315..a25e830e0 100644 --- a/src/emqttd_net.erl +++ b/src/emqx_net.erl @@ -14,7 +14,9 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_net). +-module(emqx_net). + +-author("Feng Lee "). -include_lib("kernel/include/inet.hrl"). diff --git a/src/emqttd_packet.erl b/src/emqx_packet.erl similarity index 88% rename from src/emqttd_packet.erl rename to src/emqx_packet.erl index 6349e58b1..ed690b7dd 100644 --- a/src/emqttd_packet.erl +++ b/src/emqx_packet.erl @@ -14,13 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_packet). +-module(emqx_packet). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). %% API -export([protocol_name/1, type_name/1, connack_name/1]). @@ -70,18 +70,18 @@ format_variable(Variable, Payload) -> io_lib:format("~s, Payload=~p", [format_variable(Variable), Payload]). format_variable(#mqtt_packet_connect{ - proto_ver = ProtoVer, - proto_name = ProtoName, - will_retain = WillRetain, - will_qos = WillQoS, - will_flag = WillFlag, - clean_sess = CleanSess, - keep_alive = KeepAlive, - client_id = ClientId, - will_topic = WillTopic, - will_msg = WillMsg, - username = Username, - password = Password}) -> + proto_ver = ProtoVer, + proto_name = ProtoName, + will_retain = WillRetain, + will_qos = WillQoS, + will_flag = WillFlag, + clean_sess = CleanSess, + keep_alive = KeepAlive, + client_id = ClientId, + will_topic = WillTopic, + will_msg = WillMsg, + username = Username, + password = Password}) -> Format = "ClientId=~s, ProtoName=~s, ProtoVsn=~p, CleanSess=~s, KeepAlive=~p, Username=~s, Password=~s", Args = [ClientId, ProtoName, ProtoVer, CleanSess, KeepAlive, Username, format_password(Password)], {Format1, Args1} = if diff --git a/src/emqttd_parser.erl b/src/emqx_parser.erl similarity index 99% rename from src/emqttd_parser.erl rename to src/emqx_parser.erl index dde9ae4dc..ba1624af1 100644 --- a/src/emqttd_parser.erl +++ b/src/emqx_parser.erl @@ -15,13 +15,13 @@ %%-------------------------------------------------------------------- %% @doc MQTT Packet Parser --module(emqttd_parser). +-module(emqx_parser). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). %% API -export([initial_state/0, initial_state/1, parse/2]). diff --git a/src/emqttd_plugins.erl b/src/emqx_plugins.erl similarity index 96% rename from src/emqttd_plugins.erl rename to src/emqx_plugins.erl index 73f184a3a..ad5523e54 100644 --- a/src/emqttd_plugins.erl +++ b/src/emqx_plugins.erl @@ -14,11 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_plugins). +-module(emqx_plugins). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). -export([init/0]). @@ -31,7 +31,7 @@ %% @doc Init plugins' config -spec(init() -> ok). init() -> - case emqttd:env(plugins_etc_dir) of + case emqx:env(plugins_etc_dir) of {ok, PluginsEtc} -> CfgFiles = [filename:join(PluginsEtc, File) || File <- filelib:wildcard("*.config", PluginsEtc)], @@ -49,7 +49,7 @@ init_config(CfgFile) -> %% @doc Load all plugins when the broker started. -spec(load() -> list() | {error, any()}). load() -> - case emqttd:env(plugins_loaded_file) of + case emqx:env(plugins_loaded_file) of {ok, File} -> ensure_file(File), with_loaded_file(File, fun(Names) -> load_plugins(Names, false) end); @@ -82,7 +82,7 @@ load_plugins(Names, Persistent) -> %% @doc Unload all plugins before broker stopped. -spec(unload() -> list() | {error, any()}). unload() -> - case emqttd:env(plugins_loaded_file) of + case emqx:env(plugins_loaded_file) of {ok, File} -> with_loaded_file(File, fun stop_plugins/1); undefined -> @@ -96,7 +96,7 @@ stop_plugins(Names) -> %% @doc List all available plugins -spec(list() -> [mqtt_plugin()]). list() -> - case emqttd:env(plugins_etc_dir) of + case emqx:env(plugins_etc_dir) of {ok, PluginsEtc} -> CfgFiles = filelib:wildcard("*.{conf,config}", PluginsEtc), Plugins = [plugin(CfgFile) || CfgFile <- CfgFiles], @@ -251,7 +251,7 @@ plugin_unloaded(Name, true) -> end. read_loaded() -> - case emqttd:env(plugins_loaded_file) of + case emqx:env(plugins_loaded_file) of {ok, File} -> read_loaded(File); undefined -> {error, not_found} end. @@ -259,7 +259,7 @@ read_loaded() -> read_loaded(File) -> file:consult(File). write_loaded(AppNames) -> - {ok, File} = emqttd:env(plugins_loaded_file), + {ok, File} = emqx:env(plugins_loaded_file), case file:open(File, [binary, write]) of {ok, Fd} -> lists:foreach(fun(Name) -> diff --git a/src/emqttd_pmon.erl b/src/emqx_pmon.erl similarity index 98% rename from src/emqttd_pmon.erl rename to src/emqx_pmon.erl index ebe691ad4..5efdd115e 100644 --- a/src/emqttd_pmon.erl +++ b/src/emqx_pmon.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_pmon). +-module(emqx_pmon). -author("Feng Lee "). diff --git a/src/emqttd_pool_sup.erl b/src/emqx_pool_sup.erl similarity index 94% rename from src/emqttd_pool_sup.erl rename to src/emqx_pool_sup.erl index fa1d6aace..afed06e87 100644 --- a/src/emqttd_pool_sup.erl +++ b/src/emqx_pool_sup.erl @@ -15,7 +15,7 @@ %%-------------------------------------------------------------------- %% @doc Common Pool Supervisor --module(emqttd_pool_sup). +-module(emqx_pool_sup). -author("Feng Lee "). @@ -41,7 +41,7 @@ start_link(Pool, Type, MFA) -> Schedulers = erlang:system_info(schedulers), start_link(Pool, Type, Schedulers, MFA). --spec(start_link(atom(), atom(), pos_integer(), mfa()) -> {ok, pid()} | {error, any()}). +-spec(start_link(atom() | tuple(), atom(), pos_integer(), mfa()) -> {ok, pid()} | {error, any()}). start_link(Pool, Type, Size, MFA) -> supervisor:start_link(?MODULE, [Pool, Type, Size, MFA]). diff --git a/src/emqttd_pooler.erl b/src/emqx_pooler.erl similarity index 94% rename from src/emqttd_pooler.erl rename to src/emqx_pooler.erl index 1b73d138c..c60a22e27 100644 --- a/src/emqttd_pooler.erl +++ b/src/emqx_pooler.erl @@ -14,11 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_pooler). +-module(emqx_pooler). + +-author("Feng Lee "). -behaviour(gen_server). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). %% Start the pool supervisor -export([start_link/0]). @@ -34,7 +36,7 @@ %% @doc Start Pooler Supervisor. start_link() -> - emqttd_pool_sup:start_link(pooler, random, {?MODULE, start_link, []}). + emqx_pool_sup:start_link(pooler, random, {?MODULE, start_link, []}). %%-------------------------------------------------------------------- %% API diff --git a/src/priority_queue.erl b/src/emqx_pqueue.erl similarity index 90% rename from src/priority_queue.erl rename to src/emqx_pqueue.erl index 7147b0bb4..f9392d5f6 100644 --- a/src/priority_queue.erl +++ b/src/emqx_pqueue.erl @@ -37,46 +37,27 @@ %% calls into the same function knowing that ordinary queues represent %% a base case. --module(priority_queue). +-module(emqx_pqueue). -export([new/0, is_queue/1, is_empty/1, len/1, plen/2, to_list/1, from_list/1, in/2, in/3, out/1, out/2, out_p/1, join/2, filter/2, fold/3, highest/1]). %%---------------------------------------------------------------------------- --ifdef(use_specs). - --type(q() :: pqueue()). -type(priority() :: integer() | 'infinity'). -type(squeue() :: {queue, [any()], [any()], non_neg_integer()}). -type(pqueue() :: squeue() | {pqueue, [{priority(), squeue()}]}). +-type(q() :: pqueue()). -export_type([q/0]). --spec(new/0 :: () -> pqueue()). --spec(is_queue/1 :: (any()) -> boolean()). --spec(is_empty/1 :: (pqueue()) -> boolean()). --spec(len/1 :: (pqueue()) -> non_neg_integer()). --spec(plen/2 :: (priority(), pqueue()) -> non_neg_integer()). --spec(to_list/1 :: (pqueue()) -> [{priority(), any()}]). --spec(from_list/1 :: ([{priority(), any()}]) -> pqueue()). --spec(in/2 :: (any(), pqueue()) -> pqueue()). --spec(in/3 :: (any(), priority(), pqueue()) -> pqueue()). --spec(out/1 :: (pqueue()) -> {empty | {value, any()}, pqueue()}). --spec(out_p/1 :: (pqueue()) -> {empty | {value, any(), priority()}, pqueue()}). --spec(join/2 :: (pqueue(), pqueue()) -> pqueue()). --spec(filter/2 :: (fun ((any()) -> boolean()), pqueue()) -> pqueue()). --spec(fold/3 :: - (fun ((any(), priority(), A) -> A), A, pqueue()) -> A). --spec(highest/1 :: (pqueue()) -> priority() | 'empty'). - --endif. - %%---------------------------------------------------------------------------- +-spec(new() -> pqueue()). new() -> {queue, [], [], 0}. +-spec(is_queue(any()) -> boolean()). is_queue({queue, R, F, L}) when is_list(R), is_list(F), is_integer(L) -> true; is_queue({pqueue, Queues}) when is_list(Queues) -> @@ -86,16 +67,19 @@ is_queue({pqueue, Queues}) when is_list(Queues) -> is_queue(_) -> false. +-spec(is_empty(pqueue()) -> boolean()). is_empty({queue, [], [], 0}) -> true; is_empty(_) -> false. +-spec(len(pqueue()) -> non_neg_integer()). len({queue, _R, _F, L}) -> L; len({pqueue, Queues}) -> lists:sum([len(Q) || {_, Q} <- Queues]). +-spec(plen(priority(), pqueue()) -> non_neg_integer()). plen(0, {queue, _R, _F, L}) -> L; plen(_, {queue, _R, _F, _}) -> @@ -106,18 +90,22 @@ plen(P, {pqueue, Queues}) -> false -> 0 end. +-spec(to_list(pqueue()) -> [{priority(), any()}]). to_list({queue, In, Out, _Len}) when is_list(In), is_list(Out) -> [{0, V} || V <- Out ++ lists:reverse(In, [])]; to_list({pqueue, Queues}) -> [{maybe_negate_priority(P), V} || {P, Q} <- Queues, {0, V} <- to_list(Q)]. +-spec(from_list([{priority(), any()}]) -> pqueue()). from_list(L) -> lists:foldl(fun ({P, E}, Q) -> in(E, P, Q) end, new(), L). +-spec(in(any(), pqueue()) -> pqueue()). in(Item, Q) -> in(Item, 0, Q). +-spec(in(any(), priority(), pqueue()) -> pqueue()). in(X, 0, {queue, [_] = In, [], 1}) -> {queue, [X], In, 2}; in(X, 0, {queue, In, Out, Len}) when is_list(In), is_list(Out) -> @@ -143,6 +131,7 @@ in(X, Priority, {pqueue, Queues}) -> end end}. +-spec(out(pqueue()) -> {empty | {value, any()}, pqueue()}). out({queue, [], [], 0} = Q) -> {empty, Q}; out({queue, [V], [], 1}) -> @@ -166,6 +155,7 @@ out({pqueue, [{P, Q} | Queues]}) -> end, {R, NewQ}. +-spec(out_p(pqueue()) -> {empty | {value, any(), priority()}, pqueue()}). out_p({queue, _, _, _} = Q) -> add_p(out(Q), 0); out_p({pqueue, [{P, _} | _]} = Q) -> add_p(out(Q), maybe_negate_priority(P)). @@ -196,6 +186,7 @@ add_p(R, P) -> case R of {{value, V}, Q} -> {{value, V, P}, Q} end. +-spec(join(pqueue(), pqueue()) -> pqueue()). join(A, {queue, [], [], 0}) -> A; join({queue, [], [], 0}, B) -> @@ -234,6 +225,7 @@ merge([{PA, A}|As], Bs = [{PB, _}|_], Acc) when PA < PB orelse PA == infinity -> merge(As = [{_, _}|_], [{PB, B}|Bs], Acc) -> merge(As, Bs, [ {PB, B} | Acc ]). +-spec(filter(fun ((any()) -> boolean()), pqueue()) -> pqueue()). filter(Pred, Q) -> fold(fun(V, P, Acc) -> case Pred(V) of true -> in(V, P, Acc); @@ -241,11 +233,13 @@ filter(Pred, Q) -> fold(fun(V, P, Acc) -> end end, new(), Q). +-spec(fold(fun ((any(), priority(), A) -> A), A, pqueue()) -> A). fold(Fun, Init, Q) -> case out_p(Q) of {empty, _Q} -> Init; {{value, V, P}, Q1} -> fold(Fun, Fun(V, P, Init), Q1) end. +-spec(highest(pqueue()) -> priority() | 'empty'). highest({queue, [], [], 0}) -> empty; highest({queue, _, _, _}) -> 0; highest({pqueue, [{P, _} | _]}) -> maybe_negate_priority(P). @@ -257,3 +251,4 @@ r2f([X,Y|R], L) -> {queue, [X,Y], lists:reverse(R, []), L}. maybe_negate_priority(infinity) -> infinity; maybe_negate_priority(P) -> -P. + diff --git a/src/emqttd_protocol.erl b/src/emqx_protocol.erl similarity index 80% rename from src/emqttd_protocol.erl rename to src/emqx_protocol.erl index 0129faedd..b03213310 100644 --- a/src/emqttd_protocol.erl +++ b/src/emqx_protocol.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_protocol). +-module(emqx_protocol). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -import(proplists, [get_value/2, get_value/3]). @@ -42,14 +42,15 @@ %% ws_initial_headers: Headers from first HTTP request for WebSocket Client. -record(proto_state, {peername, sendfun, connected = false, client_id, client_pid, clean_sess, proto_ver, proto_name, username, is_superuser, - will_msg, keepalive, keepalive_backoff, max_clientid_len, - session, stats_data, mountpoint, ws_initial_headers, - connected_at}). + will_msg, keepalive, max_clientid_len, session, stats_data, + keepalive_backoff, peercert_username, ws_initial_headers, + mountpoint, connected_at}). -type(proto_state() :: #proto_state{}). -define(INFO_KEYS, [client_id, username, clean_sess, proto_ver, proto_name, - keepalive, will_msg, ws_initial_headers, mountpoint, connected_at]). + keepalive, will_msg, ws_initial_headers, mountpoint, + peercert_username, connected_at]). -define(STATS_KEYS, [recv_pkt, recv_msg, send_pkt, send_msg]). @@ -68,6 +69,7 @@ init(Peername, SendFun, Opts) -> max_clientid_len = MaxLen, is_superuser = false, client_pid = self(), + peercert_username = false, ws_initial_headers = WsInitialHeaders, keepalive_backoff = Backoff, stats_data = #proto_stats{enable_stats = EnableStats}}. @@ -79,9 +81,28 @@ enrich_opt([], _Conn, State) -> State; enrich_opt([{mountpoint, MountPoint} | ConnOpts], Conn, State) -> enrich_opt(ConnOpts, Conn, State#proto_state{mountpoint = MountPoint}); +enrich_opt([{peer_cert_as_username, N} | ConnOpts], Conn, State) -> + case Conn:type() of + ssl -> enrich_opt(ConnOpts, Conn, State#proto_state{ + peercert_username = peercert_username(N, Conn:peercert())}); + _ -> enrich_opt(ConnOpts, Conn, State) + end; enrich_opt([_ | ConnOpts], Conn, State) -> enrich_opt(ConnOpts, Conn, State). +peercert_username(cn, Cert) -> + case emqx_ssl:peer_cert_common_name(Cert) of + not_found -> undefined; + CN -> iolist_to_binary(CN) + end; +peercert_username(dn, Cert) -> + iolist_to_binary(emqx_ssl:peer_cert_subject(Cert)). + +repl_username_with_peercert(State = #proto_state{peercert_username = false}) -> + State; +repl_username_with_peercert(State = #proto_state{peercert_username = PeerCert}) -> + State#proto_state{username = PeerCert}. + info(ProtoState) -> ?record_to_proplist(proto_state, ProtoState, ?INFO_KEYS). @@ -150,9 +171,9 @@ subscribe(RawTopicTable, ProtoState = #proto_state{client_id = ClientId, username = Username, session = Session}) -> TopicTable = parse_topic_table(RawTopicTable), - case emqttd_hooks:run('client.subscribe', [ClientId, Username], TopicTable) of + case emqx_hooks:run('client.subscribe', [ClientId, Username], TopicTable) of {ok, TopicTable1} -> - emqttd_session:subscribe(Session, TopicTable1); + emqx_session:subscribe(Session, TopicTable1); {stop, _} -> ok end, @@ -161,9 +182,9 @@ subscribe(RawTopicTable, ProtoState = #proto_state{client_id = ClientId, unsubscribe(RawTopics, ProtoState = #proto_state{client_id = ClientId, username = Username, session = Session}) -> - case emqttd_hooks:run('client.unsubscribe', [ClientId, Username], parse_topics(RawTopics)) of + case emqx_hooks:run('client.unsubscribe', [ClientId, Username], parse_topics(RawTopics)) of {ok, TopicTable} -> - emqttd_session:unsubscribe(Session, TopicTable); + emqx_session:unsubscribe(Session, TopicTable); {stop, _} -> ok end, @@ -182,14 +203,15 @@ process(?CONNECT_PACKET(Var), State0) -> keep_alive = KeepAlive, client_id = ClientId} = Var, - State1 = State0#proto_state{proto_ver = ProtoVer, - proto_name = ProtoName, - username = Username, - client_id = ClientId, - clean_sess = CleanSess, - keepalive = KeepAlive, - will_msg = willmsg(Var, State0), - connected_at = os:timestamp()}, + State1 = repl_username_with_peercert( + State0#proto_state{proto_ver = ProtoVer, + proto_name = ProtoName, + username = Username, + client_id = ClientId, + clean_sess = CleanSess, + keepalive = KeepAlive, + will_msg = willmsg(Var, State0), + connected_at = os:timestamp()}), {ReturnCode1, SessPresent, State3} = case validate_connect(Var, State1) of @@ -200,10 +222,10 @@ process(?CONNECT_PACKET(Var), State0) -> State2 = maybe_set_clientid(State1), %% Start session - case emqttd_sm:start_session(CleanSess, {clientid(State2), Username}) of + case emqx_sm:start_session(CleanSess, {clientid(State2), Username}) of {ok, Session, SP} -> %% Register the client - emqttd_cm:reg(client(State2)), + emqx_cm:reg(client(State2)), %% Start keepalive start_keepalive(KeepAlive, State2), %% Emit Stats @@ -221,7 +243,7 @@ process(?CONNECT_PACKET(Var), State0) -> {ReturnCode, false, State1} end, %% Run hooks - emqttd_hooks:run('client.connected', [ReturnCode1], client(State3)), + emqx_hooks:run('client.connected', [ReturnCode1], client(State3)), %% Send connack send(?CONNACK_PACKET(ReturnCode1, sp(SessPresent)), State3), %% stop if authentication failure @@ -235,19 +257,19 @@ process(Packet = ?PUBLISH_PACKET(_Qos, Topic, _PacketId, _Payload), State = #pro {ok, State}; process(?PUBACK_PACKET(?PUBACK, PacketId), State = #proto_state{session = Session}) -> - emqttd_session:puback(Session, PacketId), + emqx_session:puback(Session, PacketId), {ok, State}; process(?PUBACK_PACKET(?PUBREC, PacketId), State = #proto_state{session = Session}) -> - emqttd_session:pubrec(Session, PacketId), + emqx_session:pubrec(Session, PacketId), send(?PUBREL_PACKET(PacketId), State); process(?PUBACK_PACKET(?PUBREL, PacketId), State = #proto_state{session = Session}) -> - emqttd_session:pubrel(Session, PacketId), + emqx_session:pubrel(Session, PacketId), send(?PUBACK_PACKET(?PUBCOMP, PacketId), State); process(?PUBACK_PACKET(?PUBCOMP, PacketId), State = #proto_state{session = Session})-> - emqttd_session:pubcomp(Session, PacketId), {ok, State}; + emqx_session:pubcomp(Session, PacketId), {ok, State}; %% Protect from empty topic table process(?SUBSCRIBE_PACKET(PacketId, []), State) -> @@ -270,9 +292,9 @@ process(?SUBSCRIBE_PACKET(PacketId, RawTopicTable), ?LOG(error, "Cannot SUBSCRIBE ~p for ACL Deny", [TopicTable], State), send(?SUBACK_PACKET(PacketId, [16#80 || _ <- TopicTable]), State); false -> - case emqttd_hooks:run('client.subscribe', [ClientId, Username], TopicTable) of + case emqx_hooks:run('client.subscribe', [ClientId, Username], TopicTable) of {ok, TopicTable1} -> - emqttd_session:subscribe(Session, PacketId, mount(MountPoint, TopicTable1)), + emqx_session:subscribe(Session, PacketId, mount(MountPoint, TopicTable1)), {ok, State}; {stop, _} -> {ok, State} @@ -288,9 +310,9 @@ process(?UNSUBSCRIBE_PACKET(PacketId, RawTopics), username = Username, mountpoint = MountPoint, session = Session}) -> - case emqttd_hooks:run('client.unsubscribe', [ClientId, Username], parse_topics(RawTopics)) of + case emqx_hooks:run('client.unsubscribe', [ClientId, Username], parse_topics(RawTopics)) of {ok, TopicTable} -> - emqttd_session:unsubscribe(Session, mount(MountPoint, TopicTable)); + emqx_session:unsubscribe(Session, mount(MountPoint, TopicTable)); {stop, _} -> ok end, @@ -308,8 +330,8 @@ publish(Packet = ?PUBLISH_PACKET(?QOS_0, _PacketId), username = Username, mountpoint = MountPoint, session = Session}) -> - Msg = emqttd_message:from_packet(Username, ClientId, Packet), - emqttd_session:publish(Session, mount(MountPoint, Msg)); + Msg = emqx_message:from_packet(Username, ClientId, Packet), + emqx_session:publish(Session, mount(MountPoint, Msg)); publish(Packet = ?PUBLISH_PACKET(?QOS_1, _PacketId), State) -> with_puback(?PUBACK, Packet, State); @@ -322,8 +344,8 @@ with_puback(Type, Packet = ?PUBLISH_PACKET(_Qos, PacketId), username = Username, mountpoint = MountPoint, session = Session}) -> - Msg = emqttd_message:from_packet(Username, ClientId, Packet), - case emqttd_session:publish(Session, mount(MountPoint, Msg)) of + Msg = emqx_message:from_packet(Username, ClientId, Packet), + case emqx_session:publish(Session, mount(MountPoint, Msg)) of ok -> send(?PUBACK_PACKET(Type, PacketId), State); {error, Error} -> @@ -335,22 +357,22 @@ send(Msg, State = #proto_state{client_id = ClientId, username = Username, mountpoint = MountPoint}) when is_record(Msg, mqtt_message) -> - emqttd_hooks:run('message.delivered', [ClientId, Username], Msg), - send(emqttd_message:to_packet(unmount(MountPoint, Msg)), State); + emqx_hooks:run('message.delivered', [ClientId, Username], Msg), + send(emqx_message:to_packet(unmount(MountPoint, Msg)), State); send(Packet = ?PACKET(Type), State = #proto_state{sendfun = SendFun, stats_data = Stats}) -> trace(send, Packet, State), - emqttd_metrics:sent(Packet), + emqx_metrics:sent(Packet), SendFun(Packet), Stats1 = inc_stats(send, Type, Stats), {ok, State#proto_state{stats_data = Stats1}}. trace(recv, Packet, ProtoState) -> - ?LOG(debug, "RECV ~s", [emqttd_packet:format(Packet)], ProtoState); + ?LOG(info, "RECV ~s", [emqx_packet:format(Packet)], ProtoState); trace(send, Packet, ProtoState) -> - ?LOG(debug, "SEND ~s", [emqttd_packet:format(Packet)], ProtoState). + ?LOG(info, "SEND ~s", [emqx_packet:format(Packet)], ProtoState). inc_stats(_Direct, _Type, Stats = #proto_stats{enable_stats = false}) -> Stats; @@ -381,20 +403,20 @@ shutdown(_Error, #proto_state{client_id = undefined}) -> shutdown(conflict, #proto_state{client_id = _ClientId}) -> %% let it down - %% emqttd_cm:unreg(ClientId); + %% emqx_cm:unreg(ClientId); ignore; shutdown(Error, State = #proto_state{will_msg = WillMsg}) -> - ?LOG(debug, "Shutdown for ~p", [Error], State), + ?LOG(info, "Shutdown for ~p", [Error], State), Client = client(State), send_willmsg(Client, WillMsg), - emqttd_hooks:run('client.disconnected', [Error], Client), + emqx_hooks:run('client.disconnected', [Error], Client), %% let it down - %% emqttd_cm:unreg(ClientId). + %% emqx_cm:unreg(ClientId). ok. willmsg(Packet, #proto_state{mountpoint = MountPoint}) when is_record(Packet, mqtt_packet_connect) -> - case emqttd_message:from_packet(Packet) of + case emqx_message:from_packet(Packet) of undefined -> undefined; Msg -> mount(MountPoint, Msg) end. @@ -402,8 +424,8 @@ willmsg(Packet, #proto_state{mountpoint = MountPoint}) when is_record(Packet, mq %% Generate a client if if nulll maybe_set_clientid(State = #proto_state{client_id = NullId}) when NullId =:= undefined orelse NullId =:= <<>> -> - {_, NPid, _} = emqttd_guid:new(), - ClientId = iolist_to_binary(["emqttd_", integer_to_list(NPid)]), + {_, NPid, _} = emqx_guid:new(), + ClientId = iolist_to_binary(["emqx_", integer_to_list(NPid)]), State#proto_state{client_id = ClientId}; maybe_set_clientid(State) -> @@ -412,7 +434,7 @@ maybe_set_clientid(State) -> send_willmsg(_Client, undefined) -> ignore; send_willmsg(#mqtt_client{client_id = ClientId, username = Username}, WillMsg) -> - emqttd:publish(WillMsg#mqtt_message{from = {ClientId, Username}}). + emqx_server:publish(WillMsg#mqtt_message{from = {ClientId, Username}}). start_keepalive(0, _State) -> ignore; @@ -463,7 +485,7 @@ validate_clientid(#mqtt_packet_connect{proto_ver = ProtoVer, false. validate_packet(?PUBLISH_PACKET(_Qos, Topic, _PacketId, _Payload)) -> - case emqttd_topic:validate({name, Topic}) of + case emqx_topic:validate({name, Topic}) of true -> ok; false -> {error, badtopic} end; @@ -483,7 +505,7 @@ validate_topics(_Type, []) -> validate_topics(Type, TopicTable = [{_Topic, _Qos}|_]) when Type =:= name orelse Type =:= filter -> Valid = fun(Topic, Qos) -> - emqttd_topic:validate({Type, Topic}) and validate_qos(Qos) + emqx_topic:validate({Type, Topic}) and validate_qos(Qos) end, case [Topic || {Topic, Qos} <- TopicTable, not Valid(Topic, Qos)] of [] -> ok; @@ -491,7 +513,7 @@ validate_topics(Type, TopicTable = [{_Topic, _Qos}|_]) end; validate_topics(Type, Topics = [Topic0|_]) when is_binary(Topic0) -> - case [Topic || Topic <- Topics, not emqttd_topic:validate({Type, Topic})] of + case [Topic || Topic <- Topics, not emqx_topic:validate({Type, Topic})] of [] -> ok; _ -> {error, badtopic} end. @@ -505,15 +527,15 @@ validate_qos(_) -> parse_topic_table(TopicTable) -> lists:map(fun({Topic0, Qos}) -> - {Topic, Opts} = emqttd_topic:parse(Topic0), + {Topic, Opts} = emqx_topic:parse(Topic0), {Topic, [{qos, Qos}|Opts]} end, TopicTable). parse_topics(Topics) -> - [emqttd_topic:parse(Topic) || Topic <- Topics]. + [emqx_topic:parse(Topic) || Topic <- Topics]. authenticate(Client, Password) -> - case emqttd_access_control:auth(Client, Password) of + case emqx_access_control:auth(Client, Password) of ok -> {ok, false}; {ok, IsSuper} -> {ok, IsSuper}; {error, Error} -> {error, Error} @@ -521,20 +543,20 @@ authenticate(Client, Password) -> %% PUBLISH ACL is cached in process dictionary. check_acl(publish, Topic, Client) -> - IfCache = emqttd:env(cache_acl, true), + IfCache = emqx:env(cache_acl, true), case {IfCache, get({acl, publish, Topic})} of {true, undefined} -> - AllowDeny = emqttd_access_control:check_acl(Client, publish, Topic), + AllowDeny = emqx_access_control:check_acl(Client, publish, Topic), put({acl, publish, Topic}, AllowDeny), AllowDeny; {true, AllowDeny} -> AllowDeny; {false, _} -> - emqttd_access_control:check_acl(Client, publish, Topic) + emqx_access_control:check_acl(Client, publish, Topic) end; check_acl(subscribe, Topic, Client) -> - emqttd_access_control:check_acl(Client, subscribe, Topic). + emqx_access_control:check_acl(Client, subscribe, Topic). sp(true) -> 1; sp(false) -> 0. diff --git a/src/emqttd_pubsub.erl b/src/emqx_pubsub.erl similarity index 86% rename from src/emqttd_pubsub.erl rename to src/emqx_pubsub.erl index d976618cd..541007975 100644 --- a/src/emqttd_pubsub.erl +++ b/src/emqx_pubsub.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_pubsub). +-module(emqx_pubsub). -behaviour(gen_server2). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -export([start_link/3]). @@ -55,22 +55,23 @@ start_link(Pool, Id, Env) -> %%-------------------------------------------------------------------- %% @doc Subscribe a Topic --spec(subscribe(binary(), emqttd:subscriber(), [emqttd:suboption()]) -> ok). +-spec(subscribe(binary(), emqx:subscriber(), [emqx:suboption()]) -> ok). subscribe(Topic, Subscriber, Options) -> call(pick(Topic), {subscribe, Topic, Subscriber, Options}). --spec(async_subscribe(binary(), emqttd:subscriber(), [emqttd:suboption()]) -> ok). +-spec(async_subscribe(binary(), emqx:subscriber(), [emqx:suboption()]) -> ok). async_subscribe(Topic, Subscriber, Options) -> cast(pick(Topic), {subscribe, Topic, Subscriber, Options}). -%% @doc Publish MQTT Message to Topic +%% @doc Publish Message to a Topic -spec(publish(binary(), any()) -> {ok, mqtt_delivery()} | ignore). publish(Topic, Msg) -> - route(lists:append(emqttd_router:match(Topic), - emqttd_router:match_local(Topic)), delivery(Msg)). + route(lists:append(emqx_router:match(Topic), + emqx_router:match_local(Topic)), delivery(Msg)). -route([], #mqtt_delivery{message = #mqtt_message{topic = Topic}}) -> - dropped(Topic), ignore; +route([], #mqtt_delivery{message = Msg}) -> + emqx_hooks:run('message.offline', [undefined, Msg]), + dropped(Msg#mqtt_message.topic), ignore; %% Dispatch on the local node route([#mqtt_route{topic = To, node = Node}], @@ -90,13 +91,14 @@ delivery(Msg) -> #mqtt_delivery{sender = self(), message = Msg, flows = []}. %% @doc Forward message to another node... forward(Node, To, Delivery) -> - rpc:cast(Node, ?PUBSUB, dispatch, [To, Delivery]), {ok, Delivery}. + emqx_rpc:cast(Node, ?PUBSUB, dispatch, [To, Delivery]), {ok, Delivery}. %% @doc Dispatch Message to Subscribers -spec(dispatch(binary(), mqtt_delivery()) -> mqtt_delivery()). dispatch(Topic, Delivery = #mqtt_delivery{message = Msg, flows = Flows}) -> case subscribers(Topic) of [] -> + emqx_hooks:run('message.offline', [undefined, Msg]), dropped(Topic), {ok, Delivery}; [Sub] -> %% optimize? dispatch(Sub, Topic, Msg), @@ -110,7 +112,7 @@ dispatch(Topic, Delivery = #mqtt_delivery{message = Msg, flows = Flows}) -> dispatch(Pid, Topic, Msg) when is_pid(Pid) -> Pid ! {dispatch, Topic, Msg}; dispatch(SubId, Topic, Msg) when is_binary(SubId) -> - emqttd_sm:dispatch(SubId, Topic, Msg); + emqx_sm:dispatch(SubId, Topic, Msg); dispatch({_Share, [Sub]}, Topic, Msg) -> dispatch(Sub, Topic, Msg); dispatch({_Share, []}, _Topic, _Msg) -> @@ -138,14 +140,14 @@ group_by_share(Subscribers) -> dropped(<<"$SYS/", _/binary>>) -> ok; dropped(_Topic) -> - emqttd_metrics:inc('messages/dropped'). + emqx_metrics:inc('messages/dropped'). %% @doc Unsubscribe --spec(unsubscribe(binary(), emqttd:subscriber(), [emqttd:suboption()]) -> ok). +-spec(unsubscribe(binary(), emqx:subscriber(), [emqx:suboption()]) -> ok). unsubscribe(Topic, Subscriber, Options) -> call(pick(Topic), {unsubscribe, Topic, Subscriber, Options}). --spec(async_unsubscribe(binary(), emqttd:subscriber(), [emqttd:suboption()]) -> ok). +-spec(async_unsubscribe(binary(), emqx:subscriber(), [emqx:suboption()]) -> ok). async_unsubscribe(Topic, Subscriber, Options) -> cast(pick(Topic), {unsubscribe, Topic, Subscriber, Options}). @@ -210,11 +212,11 @@ add_subscriber(Topic, Subscriber, Options) -> end. add_subscriber_(Share, Topic, Subscriber) -> - (not ets:member(mqtt_subscriber, Topic)) andalso emqttd_router:add_route(Topic), + (not ets:member(mqtt_subscriber, Topic)) andalso emqx_router:add_route(Topic), ets:insert(mqtt_subscriber, {Topic, shared(Share, Subscriber)}). add_local_subscriber_(Share, Topic, Subscriber) -> - (not ets:member(mqtt_subscriber, {local, Topic})) andalso emqttd_router:add_local_route(Topic), + (not ets:member(mqtt_subscriber, {local, Topic})) andalso emqx_router:add_local_route(Topic), ets:insert(mqtt_subscriber, {{local, Topic}, shared(Share, Subscriber)}). del_subscriber(Topic, Subscriber, Options) -> @@ -226,11 +228,11 @@ del_subscriber(Topic, Subscriber, Options) -> del_subscriber_(Share, Topic, Subscriber) -> ets:delete_object(mqtt_subscriber, {Topic, shared(Share, Subscriber)}), - (not ets:member(mqtt_subscriber, Topic)) andalso emqttd_router:del_route(Topic). + (not ets:member(mqtt_subscriber, Topic)) andalso emqx_router:del_route(Topic). del_local_subscriber_(Share, Topic, Subscriber) -> ets:delete_object(mqtt_subscriber, {{local, Topic}, shared(Share, Subscriber)}), - (not ets:member(mqtt_subscriber, {local, Topic})) andalso emqttd_router:del_local_route(Topic). + (not ets:member(mqtt_subscriber, {local, Topic})) andalso emqx_router:del_local_route(Topic). shared(undefined, Subscriber) -> Subscriber; @@ -238,6 +240,6 @@ shared(Share, Subscriber) -> {Share, Subscriber}. setstats(State) -> - emqttd_stats:setstats('subscribers/count', 'subscribers/max', ets:info(mqtt_subscriber, size)), + emqx_stats:setstats('subscribers/count', 'subscribers/max', ets:info(mqtt_subscriber, size)), State. diff --git a/src/emqttd_pubsub_sup.erl b/src/emqx_pubsub_sup.erl similarity index 94% rename from src/emqttd_pubsub_sup.erl rename to src/emqx_pubsub_sup.erl index 09d08d110..c203ed5c3 100644 --- a/src/emqttd_pubsub_sup.erl +++ b/src/emqx_pubsub_sup.erl @@ -15,7 +15,7 @@ %%-------------------------------------------------------------------- %% @doc PubSub Supervisor. --module(emqttd_pubsub_sup). +-module(emqx_pubsub_sup). -author("Feng Lee "). @@ -44,7 +44,7 @@ pubsub_pool() -> %%-------------------------------------------------------------------- init([]) -> - {ok, Env} = emqttd:env(pubsub), + {ok, Env} = emqx:env(pubsub), %% Create ETS Tables [create_tab(Tab) || Tab <- [mqtt_subproperty, mqtt_subscriber, mqtt_subscription]], {ok, { {one_for_all, 10, 3600}, [pool_sup(pubsub, Env), pool_sup(server, Env)]} }. @@ -59,9 +59,9 @@ pool_size(Env) -> pool_sup(Name, Env) -> Pool = list_to_atom(atom_to_list(Name) ++ "_pool"), - Mod = list_to_atom("emqttd_" ++ atom_to_list(Name)), + Mod = list_to_atom("emqx_" ++ atom_to_list(Name)), MFA = {Mod, start_link, [Env]}, - emqttd_pool_sup:spec(Pool, [Name, hash, pool_size(Env), MFA]). + emqx_pool_sup:spec(Pool, [Name, hash, pool_size(Env), MFA]). %%-------------------------------------------------------------------- %% Create PubSub Tables diff --git a/src/emqttd_rest_api.erl b/src/emqx_rest_api.erl similarity index 86% rename from src/emqttd_rest_api.erl rename to src/emqx_rest_api.erl index baa056b81..f405f1ce5 100644 --- a/src/emqttd_rest_api.erl +++ b/src/emqx_rest_api.erl @@ -13,11 +13,12 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %%-------------------------------------------------------------------- --module (emqttd_rest_api). --include("emqttd.hrl"). +-module (emqx_rest_api). --include("emqttd_internal.hrl"). +-include("emqx.hrl"). + +-include("emqx_rest.hrl"). -http_api({"^nodes/(.+?)/alarms/?$", 'GET', alarm_list, []}). @@ -94,7 +95,7 @@ %% alarm %%-------------------------------------------------------------------------- alarm_list('GET', _Req, _Node) -> - Alarms = emqttd_mgmt:alarm_list(), + Alarms = emqx_mgmt:alarm_list(), {ok, lists:map(fun alarm_row/1, Alarms)}. alarm_row(#mqtt_alarm{id = AlarmId, @@ -112,12 +113,12 @@ alarm_row(#mqtt_alarm{id = AlarmId, %% client %%-------------------------------------------------------------------------- client('GET', _Params, Key) -> - Data = emqttd_mgmt:client(l2b(Key)), + Data = emqx_mgmt:client(l2b(Key)), {ok, [{objects, [client_row(Row) || Row <- Data]}]}. client_list('GET', Params, Node) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:client_list(l2a(Node), undefined, PageNo, PageSize), + Data = emqx_mgmt:client_list(l2a(Node), undefined, PageNo, PageSize), Rows = get_value(result, Data), TotalPage = get_value(totalPage, Data), TotalNum = get_value(totalNum, Data), @@ -129,11 +130,11 @@ client_list('GET', Params, Node) -> client_list('GET', Params, Node, Key) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:client_list(l2a(Node), l2b(Key), PageNo, PageSize), + Data = emqx_mgmt:client_list(l2a(Node), l2b(Key), PageNo, PageSize), {ok, [{objects, [client_row(Row) || Row <- Data]}]}. kick_client('DELETE', _Params, Key) -> - case emqttd_mgmt:kick_client(l2b(Key)) of + case emqx_mgmt:kick_client(l2b(Key)) of true -> {ok, []}; false -> {error, [{code, ?ERROR12}]} end. @@ -141,7 +142,7 @@ kick_client('DELETE', _Params, Key) -> clean_acl_cache('PUT', Params, Key0) -> Topic = get_value(<<"topic">>, Params), [Key | _] = string:tokens(Key0, "/"), - case emqttd_mgmt:clean_acl_cache(l2b(Key), Topic) of + case emqx_mgmt:clean_acl_cache(l2b(Key), Topic) of true -> {ok, []}; false -> {error, [{code, ?ERROR12}]} end. @@ -166,12 +167,12 @@ client_row(#mqtt_client{client_id = ClientId, %% route %%-------------------------------------------------------------------------- route('GET', _Params, Key) -> - Data = emqttd_mgmt:route(l2b(Key)), + Data = emqx_mgmt:route(l2b(Key)), {ok, [{objects, [route_row(Row) || Row <- Data]}]}. route_list('GET', Params) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:route_list(undefined, PageNo, PageSize), + Data = emqx_mgmt:route_list(undefined, PageNo, PageSize), Rows = get_value(result, Data), TotalPage = get_value(totalPage, Data), TotalNum = get_value(totalNum, Data), @@ -191,12 +192,12 @@ route_row({Topic, Node}) -> %% session %%-------------------------------------------------------------------------- session('GET', _Params, Key) -> - Data = emqttd_mgmt:session(l2b(Key)), + Data = emqx_mgmt:session(l2b(Key)), {ok, [{objects, [session_row(Row) || Row <- Data]}]}. session_list('GET', Params, Node) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:session_list(l2a(Node), undefined, PageNo, PageSize), + Data = emqx_mgmt:session_list(l2a(Node), undefined, PageNo, PageSize), Rows = get_value(result, Data), TotalPage = get_value(totalPage, Data), TotalNum = get_value(totalNum, Data), @@ -208,7 +209,7 @@ session_list('GET', Params, Node) -> session_list('GET', Params, Node, ClientId) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:session_list(l2a(Node), l2b(ClientId), PageNo, PageSize), + Data = emqx_mgmt:session_list(l2a(Node), l2b(ClientId), PageNo, PageSize), {ok, [{objects, [session_row(Row) || Row <- Data]}]}. session_row({ClientId, _Pid, _Persistent, Session}) -> @@ -220,12 +221,12 @@ session_row({ClientId, _Pid, _Persistent, Session}) -> %% subscription %%-------------------------------------------------------------------------- subscription('GET', _Params, Key) -> - Data = emqttd_mgmt:subscription(l2b(Key)), + Data = emqx_mgmt:subscription(l2b(Key)), {ok, [{objects, [subscription_row(Row) || Row <- Data]}]}. subscription_list('GET', Params, Node) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:subscription_list(l2a(Node), undefined, PageNo, PageSize), + Data = emqx_mgmt:subscription_list(l2a(Node), undefined, PageNo, PageSize), Rows = get_value(result, Data), TotalPage = get_value(totalPage, Data), TotalNum = get_value(totalNum, Data), @@ -237,7 +238,7 @@ subscription_list('GET', Params, Node) -> subscription_list('GET', Params, Node, Key) -> {PageNo, PageSize} = page_params(Params), - Data = emqttd_mgmt:subscription_list(l2a(Node), l2b(Key), PageNo, PageSize), + Data = emqx_mgmt:subscription_list(l2a(Node), l2b(Key), PageNo, PageSize), {ok, [{objects, [subscription_row(Row) || Row <- Data]}]}. subscription_row({{Topic, ClientId}, Option}) when is_pid(ClientId) -> @@ -250,43 +251,43 @@ subscription_row({{Topic, ClientId}, Option}) -> %% management/monitoring %%-------------------------------------------------------------------------- nodes('GET', _Params) -> - Data = emqttd_mgmt:nodes_info(), + Data = emqx_mgmt:nodes_info(), {ok, Data}. node('GET', _Params, Node) -> - Data = emqttd_mgmt:node_info(l2a(Node)), + Data = emqx_mgmt:node_info(l2a(Node)), {ok, Data}. brokers('GET', _Params) -> - Data = emqttd_mgmt:brokers(), + Data = emqx_mgmt:brokers(), {ok, [format_broker(Node, Broker) || {Node, Broker} <- Data]}. broker('GET', _Params, Node) -> - Data = emqttd_mgmt:broker(l2a(Node)), + Data = emqx_mgmt:broker(l2a(Node)), {ok, format_broker(Data)}. listeners('GET', _Params) -> - Data = emqttd_mgmt:listeners(), - {ok, [[{Node, format_listeners(Listeners, [])} || {Node, Listeners} <- Data]]}. + Data = emqx_mgmt:listeners(), + {ok, [{Node, format_listeners(Listeners, [])} || {Node, Listeners} <- Data]}. listener('GET', _Params, Node) -> - Data = emqttd_mgmt:listener(l2a(Node)), + Data = emqx_mgmt:listener(l2a(Node)), {ok, [format_listener(Listeners) || Listeners <- Data]}. metrics('GET', _Params) -> - Data = emqttd_mgmt:metrics(), - {ok, [Data]}. + Data = emqx_mgmt:metrics(), + {ok, Data}. metric('GET', _Params, Node) -> - Data = emqttd_mgmt:metrics(l2a(Node)), + Data = emqx_mgmt:metrics(l2a(Node)), {ok, Data}. stats('GET', _Params) -> - Data = emqttd_mgmt:stats(), + Data = emqx_mgmt:stats(), {ok, [Data]}. stat('GET', _Params, Node) -> - Data = emqttd_mgmt:stats(l2a(Node)), + Data = emqx_mgmt:stats(l2a(Node)), {ok, Data}. format_broker(Node, Broker) -> @@ -321,12 +322,12 @@ format_listener({Protocol, ListenOn, Info}) -> %% mqtt %%-------------------------------------------------------------------------- publish('POST', Params) -> - Topic = get_value(<<"topic">>, Params), + Topic = get_value(<<"topic">>, Params), ClientId = get_value(<<"client_id">>, Params, http), - Payload = get_value(<<"payload">>, Params, <<>>), - Qos = get_value(<<"qos">>, Params, 0), - Retain = get_value(<<"retain">>, Params, false), - case emqttd_mgmt:publish({ClientId, Topic, Payload, Qos, Retain}) of + Payload = get_value(<<"payload">>, Params, <<>>), + Qos = get_value(<<"qos">>, Params, 0), + Retain = get_value(<<"retain">>, Params, false), + case emqx_mgmt:publish({ClientId, Topic, Payload, Qos, Retain}) of ok -> {ok, []}; {error, Error} -> @@ -337,7 +338,7 @@ subscribe('POST', Params) -> ClientId = get_value(<<"client_id">>, Params), Topic = get_value(<<"topic">>, Params), Qos = get_value(<<"qos">>, Params, 0), - case emqttd_mgmt:subscribe({ClientId, Topic, Qos}) of + case emqx_mgmt:subscribe({ClientId, Topic, Qos}) of ok -> {ok, []}; {error, Error} -> @@ -347,7 +348,7 @@ subscribe('POST', Params) -> unsubscribe('POST', Params) -> ClientId = get_value(<<"client_id">>, Params), Topic = get_value(<<"topic">>, Params), - case emqttd_mgmt:unsubscribe({ClientId, Topic})of + case emqx_mgmt:unsubscribe({ClientId, Topic})of ok -> {ok, []}; {error, Error} -> @@ -358,16 +359,16 @@ unsubscribe('POST', Params) -> %% plugins %%-------------------------------------------------------------------------- plugin_list('GET', _Params, Node) -> - Plugins = lists:map(fun plugin/1, emqttd_mgmt:plugin_list(l2a(Node))), + Plugins = lists:map(fun plugin/1, emqx_mgmt:plugin_list(l2a(Node))), {ok, Plugins}. enabled('PUT', Params, Node, PluginName) -> Active = get_value(<<"active">>, Params), case Active of true -> - return(emqttd_mgmt:plugin_load(l2a(Node), l2a(PluginName))); + return(emqx_mgmt:plugin_load(l2a(Node), l2a(PluginName))); false -> - return(emqttd_mgmt:plugin_unload(l2a(Node), l2a(PluginName))) + return(emqx_mgmt:plugin_unload(l2a(Node), l2a(PluginName))) end. return(Result) -> @@ -397,7 +398,7 @@ plugin(#mqtt_plugin{name = Name, version = Ver, descr = Descr, modify_config('PUT', Params, App) -> Key = get_value(<<"key">>, Params, <<"">>), Value = get_value(<<"value">>, Params, <<"">>), - case emqttd_mgmt:modify_config(l2a(App), b2l(Key), b2l(Value)) of + case emqx_mgmt:modify_config(l2a(App), b2l(Key), b2l(Value)) of true -> {ok, []}; false -> {error, [{code, ?ERROR2}]} end. @@ -405,26 +406,26 @@ modify_config('PUT', Params, App) -> modify_config('PUT', Params, Node, App) -> Key = get_value(<<"key">>, Params, <<"">>), Value = get_value(<<"value">>, Params, <<"">>), - case emqttd_mgmt:modify_config(l2a(Node), l2a(App), b2l(Key), b2l(Value)) of + case emqx_mgmt:modify_config(l2a(Node), l2a(App), b2l(Key), b2l(Value)) of ok -> {ok, []}; _ -> {error, [{code, ?ERROR2}]} end. config_list('GET', _Params) -> - Data = emqttd_mgmt:get_configs(), + Data = emqx_mgmt:get_configs(), {ok, [{Node, format_config(Config, [])} || {Node, Config} <- Data]}. config_list('GET', _Params, Node) -> - Data = emqttd_mgmt:get_config(l2a(Node)), + Data = emqx_mgmt:get_config(l2a(Node)), {ok, [format_config(Config) || Config <- lists:reverse(Data)]}. plugin_config_list('GET', _Params, Node, App) -> - {ok, Data} = emqttd_mgmt:get_plugin_config(l2a(Node), l2a(App)), + {ok, Data} = emqx_mgmt:get_plugin_config(l2a(Node), l2a(App)), {ok, [format_plugin_config(Config) || Config <- lists:reverse(Data)]}. modify_plugin_config('PUT', Params, Node, App) -> PluginName = l2a(App), - case emqttd_mgmt:modify_plugin_config(l2a(Node), PluginName, Params) of + case emqx_mgmt:modify_plugin_config(l2a(Node), PluginName, Params) of ok -> Plugins = emqttd_plugins:list(), {_, _, _, _, Status} = lists:keyfind(PluginName, 2, Plugins), @@ -465,7 +466,7 @@ format_plugin_config({Key, Value, Desc, Required}) -> auth('POST', Params) -> Username = get_value(<<"username">>, Params), Password = get_value(<<"password">>, Params), - case emqttd_mgmt:check_user(Username, Password) of + case emqx_mgmt:check_user(Username, Password) of ok -> {ok, []}; {error, Reason} -> @@ -476,26 +477,26 @@ users('POST', Params) -> Username = get_value(<<"username">>, Params), Password = get_value(<<"password">>, Params), Tag = get_value(<<"tags">>, Params), - code(emqttd_mgmt:add_user(Username, Password, Tag)); + code(emqx_mgmt:add_user(Username, Password, Tag)); users('GET', _Params) -> - {ok, [Admin || Admin <- emqttd_mgmt:user_list()]}. + {ok, [Admin || Admin <- emqx_mgmt:user_list()]}. users('GET', _Params, Username) -> - {ok, emqttd_mgmt:lookup_user(list_to_binary(Username))}; + {ok, emqx_mgmt:lookup_user(list_to_binary(Username))}; users('PUT', Params, Username) -> - code(emqttd_mgmt:update_user(list_to_binary(Username), Params)); + code(emqx_mgmt:update_user(list_to_binary(Username), Params)); users('DELETE', _Params, "admin") -> {error, [{code, ?ERROR6}, {message, <<"admin cannot be deleted">>}]}; users('DELETE', _Params, Username) -> - code(emqttd_mgmt:remove_user(list_to_binary(Username))). + code(emqx_mgmt:remove_user(list_to_binary(Username))). change_pwd('PUT', Params, Username) -> OldPwd = get_value(<<"old_pwd">>, Params), NewPwd = get_value(<<"new_pwd">>, Params), - code(emqttd_mgmt:change_password(list_to_binary(Username), OldPwd, NewPwd)). + code(emqx_mgmt:change_password(list_to_binary(Username), OldPwd, NewPwd)). code(ok) -> {ok, []}; code(error) -> {error, [{code, ?ERROR2}]}; diff --git a/src/emqttd_router.erl b/src/emqx_router.erl similarity index 94% rename from src/emqttd_router.erl rename to src/emqx_router.erl index b3dd8b4ad..b16d8af1f 100644 --- a/src/emqttd_router.erl +++ b/src/emqx_router.erl @@ -14,13 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_router). +-module(emqx_router). -author("Feng Lee "). -behaviour(gen_server). --include("emqttd.hrl"). +-include("emqx.hrl"). %% Mnesia Bootstrap -export([mnesia/1]). @@ -89,7 +89,7 @@ local_topics() -> %% @doc Match Routes. -spec(match(Topic:: binary()) -> [mqtt_route()]). match(Topic) when is_binary(Topic) -> - Matched = mnesia:async_dirty(fun emqttd_trie:match/1, [Topic]), + Matched = mnesia:async_dirty(fun emqx_trie:match/1, [Topic]), %% Optimize: route table will be replicated to all nodes. lists:append([ets:lookup(mqtt_route, To) || To <- [Topic | Matched]]). @@ -123,8 +123,8 @@ add_routes(Routes) -> add_route_(Route = #mqtt_route{topic = Topic}) -> case mnesia:wread({mqtt_route, Topic}) of [] -> - case emqttd_topic:wildcard(Topic) of - true -> emqttd_trie:insert(Topic); + case emqx_topic:wildcard(Topic) of + true -> emqx_trie:insert(Topic); false -> ok end, mnesia:write(Route), @@ -163,8 +163,8 @@ del_route_(Route = #mqtt_route{topic = Topic}) -> [Route] -> %% Remove route and trie mnesia:delete_object(Route), - case emqttd_topic:wildcard(Topic) of - true -> emqttd_trie:delete(Topic); + case emqx_topic:wildcard(Topic) of + true -> emqx_trie:delete(Topic); false -> ok end, mnesia:delete({mqtt_topic, Topic}); @@ -206,7 +206,7 @@ del_local_route(Topic) -> match_local(Name) -> [#mqtt_route{topic = {local, Filter}, node = Node} || {Filter, Node} <- ets:tab2list(mqtt_local_route), - emqttd_topic:match(Name, Filter)]. + emqx_topic:match(Name, Filter)]. dump() -> [{route, ets:tab2list(mqtt_route)}, {local_route, ets:tab2list(mqtt_local_route)}]. @@ -281,5 +281,5 @@ clean_routes_(Node) -> mnesia:transaction(Clean). update_stats_() -> - emqttd_stats:setstats('routes/count', 'routes/max', mnesia:table_info(mqtt_route, size)). + emqx_stats:setstats('routes/count', 'routes/max', mnesia:table_info(mqtt_route, size)). diff --git a/src/emqx_rpc.erl b/src/emqx_rpc.erl new file mode 100644 index 000000000..17525c065 --- /dev/null +++ b/src/emqx_rpc.erl @@ -0,0 +1,17 @@ +%% +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. All Rights Reserved. +%% +%% @doc EMQ X Distributed RPC. +%% + +-module(emqx_rpc). + +-author("Feng Lee "). + +-export([cast/4]). + +%% @doc Wraps gen_rpc first. +cast(Node, Mod, Fun, Args) -> + emqx_metrics:inc('messages/forward'), + gen_rpc:cast({Node, erlang:system_info(scheduler_id)}, Mod, Fun, Args). + diff --git a/src/emqttd_serializer.erl b/src/emqx_serializer.erl similarity index 96% rename from src/emqttd_serializer.erl rename to src/emqx_serializer.erl index 079cfbb3c..ef6aaf15c 100644 --- a/src/emqttd_serializer.erl +++ b/src/emqx_serializer.erl @@ -15,13 +15,13 @@ %%-------------------------------------------------------------------- %% @doc MQTT Packet Serializer --module(emqttd_serializer). +-module(emqx_serializer). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). %% API -export([serialize/1]). @@ -46,18 +46,18 @@ serialize_header(#mqtt_packet_header{type = Type, [<>, serialize_len(Len), VariableBin, PayloadBin]. -serialize_variable(?CONNECT, #mqtt_packet_connect{client_id = ClientId, - proto_ver = ProtoVer, - proto_name = ProtoName, - will_retain = WillRetain, - will_qos = WillQos, - will_flag = WillFlag, - clean_sess = CleanSess, - keep_alive = KeepAlive, - will_topic = WillTopic, - will_msg = WillMsg, - username = Username, - password = Password}, undefined) -> +serialize_variable(?CONNECT, #mqtt_packet_connect{client_id = ClientId, + proto_ver = ProtoVer, + proto_name = ProtoName, + will_retain = WillRetain, + will_qos = WillQos, + will_flag = WillFlag, + clean_sess = CleanSess, + keep_alive = KeepAlive, + will_topic = WillTopic, + will_msg = WillMsg, + username = Username, + password = Password}, undefined) -> VariableBin = <<(byte_size(ProtoName)):16/big-unsigned-integer, ProtoName/binary, ProtoVer:8, diff --git a/src/emqttd_server.erl b/src/emqx_server.erl similarity index 82% rename from src/emqttd_server.erl rename to src/emqx_server.erl index 69d18e1e4..0ffc99eb6 100644 --- a/src/emqttd_server.erl +++ b/src/emqx_server.erl @@ -14,17 +14,17 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_server). +-module(emqx_server). -behaviour(gen_server2). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -export([start_link/3]). @@ -47,9 +47,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --record(state, {pool, id, env, submon :: emqttd_pmon:pmon()}). +-record(state, { pool, id, env, submon :: emqx_pmon:pmon() }). -%% @doc Start server +%% @doc Start a Server -spec(start_link(atom(), pos_integer(), list()) -> {ok, pid()} | ignore | {error, any()}). start_link(Pool, Id, Env) -> gen_server2:start_link({local, ?PROC_NAME(?MODULE, Id)}, ?MODULE, [Pool, Id, Env], []). @@ -59,16 +59,16 @@ start_link(Pool, Id, Env) -> %%-------------------------------------------------------------------- %% @doc Subscribe a Topic --spec(subscribe(binary()) -> ok | emqttd:pubsub_error()). +-spec(subscribe(binary()) -> ok | {error, any()}). subscribe(Topic) when is_binary(Topic) -> subscribe(Topic, self()). --spec(subscribe(binary(), emqttd:subscriber()) -> ok | emqttd:pubsub_error()). +-spec(subscribe(binary(), emqx:subscriber()) -> ok | {error, any()}). subscribe(Topic, Subscriber) when is_binary(Topic) -> subscribe(Topic, Subscriber, []). --spec(subscribe(binary(), emqttd:subscriber(), [emqttd:suboption()]) -> - ok | emqttd:pubsub_error()). +-spec(subscribe(binary(), emqx:subscriber(), [emqx:suboption()]) -> + ok | {error, any()}). subscribe(Topic, Subscriber, Options) when is_binary(Topic) -> call(pick(Subscriber), {subscribe, Topic, Subscriber, Options}). @@ -77,23 +77,23 @@ subscribe(Topic, Subscriber, Options) when is_binary(Topic) -> async_subscribe(Topic) when is_binary(Topic) -> async_subscribe(Topic, self()). --spec(async_subscribe(binary(), emqttd:subscriber()) -> ok). +-spec(async_subscribe(binary(), emqx:subscriber()) -> ok). async_subscribe(Topic, Subscriber) when is_binary(Topic) -> async_subscribe(Topic, Subscriber, []). --spec(async_subscribe(binary(), emqttd:subscriber(), [emqttd:suboption()]) -> ok). +-spec(async_subscribe(binary(), emqx:subscriber(), [emqx:suboption()]) -> ok). async_subscribe(Topic, Subscriber, Options) when is_binary(Topic) -> cast(pick(Subscriber), {subscribe, Topic, Subscriber, Options}). -%% @doc Publish message to Topic. +%% @doc Publish a message -spec(publish(mqtt_message()) -> {ok, mqtt_delivery()} | ignore). publish(Msg = #mqtt_message{from = From}) -> trace(publish, From, Msg), - case emqttd_hooks:run('message.publish', [], Msg) of + case emqx_hooks:run('message.publish', [], Msg) of {ok, Msg1 = #mqtt_message{topic = Topic}} -> - emqttd_pubsub:publish(Topic, Msg1); + emqx_pubsub:publish(Topic, Msg1); {stop, Msg1} -> - lager:warning("Stop publishing: ~s", [emqttd_message:format(Msg1)]), + lager:warning("Stop publishing: ~s", [emqx_message:format(Msg1)]), ignore end. @@ -102,19 +102,19 @@ trace(publish, From, _Msg) when is_atom(From) -> %% Dont' trace '$SYS' publish ignore; trace(publish, {ClientId, Username}, #mqtt_message{topic = Topic, payload = Payload}) -> - lager:debug([{client, ClientId}, {topic, Topic}], - "~s/~s PUBLISH to ~s: ~p", [ClientId, Username, Topic, Payload]); -trace(publish, From, #mqtt_message{topic = Topic, payload = Payload}) -> - lager:debug([{client, From}, {topic, Topic}], - "~s PUBLISH to ~s: ~p", [From, Topic, Payload]). + lager:info([{client, ClientId}, {topic, Topic}], + "~s/~s PUBLISH to ~s: ~p", [ClientId, Username, Topic, Payload]); +trace(publish, From, #mqtt_message{topic = Topic, payload = Payload}) when is_binary(From); is_list(From) -> + lager:info([{client, From}, {topic, Topic}], + "~s PUBLISH to ~s: ~p", [From, Topic, Payload]). %% @doc Unsubscribe --spec(unsubscribe(binary()) -> ok | emqttd:pubsub_error()). +-spec(unsubscribe(binary()) -> ok | {error, any()}). unsubscribe(Topic) when is_binary(Topic) -> unsubscribe(Topic, self()). %% @doc Unsubscribe --spec(unsubscribe(binary(), emqttd:subscriber()) -> ok | emqttd:pubsub_error()). +-spec(unsubscribe(binary(), emqx:subscriber()) -> ok | {error, any()}). unsubscribe(Topic, Subscriber) when is_binary(Topic) -> call(pick(Subscriber), {unsubscribe, Topic, Subscriber}). @@ -123,14 +123,14 @@ unsubscribe(Topic, Subscriber) when is_binary(Topic) -> async_unsubscribe(Topic) when is_binary(Topic) -> async_unsubscribe(Topic, self()). --spec(async_unsubscribe(binary(), emqttd:subscriber()) -> ok). +-spec(async_unsubscribe(binary(), emqx:subscriber()) -> ok). async_unsubscribe(Topic, Subscriber) when is_binary(Topic) -> cast(pick(Subscriber), {unsubscribe, Topic, Subscriber}). setqos(Topic, Subscriber, Qos) when is_binary(Topic) -> call(pick(Subscriber), {setqos, Topic, Subscriber, Qos}). --spec(subscriptions(emqttd:subscriber()) -> [{binary(), binary(), list(emqttd:suboption())}]). +-spec(subscriptions(emqx:subscriber()) -> [{binary(), list(emqx:suboption())}]). subscriptions(Subscriber) -> lists:map(fun({_, {_Share, Topic}}) -> subscription(Topic, Subscriber); @@ -142,13 +142,13 @@ subscription(Topic, Subscriber) -> {Topic, Subscriber, ets:lookup_element(mqtt_subproperty, {Topic, Subscriber}, 2)}. subscribers(Topic) -> - emqttd_pubsub:subscribers(Topic). + emqx_pubsub:subscribers(Topic). --spec(is_subscribed(binary(), emqttd:subscriber()) -> boolean()). +-spec(is_subscribed(binary(), emqx:subscriber()) -> boolean()). is_subscribed(Topic, Subscriber) when is_binary(Topic) -> ets:member(mqtt_subproperty, {Topic, Subscriber}). --spec(subscriber_down(emqttd:subscriber()) -> ok). +-spec(subscriber_down(emqx:subscriber()) -> ok). subscriber_down(Subscriber) -> cast(pick(Subscriber), {subscriber_down, Subscriber}). @@ -170,7 +170,7 @@ dump() -> init([Pool, Id, Env]) -> ?GPROC_POOL(join, Pool, Id), - {ok, #state{pool = Pool, id = Id, env = Env, submon = emqttd_pmon:new()}}. + {ok, #state{pool = Pool, id = Id, env = Env, submon = emqx_pmon:new()}}. handle_call({subscribe, Topic, Subscriber, Options}, _From, State) -> case do_subscribe_(Topic, Subscriber, Options, State) of @@ -237,7 +237,7 @@ code_change(_OldVsn, State, _Extra) -> do_subscribe_(Topic, Subscriber, Options, State) -> case ets:lookup(mqtt_subproperty, {Topic, Subscriber}) of [] -> - emqttd_pubsub:async_subscribe(Topic, Subscriber, Options), + emqx_pubsub:async_subscribe(Topic, Subscriber, Options), Share = proplists:get_value(share, Options), add_subscription_(Share, Subscriber, Topic), ets:insert(mqtt_subproperty, {{Topic, Subscriber}, Options}), @@ -259,7 +259,7 @@ monitor_subpid(_SubPid, State) -> do_unsubscribe_(Topic, Subscriber, State) -> case ets:lookup(mqtt_subproperty, {Topic, Subscriber}) of [{_, Options}] -> - emqttd_pubsub:async_unsubscribe(Topic, Subscriber, Options), + emqx_pubsub:async_unsubscribe(Topic, Subscriber, Options), Share = proplists:get_value(share, Options), del_subscription_(Share, Subscriber, Topic), ets:delete(mqtt_subproperty, {Topic, Subscriber}), @@ -294,13 +294,13 @@ subscriber_down_(Share, Subscriber, Topic) -> [] -> %% TODO:....??? Options = if Share == undefined -> []; true -> [{share, Share}] end, - emqttd_pubsub:async_unsubscribe(Topic, Subscriber, Options); + emqx_pubsub:async_unsubscribe(Topic, Subscriber, Options); [{_, Options}] -> - emqttd_pubsub:async_unsubscribe(Topic, Subscriber, Options), + emqx_pubsub:async_unsubscribe(Topic, Subscriber, Options), ets:delete(mqtt_subproperty, {Topic, Subscriber}) end. setstats(State) -> - emqttd_stats:setstats('subscriptions/count', 'subscriptions/max', - ets:info(mqtt_subscription, size)), State. + emqx_stats:setstats('subscriptions/count', 'subscriptions/max', + ets:info(mqtt_subscription, size)), State. diff --git a/src/emqttd_session.erl b/src/emqx_session.erl similarity index 86% rename from src/emqttd_session.erl rename to src/emqx_session.erl index e8e694530..c46f50b97 100644 --- a/src/emqttd_session.erl +++ b/src/emqx_session.erl @@ -43,19 +43,19 @@ %% @end %% --module(emqttd_session). +-module(emqx_session). -behaviour(gen_server2). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). --import(emqttd_misc, [start_timer/2]). +-import(emqx_misc, [start_timer/2]). -import(proplists, [get_value/2, get_value/3]). @@ -77,7 +77,7 @@ -export([prioritise_call/4, prioritise_cast/3, prioritise_info/3, handle_pre_hibernate/1]). --define(MQueue, emqttd_mqueue). +-define(MQueue, emqx_mqueue). -record(state, { @@ -111,7 +111,7 @@ upgrade_qos = false :: boolean(), %% Client <- Broker: Inflight QoS1, QoS2 messages sent to the client but unacked. - inflight :: emqttd_inflight:inflight(), + inflight :: emqx_inflight:inflight(), %% Max Inflight Size max_inflight = 32 :: non_neg_integer(), @@ -152,9 +152,10 @@ %% Force GC Count force_gc_count :: undefined | integer(), - created_at :: erlang:timestamp(), + %% Ignore loop deliver? + ignore_loop_deliver = false :: boolean(), - ignore_loop_deliver = false :: boolean() + created_at :: erlang:timestamp() }). -define(TIMEOUT, 60000). @@ -181,11 +182,11 @@ start_link(CleanSess, {ClientId, Username}, ClientPid) -> %%-------------------------------------------------------------------- %% @doc Subscribe topics --spec(subscribe(pid(), [{binary(), [emqttd_topic:option()]}]) -> ok). -subscribe(Session, TopicTable) -> %%TODO: the ack function??... +-spec(subscribe(pid(), [{binary(), [emqx_topic:option()]}]) -> ok). +subscribe(Session, TopicTable) ->%%TODO: the ack function??... gen_server2:cast(Session, {subscribe, self(), TopicTable, fun(_) -> ok end}). --spec(subscribe(pid(), mqtt_packet_id(), [{binary(), [emqttd_topic:option()]}]) -> ok). +-spec(subscribe(pid(), mqtt_packet_id(), [{binary(), [emqx_topic:option()]}]) -> ok). subscribe(Session, PacketId, TopicTable) -> %%TODO: the ack function??... From = self(), AckFun = fun(GrantedQos) -> From ! {suback, PacketId, GrantedQos} end, @@ -195,11 +196,11 @@ subscribe(Session, PacketId, TopicTable) -> %%TODO: the ack function??... -spec(publish(pid(), mqtt_message()) -> ok | {error, any()}). publish(_Session, Msg = #mqtt_message{qos = ?QOS_0}) -> %% Publish QoS0 Directly - emqttd_server:publish(Msg), ok; + emqx_server:publish(Msg), ok; publish(_Session, Msg = #mqtt_message{qos = ?QOS_1}) -> %% Publish QoS1 message directly for client will PubAck automatically - emqttd_server:publish(Msg), ok; + emqx_server:publish(Msg), ok; publish(Session, Msg = #mqtt_message{qos = ?QOS_2}) -> %% Publish QoS2 to Session @@ -223,7 +224,7 @@ pubcomp(Session, PacketId) -> gen_server2:cast(Session, {pubcomp, PacketId}). %% @doc Unsubscribe the topics --spec(unsubscribe(pid(), [{binary(), [emqttd_topic:option()]}]) -> ok). +-spec(unsubscribe(pid(), [{binary(), [emqx_topic:option()]}]) -> ok). unsubscribe(Session, TopicTable) -> gen_server2:cast(Session, {unsubscribe, self(), TopicTable}). @@ -255,7 +256,7 @@ stats(#state{max_subscriptions = MaxSubscriptions, mqueue = MQueue, max_awaiting_rel = MaxAwaitingRel, awaiting_rel = AwaitingRel}) -> - lists:append(emqttd_misc:proc_stats(), + lists:append(emqx_misc:proc_stats(), [{max_subscriptions, MaxSubscriptions}, {subscriptions, maps:size(Subscriptions)}, {max_inflight, MaxInflight}, @@ -281,13 +282,13 @@ init([CleanSess, {ClientId, Username}, ClientPid]) -> process_flag(trap_exit, true), true = link(ClientPid), init_stats([deliver_msg, enqueue_msg]), - {ok, Env} = emqttd:env(session), - {ok, QEnv} = emqttd:env(mqueue), + {ok, Env} = emqx:env(session), + {ok, QEnv} = emqx:env(mqueue), MaxInflight = get_value(max_inflight, Env, 0), EnableStats = get_value(enable_stats, Env, false), + ForceGcCount = emqx_gc:conn_max_gc_count(), IgnoreLoopDeliver = get_value(ignore_loop_deliver, Env, false), - ForceGcCount = emqttd_gc:conn_max_gc_count(), - MQueue = ?MQueue:new(ClientId, QEnv, emqttd_alarm:alarm_fun()), + MQueue = ?MQueue:new(ClientId, QEnv, emqx_alarm:alarm_fun()), State = #state{clean_sess = CleanSess, binding = binding(ClientPid), client_id = ClientId, @@ -297,7 +298,7 @@ init([CleanSess, {ClientId, Username}, ClientPid]) -> max_subscriptions = get_value(max_subscriptions, Env, 0), upgrade_qos = get_value(upgrade_qos, Env, false), max_inflight = MaxInflight, - inflight = emqttd_inflight:new(MaxInflight), + inflight = emqx_inflight:new(MaxInflight), mqueue = MQueue, retry_interval = get_value(retry_interval, Env), awaiting_rel = #{}, @@ -306,10 +307,10 @@ init([CleanSess, {ClientId, Username}, ClientPid]) -> expiry_interval = get_value(expiry_interval, Env), enable_stats = EnableStats, force_gc_count = ForceGcCount, - created_at = os:timestamp(), - ignore_loop_deliver = IgnoreLoopDeliver}, - emqttd_sm:register_session(ClientId, CleanSess, info(State)), - emqttd_hooks:run('session.created', [ClientId, Username]), + ignore_loop_deliver = IgnoreLoopDeliver, + created_at = os:timestamp()}, + emqx_sm:register_session(ClientId, CleanSess, info(State)), + emqx_hooks:run('session.created', [ClientId, Username]), {ok, emit_stats(State), hibernate, {backoff, 1000, 1000, 10000}}. init_stats(Keys) -> @@ -343,7 +344,7 @@ prioritise_info(Msg, _Len, _State) -> end. handle_pre_hibernate(State) -> - {hibernate, emqttd_gc:reset_conn_gc_count(#state.force_gc_count, emit_stats(State))}. + {hibernate, emqx_gc:reset_conn_gc_count(#state.force_gc_count, emit_stats(State))}. handle_call({publish, Msg = #mqtt_message{qos = ?QOS_2, pktid = PacketId}}, _From, State = #state{awaiting_rel = AwaitingRel, @@ -358,7 +359,7 @@ handle_call({publish, Msg = #mqtt_message{qos = ?QOS_2, pktid = PacketId}}, _Fro reply(ok, State1#state{awaiting_rel = maps:put(PacketId, Msg, AwaitingRel)}); true -> ?LOG(warning, "Dropped Qos2 Message for too many awaiting_rel: ~p", [Msg], State), - emqttd_metrics:inc('messages/qos2/dropped'), + emqx_metrics:inc('messages/qos2/dropped'), reply({error, dropped}, State) end; @@ -374,27 +375,31 @@ handle_call(state, _From, State) -> handle_call(Req, _From, State) -> ?UNEXPECTED_REQ(Req, State). -handle_cast({subscribe, _From, TopicTable, AckFun}, +handle_cast({subscribe, From, TopicTable, AckFun}, State = #state{client_id = ClientId, username = Username, subscriptions = Subscriptions}) -> - ?LOG(debug, "Subscribe ~p", [TopicTable], State), + ?LOG(info, "Subscribe ~p", [TopicTable], State), {GrantedQos, Subscriptions1} = lists:foldl(fun({Topic, Opts}, {QosAcc, SubMap}) -> - NewQos = proplists:get_value(qos, Opts), + Fastlane = lists:member(fastlane, Opts), + NewQos = if Fastlane == true -> ?QOS_0; true -> get_value(qos, Opts) end, SubMap1 = case maps:find(Topic, SubMap) of {ok, NewQos} -> ?LOG(warning, "Duplicated subscribe: ~s, qos = ~w", [Topic, NewQos], State), SubMap; {ok, OldQos} -> - emqttd:setqos(Topic, ClientId, NewQos), + emqx_server:setqos(Topic, ClientId, NewQos), ?LOG(warning, "Duplicated subscribe ~s, old_qos=~w, new_qos=~w", [Topic, OldQos, NewQos], State), maps:put(Topic, NewQos, SubMap); error -> - emqttd:subscribe(Topic, ClientId, Opts), - emqttd_hooks:run('session.subscribed', [ClientId, Username], {Topic, Opts}), + case Fastlane of + true -> emqx:subscribe(Topic, From, Opts); + false -> emqx:subscribe(Topic, ClientId, Opts) + end, + emqx_hooks:run('session.subscribed', [ClientId, Username], {Topic, Opts}), maps:put(Topic, NewQos, SubMap) end, {[NewQos|QosAcc], SubMap1} @@ -402,17 +407,21 @@ handle_cast({subscribe, _From, TopicTable, AckFun}, AckFun(lists:reverse(GrantedQos)), hibernate(emit_stats(State#state{subscriptions = Subscriptions1})); -handle_cast({unsubscribe, _From, TopicTable}, +handle_cast({unsubscribe, From, TopicTable}, State = #state{client_id = ClientId, username = Username, subscriptions = Subscriptions}) -> - ?LOG(debug, "Unsubscribe ~p", [TopicTable], State), + ?LOG(info, "Unsubscribe ~p", [TopicTable], State), Subscriptions1 = lists:foldl(fun({Topic, Opts}, SubMap) -> + Fastlane = lists:member(fastlane, Opts), case maps:find(Topic, SubMap) of {ok, _Qos} -> - emqttd:unsubscribe(Topic, ClientId), - emqttd_hooks:run('session.unsubscribed', [ClientId, Username], {Topic, Opts}), + case Fastlane of + true -> emqx:unsubscribe(Topic, From); + false -> emqx:unsubscribe(Topic, ClientId) + end, + emqx_hooks:run('session.unsubscribed', [ClientId, Username], {Topic, Opts}), maps:remove(Topic, SubMap); error -> SubMap @@ -429,7 +438,7 @@ handle_cast({puback, PacketId}, State = #state{inflight = Inflight}) -> false -> ?LOG(warning, "PUBACK ~p missed inflight: ~p", [PacketId, Inflight:window()], State), - emqttd_metrics:inc('packets/puback/missed'), + emqx_metrics:inc('packets/puback/missed'), State end, hibernate}; @@ -442,7 +451,7 @@ handle_cast({pubrec, PacketId}, State = #state{inflight = Inflight}) -> false -> ?LOG(warning, "PUBREC ~p missed inflight: ~p", [PacketId, Inflight:window()], State), - emqttd_metrics:inc('packets/pubrec/missed'), + emqx_metrics:inc('packets/pubrec/missed'), State end, hibernate}; @@ -451,11 +460,12 @@ handle_cast({pubrel, PacketId}, State = #state{awaiting_rel = AwaitingRel}) -> {noreply, case maps:take(PacketId, AwaitingRel) of {Msg, AwaitingRel1} -> - spawn(emqttd_server, publish, [Msg]), %%:) + %% TODO: woker pool to publish the qos2 messages? + spawn(emqx_server, publish, [Msg]), %%:) gc(State#state{awaiting_rel = AwaitingRel1}); error -> ?LOG(warning, "Cannot find PUBREL: ~p", [PacketId], State), - emqttd_metrics:inc('packets/pubrel/missed'), + emqx_metrics:inc('packets/pubrel/missed'), State end, hibernate}; @@ -468,7 +478,7 @@ handle_cast({pubcomp, PacketId}, State = #state{inflight = Inflight}) -> false -> ?LOG(warning, "The PUBCOMP ~p is not inflight: ~p", [PacketId, Inflight:window()], State), - emqttd_metrics:inc('packets/pubcomp/missed'), + emqx_metrics:inc('packets/pubcomp/missed'), State end, hibernate}; @@ -481,10 +491,10 @@ handle_cast({resume, ClientId, ClientPid}, await_rel_timer = AwaitTimer, expiry_timer = ExpireTimer}) -> - ?LOG(debug, "Resumed by ~p", [ClientPid], State), + ?LOG(info, "Resumed by ~p", [ClientPid], State), %% Cancel Timers - lists:foreach(fun emqttd_misc:cancel_timer/1, + lists:foreach(fun emqx_misc:cancel_timer/1, [RetryTimer, AwaitTimer, ExpireTimer]), case kick(ClientId, OldClientPid, ClientPid) of @@ -507,7 +517,7 @@ handle_cast({resume, ClientId, ClientPid}, if CleanSess =:= true -> ?LOG(error, "CleanSess changed to false.", [], State1), - emqttd_sm:register_session(ClientId, false, info(State1)); + emqx_sm:register_session(ClientId, false, info(State1)); CleanSess =:= false -> ok end, @@ -528,17 +538,14 @@ handle_cast({destroy, ClientId}, handle_cast(Msg, State) -> ?UNEXPECTED_MSG(Msg, State). -%% Dispatch message from self publish -handle_info({dispatch, Topic, Msg = #mqtt_message{from = {ClientId, _}}}, - State = #state{client_id = ClientId, - ignore_loop_deliver = IgnoreLoopDeliver}) when is_record(Msg, mqtt_message) -> - case IgnoreLoopDeliver of - true -> {noreply, State, hibernate}; - false -> {noreply, gc(dispatch(tune_qos(Topic, Msg, State), State)), hibernate} - end; +%% Ignore Messages delivered by self +handle_info({dispatch, _Topic, #mqtt_message{from = {ClientId, _}}}, + State = #state{client_id = ClientId, ignore_loop_deliver = true}) -> + hibernate(State); + %% Dispatch Message handle_info({dispatch, Topic, Msg}, State) when is_record(Msg, mqtt_message) -> - {noreply, gc(dispatch(tune_qos(Topic, Msg, State), State)), hibernate}; + hibernate(gc(dispatch(tune_qos(Topic, Msg, State), State))); %% Do nothing if the client has been disconnected. handle_info({timeout, _Timer, retry_delivery}, State = #state{client_pid = undefined}) -> @@ -551,7 +558,7 @@ handle_info({timeout, _Timer, check_awaiting_rel}, State) -> hibernate(expire_awaiting_rel(emit_stats(State#state{await_rel_timer = undefined}))); handle_info({timeout, _Timer, expired}, State) -> - ?LOG(debug, "Expired, shutdown now.", [], State), + ?LOG(info, "Expired, shutdown now.", [], State), shutdown(expired, State); handle_info({'EXIT', ClientPid, _Reason}, @@ -562,7 +569,7 @@ handle_info({'EXIT', ClientPid, Reason}, State = #state{clean_sess = false, client_pid = ClientPid, expiry_interval = Interval}) -> - ?LOG(debug, "Client ~p EXIT for ~p", [ClientPid, Reason], State), + ?LOG(info, "Client ~p EXIT for ~p", [ClientPid, Reason], State), ExpireTimer = start_timer(Interval, expired), State1 = State#state{client_pid = undefined, expiry_timer = ExpireTimer}, hibernate(emit_stats(State1)); @@ -581,10 +588,10 @@ handle_info(Info, Session) -> ?UNEXPECTED_INFO(Info, Session). terminate(Reason, #state{client_id = ClientId, username = Username}) -> - emqttd_stats:del_session_stats(ClientId), - emqttd_hooks:run('session.terminated', [ClientId, Username, Reason]), - emqttd_server:subscriber_down(ClientId), - emqttd_sm:unregister_session(ClientId). + emqx_stats:del_session_stats(ClientId), + emqx_hooks:run('session.terminated', [ClientId, Username, Reason]), + emqx_server:subscriber_down(ClientId), + emqx_sm:unregister_session(ClientId). code_change(_OldVsn, Session, _Extra) -> {ok, Session}. @@ -687,8 +694,11 @@ is_awaiting_full(#state{awaiting_rel = AwaitingRel, max_awaiting_rel = MaxLen}) %%-------------------------------------------------------------------- %% Enqueue message if the client has been disconnected -dispatch(Msg, State = #state{client_pid = undefined}) -> - enqueue_msg(Msg, State); +dispatch(Msg, State = #state{client_id = ClientId, client_pid = undefined}) -> + case emqx_hooks:run('message.offline', [ClientId, Msg]) of + ok -> enqueue_msg(Msg, State); + stop -> State + end; %% Deliver qos0 message directly to client dispatch(Msg = #mqtt_message{qos = ?QOS0}, State) -> @@ -717,9 +727,10 @@ enqueue_msg(Msg, State = #state{mqueue = Q}) -> redeliver(Msg = #mqtt_message{qos = QoS}, State) -> deliver(Msg#mqtt_message{dup = if QoS =:= ?QOS2 -> false; true -> true end}, State). -deliver(Msg, #state{client_pid = Pid}) -> - inc_stats(deliver_msg), - Pid ! {deliver, Msg}. +deliver(Msg, #state{client_pid = Pid, binding = local}) -> + inc_stats(deliver_msg), Pid ! {deliver, Msg}; +deliver(Msg, #state{client_pid = Pid, binding = remote}) -> + inc_stats(deliver_msg), emqx_rpc:cast(node(Pid), erlang, send, [Pid, {deliver, Msg}]). %%-------------------------------------------------------------------- %% Awaiting ACK for QoS1/QoS2 Messages @@ -738,7 +749,7 @@ acked(puback, PacketId, State = #state{client_id = ClientId, inflight = Inflight}) -> case Inflight:lookup(PacketId) of {publish, Msg, _Ts} -> - emqttd_hooks:run('message.acked', [ClientId, Username], Msg), + emqx_hooks:run('message.acked', [ClientId, Username], Msg), State#state{inflight = Inflight:delete(PacketId)}; _ -> ?LOG(warning, "Duplicated PUBACK Packet: ~p", [PacketId], State), @@ -750,7 +761,7 @@ acked(pubrec, PacketId, State = #state{client_id = ClientId, inflight = Inflight}) -> case Inflight:lookup(PacketId) of {publish, Msg, _Ts} -> - emqttd_hooks:run('message.acked', [ClientId, Username], Msg), + emqx_hooks:run('message.acked', [ClientId, Username], Msg), State#state{inflight = Inflight:update(PacketId, {pubrel, PacketId, os:timestamp()})}; {pubrel, PacketId, _Ts} -> ?LOG(warning, "Duplicated PUBREC Packet: ~p", [PacketId], State), @@ -817,7 +828,7 @@ next_msg_id(State = #state{next_msg_id = Id}) -> emit_stats(State = #state{enable_stats = false}) -> State; emit_stats(State = #state{client_id = ClientId}) -> - emqttd_stats:set_session_stats(ClientId, stats(State)), + emqx_stats:set_session_stats(ClientId, stats(State)), State. inc_stats(Key) -> put(Key, get(Key) + 1). @@ -836,5 +847,5 @@ shutdown(Reason, State) -> {stop, {shutdown, Reason}, State}. gc(State) -> - emqttd_gc:maybe_force_gc(#state.force_gc_count, State). + emqx_gc:maybe_force_gc(#state.force_gc_count, State). diff --git a/src/emqttd_session_sup.erl b/src/emqx_session_sup.erl similarity index 91% rename from src/emqttd_session_sup.erl rename to src/emqx_session_sup.erl index bd9b34f02..8784ca396 100644 --- a/src/emqttd_session_sup.erl +++ b/src/emqx_session_sup.erl @@ -15,7 +15,7 @@ %%-------------------------------------------------------------------- %% @doc Session Supervisor. --module(emqttd_session_sup). +-module(emqx_session_sup). -author("Feng Lee "). @@ -41,5 +41,6 @@ start_session(CleanSess, {ClientId, Username}, ClientPid) -> init([]) -> {ok, {{simple_one_for_one, 0, 1}, - [{session, {emqttd_session, start_link, []}, - temporary, 5000, worker, [emqttd_session]}]}}. + [{session, {emqx_session, start_link, []}, + temporary, 5000, worker, [emqx_session]}]}}. + diff --git a/src/emqttd_sm.erl b/src/emqx_sm.erl similarity index 94% rename from src/emqttd_sm.erl rename to src/emqx_sm.erl index dacb0b6a1..1b652d600 100644 --- a/src/emqttd_sm.erl +++ b/src/emqx_sm.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_sm). +-module(emqx_sm). -author("Feng Lee "). -behaviour(gen_server2). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). %% Mnesia Callbacks -export([mnesia/1]). @@ -116,7 +116,9 @@ dispatch(ClientId, Topic, Msg) -> try ets:lookup_element(mqtt_local_session, ClientId, 2) of Pid -> Pid ! {dispatch, Topic, Msg} catch - error:badarg -> ok %%FIXME Later. + error:badarg -> + emqx_hooks:run('message.offline', [ClientId, Msg]), + ok %%TODO: How?? end. call(SM, Req) -> @@ -187,7 +189,7 @@ handle_info({'DOWN', MRef, process, DownPid, _Reason}, State) -> [] -> ok; [Sess = #mqtt_session{sess_pid = DownPid}] -> - emqttd_stats:del_session_stats(ClientId), + emqx_stats:del_session_stats(ClientId), mnesia:delete_object(mqtt_session, Sess, write); [_Sess] -> ok @@ -223,7 +225,7 @@ create_session({CleanSess, {ClientId, Username}, ClientPid}, State) -> end. create_session(CleanSess, {ClientId, Username}, ClientPid) -> - case emqttd_session_sup:start_session(CleanSess, {ClientId, Username}, ClientPid) of + case emqx_session_sup:start_session(CleanSess, {ClientId, Username}, ClientPid) of {ok, SessPid} -> Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid, clean_sess = CleanSess}, case insert_session(Session) of @@ -255,7 +257,7 @@ resume_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid} case is_process_alive(SessPid) of true -> - emqttd_session:resume(SessPid, ClientId, ClientPid), + emqx_session:resume(SessPid, ClientId, ClientPid), {ok, SessPid}; false -> ?LOG(error, "Cannot resume ~p which seems already dead!", [SessPid], Session), @@ -265,7 +267,7 @@ resume_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid} %% Remote node resume_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid}, ClientPid) -> Node = node(SessPid), - case rpc:call(Node, emqttd_session, resume, [SessPid, ClientId, ClientPid]) of + case rpc:call(Node, emqx_session, resume, [SessPid, ClientId, ClientPid]) of ok -> {ok, SessPid}; {badrpc, nodedown} -> @@ -278,16 +280,16 @@ resume_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid} end. %% Local node -destroy_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid}) +destroy_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid}) when node(SessPid) =:= node() -> - emqttd_session:destroy(SessPid, ClientId), + emqx_session:destroy(SessPid, ClientId), remove_session(Session); %% Remote node destroy_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid}) -> Node = node(SessPid), - case rpc:call(Node, emqttd_session, destroy, [SessPid, ClientId]) of + case rpc:call(Node, emqx_session, destroy, [SessPid, ClientId]) of ok -> remove_session(Session); {badrpc, nodedown} -> diff --git a/src/emqttd_sm_helper.erl b/src/emqx_sm_helper.erl similarity index 97% rename from src/emqttd_sm_helper.erl rename to src/emqx_sm_helper.erl index 2e8e9a749..4d0e7a9cb 100644 --- a/src/emqttd_sm_helper.erl +++ b/src/emqx_sm_helper.erl @@ -15,15 +15,15 @@ %%-------------------------------------------------------------------- %% @doc Session Helper. --module(emqttd_sm_helper). +-module(emqx_sm_helper). -author("Feng Lee "). -behaviour(gen_server). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). diff --git a/src/emqttd_sm_sup.erl b/src/emqx_sm_sup.erl similarity index 84% rename from src/emqttd_sm_sup.erl rename to src/emqx_sm_sup.erl index efabadb96..ad5c9732b 100644 --- a/src/emqttd_sm_sup.erl +++ b/src/emqx_sm_sup.erl @@ -16,17 +16,17 @@ %% @doc Session Manager Supervisor. --module(emqttd_sm_sup). +-module(emqx_sm_sup). -behaviour(supervisor). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --define(SM, emqttd_sm). +-define(SM, emqx_sm). --define(HELPER, emqttd_sm_helper). +-define(HELPER, emqx_sm_helper). %% API -export([start_link/0]). @@ -42,13 +42,13 @@ init([]) -> ets:new(mqtt_local_session, [public, ordered_set, named_table, {write_concurrency, true}]), %% Helper - StatsFun = emqttd_stats:statsfun('sessions/count', 'sessions/max'), + StatsFun = emqx_stats:statsfun('sessions/count', 'sessions/max'), Helper = {?HELPER, {?HELPER, start_link, [StatsFun]}, permanent, 5000, worker, [?HELPER]}, %% SM Pool Sup MFA = {?SM, start_link, []}, - PoolSup = emqttd_pool_sup:spec([?SM, hash, erlang:system_info(schedulers), MFA]), + PoolSup = emqx_pool_sup:spec([?SM, hash, erlang:system_info(schedulers), MFA]), {ok, {{one_for_all, 10, 3600}, [Helper, PoolSup]}}. diff --git a/src/emqx_ssl.erl b/src/emqx_ssl.erl new file mode 100644 index 000000000..8d91202cd --- /dev/null +++ b/src/emqx_ssl.erl @@ -0,0 +1,259 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- +%% +%% @doc SSL Utility Functions. This module is copied from rabbit_ssl.erl +%% + +-module(emqx_ssl). + +-include_lib("public_key/include/public_key.hrl"). + +-type(certificate() :: binary()). + +-export([peer_cert_issuer/1, peer_cert_subject/1, peer_cert_common_name/1, + peer_cert_subject_items/2, peer_cert_validity/1]). + +%% Return a string describing the certificate's issuer. +-spec(peer_cert_issuer(certificate()) -> string()). +peer_cert_issuer(Cert) -> + cert_info(fun(#'OTPCertificate' { + tbsCertificate = #'OTPTBSCertificate' { + issuer = Issuer }}) -> + format_rdn_sequence(Issuer) + end, Cert). + +%% Return a string describing the certificate's subject, as per RFC4514. +-spec(peer_cert_subject(certificate()) -> string()). +peer_cert_subject(Cert) -> + cert_info(fun(#'OTPCertificate' { + tbsCertificate = #'OTPTBSCertificate' { + subject = Subject }}) -> + format_rdn_sequence(Subject) + end, Cert). + +-spec(peer_cert_common_name(certificate()) -> string() | 'not_found'). +peer_cert_common_name(Cert) -> + case peer_cert_subject_items(Cert, ?'id-at-commonName') of + not_found -> not_found; + CNs -> string:join(CNs, ",") + end. + +%% Return the parts of the certificate's subject. +-spec(peer_cert_subject_items(certificate(), tuple()) -> [string()] | 'undefined'). +peer_cert_subject_items(Cert, Type) -> + cert_info(fun(#'OTPCertificate' { + tbsCertificate = #'OTPTBSCertificate' { + subject = Subject }}) -> + find_by_type(Type, Subject) + end, Cert). + +%% Return a string describing the certificate's validity. +-spec(peer_cert_validity(certificate()) -> string()). +peer_cert_validity(Cert) -> + cert_info(fun(#'OTPCertificate' { + tbsCertificate = #'OTPTBSCertificate' { + validity = {'Validity', Start, End} }}) -> + format("~s - ~s", [format_asn1_value(Start), + format_asn1_value(End)]) + end, Cert). + +cert_info(F, {ok, Cert}) -> + F(case public_key:pkix_decode_cert(Cert, otp) of + {ok, DecCert} -> DecCert; %%pre R14B + DecCert -> DecCert %%R14B onwards + end). + +find_by_type(Type, {rdnSequence, RDNs}) -> + case [V || #'AttributeTypeAndValue'{type = T, value = V} + <- lists:flatten(RDNs), + T == Type] of + [] -> not_found; + L -> [format_asn1_value(V) || V <- L] + end. + +%%-------------------------------------------------------------------------- +%% Formatting functions. +%%-------------------------------------------------------------------------- + +%% Format and rdnSequence as a RFC4514 subject string. +format_rdn_sequence({rdnSequence, Seq}) -> + string:join(lists:reverse([format_complex_rdn(RDN) || RDN <- Seq]), ","). + +%% Format an RDN set. +format_complex_rdn(RDNs) -> + string:join([format_rdn(RDN) || RDN <- RDNs], "+"). + +%% Format an RDN. If the type name is unknown, use the dotted decimal +%% representation. See RFC4514, section 2.3. +format_rdn(#'AttributeTypeAndValue'{type = T, value = V}) -> + FV = escape_rdn_value(format_asn1_value(V)), + Fmts = [{?'id-at-surname' , "SN"}, + {?'id-at-givenName' , "GIVENNAME"}, + {?'id-at-initials' , "INITIALS"}, + {?'id-at-generationQualifier' , "GENERATIONQUALIFIER"}, + {?'id-at-commonName' , "CN"}, + {?'id-at-localityName' , "L"}, + {?'id-at-stateOrProvinceName' , "ST"}, + {?'id-at-organizationName' , "O"}, + {?'id-at-organizationalUnitName' , "OU"}, + {?'id-at-title' , "TITLE"}, + {?'id-at-countryName' , "C"}, + {?'id-at-serialNumber' , "SERIALNUMBER"}, + {?'id-at-pseudonym' , "PSEUDONYM"}, + {?'id-domainComponent' , "DC"}, + {?'id-emailAddress' , "EMAILADDRESS"}, + {?'street-address' , "STREET"}, + {{0,9,2342,19200300,100,1,1} , "UID"}], %% Not in public_key.hrl + case proplists:lookup(T, Fmts) of + {_, Fmt} -> + format(Fmt ++ "=~s", [FV]); + none when is_tuple(T) -> + TypeL = [format("~w", [X]) || X <- tuple_to_list(T)], + format("~s=~s", [string:join(TypeL, "."), FV]); + none -> + format("~p=~s", [T, FV]) + end. + +%% Escape a string as per RFC4514. +escape_rdn_value(V) -> + escape_rdn_value(V, start). + +escape_rdn_value([], _) -> + []; +escape_rdn_value([C | S], start) when C =:= $ ; C =:= $# -> + [$\\, C | escape_rdn_value(S, middle)]; +escape_rdn_value(S, start) -> + escape_rdn_value(S, middle); +escape_rdn_value([$ ], middle) -> + [$\\, $ ]; +escape_rdn_value([C | S], middle) when C =:= $"; C =:= $+; C =:= $,; C =:= $;; + C =:= $<; C =:= $>; C =:= $\\ -> + [$\\, C | escape_rdn_value(S, middle)]; +escape_rdn_value([C | S], middle) when C < 32 ; C >= 126 -> + %% Of ASCII characters only U+0000 needs escaping, but for display + %% purposes it's handy to escape all non-printable chars. All non-ASCII + %% characters get converted to UTF-8 sequences and then escaped. We've + %% already got a UTF-8 sequence here, so just escape it. + rabbit_misc:format("\\~2.16.0B", [C]) ++ escape_rdn_value(S, middle); +escape_rdn_value([C | S], middle) -> + [C | escape_rdn_value(S, middle)]. + +%% Get the string representation of an OTPCertificate field. +format_asn1_value({ST, S}) when ST =:= teletexString; ST =:= printableString; + ST =:= universalString; ST =:= utf8String; + ST =:= bmpString -> + format_directory_string(ST, S); +format_asn1_value({utcTime, [Y1, Y2, M1, M2, D1, D2, H1, H2, + Min1, Min2, S1, S2, $Z]}) -> + format("20~c~c-~c~c-~c~cT~c~c:~c~c:~c~cZ", + [Y1, Y2, M1, M2, D1, D2, H1, H2, Min1, Min2, S1, S2]); +%% We appear to get an untagged value back for an ia5string +%% (e.g. domainComponent). +format_asn1_value(V) when is_list(V) -> + V; +format_asn1_value(V) when is_binary(V) -> + %% OTP does not decode some values when combined with an unknown + %% type. That's probably wrong, so as a last ditch effort let's + %% try manually decoding. 'DirectoryString' is semi-arbitrary - + %% but it is the type which covers the various string types we + %% handle below. + try + {ST, S} = public_key:der_decode('DirectoryString', V), + format_directory_string(ST, S) + catch _:_ -> + format("~p", [V]) + end; +format_asn1_value(V) -> + format("~p", [V]). + +%% DirectoryString { INTEGER : maxSize } ::= CHOICE { +%% teletexString TeletexString (SIZE (1..maxSize)), +%% printableString PrintableString (SIZE (1..maxSize)), +%% bmpString BMPString (SIZE (1..maxSize)), +%% universalString UniversalString (SIZE (1..maxSize)), +%% uTF8String UTF8String (SIZE (1..maxSize)) } +%% +%% Precise definitions of printable / teletexString are hard to come +%% by. This is what I reconstructed: +%% +%% printableString: +%% "intended to represent the limited character sets available to +%% mainframe input terminals" +%% A-Z a-z 0-9 ' ( ) + , - . / : = ? [space] +%% http://msdn.microsoft.com/en-us/library/bb540814(v=vs.85).aspx +%% +%% teletexString: +%% "a sizable volume of software in the world treats TeletexString +%% (T61String) as a simple 8-bit string with mostly Windows Latin 1 +%% (superset of iso-8859-1) encoding" +%% http://www.mail-archive.com/asn1@asn1.org/msg00460.html +%% +%% (However according to that link X.680 actually defines +%% TeletexString in some much more involved and crazy way. I suggest +%% we treat it as ISO-8859-1 since Erlang does not support Windows +%% Latin 1). +%% +%% bmpString: +%% UCS-2 according to RFC 3641. Hence cannot represent Unicode +%% characters above 65535 (outside the "Basic Multilingual Plane"). +%% +%% universalString: +%% UCS-4 according to RFC 3641. +%% +%% utf8String: +%% UTF-8 according to RFC 3641. +%% +%% Within Rabbit we assume UTF-8 encoding. Since printableString is a +%% subset of ASCII it is also a subset of UTF-8. The others need +%% converting. Fortunately since the Erlang SSL library does the +%% decoding for us (albeit into a weird format, see below), we just +%% need to handle encoding into UTF-8. Note also that utf8Strings come +%% back as binary. +%% +%% Note for testing: the default Ubuntu configuration for openssl will +%% only create printableString or teletexString types no matter what +%% you do. Edit string_mask in the [req] section of +%% /etc/ssl/openssl.cnf to change this (see comments there). You +%% probably also need to set utf8 = yes to get it to accept UTF-8 on +%% the command line. Also note I could not get openssl to generate a +%% universalString. + +format_directory_string(printableString, S) -> S; +format_directory_string(teletexString, S) -> utf8_list_from(S); +format_directory_string(bmpString, S) -> utf8_list_from(S); +format_directory_string(universalString, S) -> utf8_list_from(S); +format_directory_string(utf8String, S) -> binary_to_list(S). + +utf8_list_from(S) -> + binary_to_list( + unicode:characters_to_binary(flatten_ssl_list(S), utf32, utf8)). + +%% The Erlang SSL implementation invents its own representation for +%% non-ascii strings - looking like [97,{0,0,3,187}] (that's LATIN +%% SMALL LETTER A followed by GREEK SMALL LETTER LAMDA). We convert +%% this into a list of unicode characters, which we can tell +%% unicode:characters_to_binary is utf32. + +flatten_ssl_list(L) -> [flatten_ssl_list_item(I) || I <- L]. + +flatten_ssl_list_item({A, B, C, D}) -> + A * (1 bsl 24) + B * (1 bsl 16) + C * (1 bsl 8) + D; +flatten_ssl_list_item(N) when is_number (N) -> + N. + +format(Fmt, Args) -> + lists:flatten(io_lib:format(Fmt, Args)). + diff --git a/src/emqttd_stats.erl b/src/emqx_stats.erl similarity index 91% rename from src/emqttd_stats.erl rename to src/emqx_stats.erl index 73a1471ac..b9ce291e5 100644 --- a/src/emqttd_stats.erl +++ b/src/emqx_stats.erl @@ -14,13 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_stats). +-module(emqx_stats). -behaviour(gen_server). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). -export([start_link/0, stop/0]). @@ -87,7 +87,7 @@ stop() -> -spec(set_client_stats(binary(), stats()) -> true). set_client_stats(ClientId, Stats) -> - ets:insert(?CLIENT_STATS_TAB, {ClientId, [{'$ts', emqttd_time:now_secs()}|Stats]}). + ets:insert(?CLIENT_STATS_TAB, {ClientId, [{'$ts', emqx_time:now_secs()}|Stats]}). -spec(get_client_stats(binary()) -> stats()). get_client_stats(ClientId) -> @@ -102,7 +102,7 @@ del_client_stats(ClientId) -> -spec(set_session_stats(binary(), stats()) -> true). set_session_stats(ClientId, Stats) -> - ets:insert(?SESSION_STATS_TAB, {ClientId, [{'$ts', emqttd_time:now_secs()}|Stats]}). + ets:insert(?SESSION_STATS_TAB, {ClientId, [{'$ts', emqx_time:now_secs()}|Stats]}). -spec(get_session_stats(binary()) -> stats()). get_session_stats(ClientId) -> @@ -152,7 +152,7 @@ setstats(Stat, MaxStat, Val) -> %%-------------------------------------------------------------------- init([]) -> - emqttd_time:seed(), + emqx_time:seed(), lists:foreach( fun(Tab) -> Tab = ets:new(Tab, [set, public, named_table, {write_concurrency, true}]) @@ -160,7 +160,7 @@ init([]) -> Topics = ?SYSTOP_CLIENTS ++ ?SYSTOP_SESSIONS ++ ?SYSTOP_PUBSUB ++ ?SYSTOP_RETAINED, ets:insert(?STATS_TAB, [{Topic, 0} || Topic <- Topics]), % Tick to publish stats - {ok, #state{tick = emqttd_broker:start_tick(tick)}, hibernate}. + {ok, #state{tick = emqx_broker:start_tick(tick)}, hibernate}. handle_call(stop, _From, State) -> {stop, normal, ok, State}; @@ -191,7 +191,7 @@ handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, #state{tick = TRef}) -> - emqttd_broker:stop_tick(TRef). + emqx_broker:stop_tick(TRef). code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -201,11 +201,11 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- publish(Stat, Val) -> - Msg = emqttd_message:make(stats, stats_topic(Stat), bin(Val)), - emqttd:publish(emqttd_message:set_flag(sys, Msg)). + Msg = emqx_message:make(stats, stats_topic(Stat), bin(Val)), + emqx:publish(emqx_message:set_flag(sys, Msg)). stats_topic(Stat) -> - emqttd_topic:systop(list_to_binary(lists:concat(['stats/', Stat]))). + emqx_topic:systop(list_to_binary(lists:concat(['stats/', Stat]))). bin(I) when is_integer(I) -> list_to_binary(integer_to_list(I)). diff --git a/src/emqx_sup.erl b/src/emqx_sup.erl new file mode 100644 index 000000000..63c52e4ef --- /dev/null +++ b/src/emqx_sup.erl @@ -0,0 +1,83 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_sup). + +-behaviour(supervisor). + +-author("Feng Lee "). + +-export([start_link/0, start_child/1, start_child/2, stop_child/1]). + +%% Supervisor callbacks +-export([init/1]). + +-type(startchild_ret() :: {ok, supervisor:child()} + | {ok, supervisor:child(), term()} + | {error, term()}). + +-define(SUPERVISOR, ?MODULE). + +-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). + +start_link() -> + supervisor:start_link({local, ?SUPERVISOR}, ?MODULE, []). + +-spec(start_child(atom(), worker | supervisor) -> startchild_ret()). +start_child(Mod, Type) when Type == worker orelse Type == supervisor -> + start_child(?CHILD(Mod, Type)). + +-spec(start_child(supervisor:child_spec()) -> startchild_ret()). +start_child(ChildSpec) when is_tuple(ChildSpec) -> + supervisor:start_child(?SUPERVISOR, ChildSpec). + +-spec(start_child(Mod::atom(), Type :: worker | supervisor) -> {ok, pid()}). +start_child(Mod, Type) when is_atom(Mod) and is_atom(Type) -> + supervisor:start_child(?MODULE, ?CHILD(Mod, Type)). + +-spec(stop_child(supervisor:child_id()) -> ok | {error, any()}). +stop_child(ChildId) -> + case supervisor:terminate_child(?SUPERVISOR, ChildId) of + ok -> supervisor:delete_child(?SUPERVISOR, ChildId); + Error -> Error + end. + +%%-------------------------------------------------------------------- +%% Supervisor callbacks +%%-------------------------------------------------------------------- + +init([]) -> + {ok, {{one_for_all, 0, 1}, + [?CHILD(emqx_ctl, worker), + ?CHILD(emqx_hooks, worker), + ?CHILD(emqx_router, worker), + ?CHILD(emqx_pubsub_sup, supervisor), + ?CHILD(emqx_stats, worker), + ?CHILD(emqx_metrics, worker), + ?CHILD(emqx_pooler, supervisor), + ?CHILD(emqx_trace_sup, supervisor), + ?CHILD(emqx_cm_sup, supervisor), + ?CHILD(emqx_sm_sup, supervisor), + ?CHILD(emqx_session_sup, supervisor), + ?CHILD(emqx_ws_client_sup, supervisor), + ?CHILD(emqx_broker, worker), + ?CHILD(emqx_alarm, worker), + ?CHILD(emqx_mod_sup, supervisor), + ?CHILD(emqx_bridge_sup_sup, supervisor), + ?CHILD(emqx_access_control, worker), + ?CHILD(emqx_sysmon_sup, supervisor)] + }}. + diff --git a/src/emqttd_sysmon.erl b/src/emqx_sysmon.erl similarity index 91% rename from src/emqttd_sysmon.erl rename to src/emqx_sysmon.erl index c94c1df54..77103c9d6 100644 --- a/src/emqttd_sysmon.erl +++ b/src/emqx_sysmon.erl @@ -14,14 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- -%% @doc VM System Monitor --module(emqttd_sysmon). +-module(emqx_sysmon). -author("Feng Lee "). -behavior(gen_server). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -export([start_link/1]). @@ -143,26 +142,24 @@ code_change(_OldVsn, State, _Extra) -> suppress(Key, SuccFun, State = #state{events = Events}) -> case lists:member(Key, Events) of - true -> - {noreply, State}; - false -> - SuccFun(), - {noreply, State#state{events = [Key|Events]}} + true -> {noreply, State}; + false -> SuccFun(), + {noreply, State#state{events = [Key|Events]}} end. procinfo(Pid) -> - case {emqttd_vm:get_process_info(Pid), emqttd_vm:get_process_gc(Pid)} of + case {emqx_vm:get_process_info(Pid), emqx_vm:get_process_gc(Pid)} of {undefined, _} -> undefined; {_, undefined} -> undefined; {Info, GcInfo} -> Info ++ GcInfo end. publish(Sysmon, WarnMsg) -> - Msg = emqttd_message:make(sysmon, topic(Sysmon), iolist_to_binary(WarnMsg)), - emqttd:publish(emqttd_message:set_flag(sys, Msg)). + Msg = emqx_message:make(sysmon, topic(Sysmon), iolist_to_binary(WarnMsg)), + emqx:publish(emqx_message:set_flag(sys, Msg)). topic(Sysmon) -> - emqttd_topic:systop(list_to_binary(lists:concat(['sysmon/', Sysmon]))). + emqx_topic:systop(list_to_binary(lists:concat(['sysmon/', Sysmon]))). %% start_tracelog(undefined) -> %% {ok, undefined}; diff --git a/src/emqttd_sysmon_sup.erl b/src/emqx_sysmon_sup.erl similarity index 82% rename from src/emqttd_sysmon_sup.erl rename to src/emqx_sysmon_sup.erl index 99e7a628d..6db24a30e 100644 --- a/src/emqttd_sysmon_sup.erl +++ b/src/emqx_sysmon_sup.erl @@ -14,7 +14,9 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_sysmon_sup). +-module(emqx_sysmon_sup). + +-author("Feng Lee "). -behaviour(supervisor). @@ -28,8 +30,8 @@ start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). init([]) -> - {ok, Env} = emqttd:env(sysmon), - Sysmon = {sysmon, {emqttd_sysmon, start_link, [Env]}, - permanent, 5000, worker, [emqttd_sysmon]}, + {ok, Env} = emqx:env(sysmon), + Sysmon = {sysmon, {emqx_sysmon, start_link, [Env]}, + permanent, 5000, worker, [emqx_sysmon]}, {ok, {{one_for_one, 10, 100}, [Sysmon]}}. diff --git a/src/emqttd_time.erl b/src/emqx_time.erl similarity index 98% rename from src/emqttd_time.erl rename to src/emqx_time.erl index 7e5940438..f6cb02854 100644 --- a/src/emqttd_time.erl +++ b/src/emqx_time.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_time). +-module(emqx_time). -author("Feng Lee "). diff --git a/src/emqttd_topic.erl b/src/emqx_topic.erl similarity index 93% rename from src/emqttd_topic.erl rename to src/emqx_topic.erl index 458a41f7d..3d4c2a741 100644 --- a/src/emqttd_topic.erl +++ b/src/emqx_topic.erl @@ -14,13 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_topic). +-module(emqx_topic). -author("Feng Lee "). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). -import(lists, [reverse/1]). @@ -186,6 +186,11 @@ parse(<<"$local/", Topic1/binary>>, Options) -> parse(Topic1, [local | Options]) end); +parse(<<"$fastlane/", Topic1/binary>>, Options) -> + if_not_contain(fastlane, Options, fun() -> + parse(Topic1, [fastlane | Options]) + end); + parse(<<"$queue/", Topic1/binary>>, Options) -> if_not_contain(share, Options,fun() -> parse(Topic1, [{share, '$queue'} | Options]) @@ -200,8 +205,8 @@ parse(<<"$share/", Topic1/binary>>, Options) -> parse(Topic, Options) -> {Topic, Options}. -if_not_contain(local, Options, Fun) -> - ?IF(lists:member(local, Options), error(invalid_topic), Fun()); +if_not_contain(Key, Options, Fun) when Key == local; Key == fastlane -> + ?IF(lists:member(Key, Options), error(invalid_topic), Fun()); if_not_contain(share, Options, Fun) -> ?IF(lists:keyfind(share, 1, Options), error(invalid_topic), Fun()). diff --git a/src/emqttd_trace.erl b/src/emqx_trace.erl similarity index 97% rename from src/emqttd_trace.erl rename to src/emqx_trace.erl index 4d46d9165..7b09b55a8 100644 --- a/src/emqttd_trace.erl +++ b/src/emqx_trace.erl @@ -14,14 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- -%% @docTrace MQTT packets/messages by ClientID or Topic. --module(emqttd_trace). +-module(emqx_trace). -behaviour(gen_server). -author("Feng Lee "). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). %% API Function Exports -export([start_link/0]). diff --git a/src/emqttd_trace_sup.erl b/src/emqx_trace_sup.erl similarity index 88% rename from src/emqttd_trace_sup.erl rename to src/emqx_trace_sup.erl index 728e6818e..31f5ba7d8 100644 --- a/src/emqttd_trace_sup.erl +++ b/src/emqx_trace_sup.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_trace_sup). +-module(emqx_trace_sup). -author("Feng Lee "). @@ -30,7 +30,7 @@ start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). init([]) -> - Trace = {trace, {emqttd_trace, start_link, []}, - permanent, 5000, worker, [emqttd_trace]}, + Trace = {trace, {emqx_trace, start_link, []}, + permanent, 5000, worker, [emqx_trace]}, {ok, {{one_for_one, 10, 3600}, [Trace]}}. diff --git a/src/emqttd_trie.erl b/src/emqx_trie.erl similarity index 95% rename from src/emqttd_trie.erl rename to src/emqx_trie.erl index 5b36e6e04..4ad525a90 100644 --- a/src/emqttd_trie.erl +++ b/src/emqx_trie.erl @@ -18,11 +18,11 @@ %% [Trie](http://en.wikipedia.org/wiki/Trie) %% @end --module(emqttd_trie). +-module(emqx_trie). -author("Feng Lee "). --include("emqttd_trie.hrl"). +-include("emqx_trie.hrl"). %% Mnesia Callbacks -export([mnesia/1]). @@ -71,7 +71,7 @@ insert(Topic) when is_binary(Topic) -> write_trie_node(TrieNode#trie_node{topic=Topic}); [] -> % Add trie path - lists:foreach(fun add_path/1, emqttd_topic:triples(Topic)), + lists:foreach(fun add_path/1, emqx_topic:triples(Topic)), % Add last node write_trie_node(#trie_node{node_id=Topic, topic=Topic}) end. @@ -79,7 +79,7 @@ insert(Topic) when is_binary(Topic) -> %% @doc Find trie nodes that match topic -spec(match(Topic :: binary()) -> list(MatchedTopic :: binary())). match(Topic) when is_binary(Topic) -> - TrieNodes = match_node(root, emqttd_topic:words(Topic)), + TrieNodes = match_node(root, emqx_topic:words(Topic)), [Name || #trie_node{topic=Name} <- TrieNodes, Name =/= undefined]. %% @doc Lookup a Trie Node @@ -93,7 +93,7 @@ delete(Topic) when is_binary(Topic) -> case mnesia:read(mqtt_trie_node, Topic) of [#trie_node{edge_count=0}] -> mnesia:delete({mqtt_trie_node, Topic}), - delete_path(lists:reverse(emqttd_topic:triples(Topic))); + delete_path(lists:reverse(emqx_topic:triples(Topic))); [TrieNode] -> write_trie_node(TrieNode#trie_node{topic = undefined}); [] -> diff --git a/src/emqttd_vm.erl b/src/emqx_vm.erl similarity index 99% rename from src/emqttd_vm.erl rename to src/emqx_vm.erl index 16fae60ae..a4b9a67fc 100644 --- a/src/emqttd_vm.erl +++ b/src/emqx_vm.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_vm). +-module(emqx_vm). -export([schedulers/0]). diff --git a/src/emqttd_ws.erl b/src/emqx_ws.erl similarity index 88% rename from src/emqttd_ws.erl rename to src/emqx_ws.erl index c7d0b2119..1e2870a42 100644 --- a/src/emqttd_ws.erl +++ b/src/emqx_ws.erl @@ -14,11 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_ws). +-module(emqx_ws). -author("Feng Lee "). --include("emqttd_protocol.hrl"). +-include("emqx_protocol.hrl"). -import(proplists, [get_value/3]). @@ -44,12 +44,12 @@ handle_request('GET', "/mqtt", Req) -> Proto = check_protocol_header(Req), case {is_websocket(Upgrade), Proto} of {true, "mqtt" ++ _Vsn} -> - {ok, ProtoEnv} = emqttd:env(protocol), + {ok, ProtoEnv} = emqx:env(protocol), PacketSize = get_value(max_packet_size, ProtoEnv, ?MAX_PACKET_SIZE), - Parser = emqttd_parser:initial_state(PacketSize), + Parser = emqx_parser:initial_state(PacketSize), %% Upgrade WebSocket. {ReentryWs, ReplyChannel} = mochiweb_websocket:upgrade_connection(Req, fun ?MODULE:ws_loop/3), - {ok, ClientPid} = emqttd_ws_client_sup:start_client(self(), Req, ReplyChannel), + {ok, ClientPid} = emqx_ws_client_sup:start_client(self(), Req, ReplyChannel), ReentryWs(#wsocket_state{peername = Req:get(peername), parser = Parser, max_packet_size = PacketSize, client_pid = ClientPid}); {false, _} -> @@ -68,7 +68,7 @@ is_websocket(Upgrade) -> Upgrade =/= undefined andalso string:to_lower(Upgrade) =:= "websocket". check_protocol_header(Req) -> - case emqttd:env(websocket_protocol_header, false) of + case emqx:env(websocket_protocol_header, false) of true -> get_protocol_header(Req); false -> "mqtt-v3.1.1" end. @@ -90,8 +90,8 @@ ws_loop([<<>>], State, _ReplyChannel) -> State; ws_loop(Data, State = #wsocket_state{client_pid = ClientPid, parser = Parser}, ReplyChannel) -> ?WSLOG(debug, "RECV ~p", [Data], State), - emqttd_metrics:inc('bytes/received', iolist_size(Data)), - case catch emqttd_parser:parse(iolist_to_binary(Data), Parser) of + emqx_metrics:inc('bytes/received', iolist_size(Data)), + case catch emqx_parser:parse(iolist_to_binary(Data), Parser) of {more, NewParser} -> State#wsocket_state{parser = NewParser}; {ok, Packet, Rest} -> @@ -107,5 +107,5 @@ ws_loop(Data, State = #wsocket_state{client_pid = ClientPid, parser = Parser}, R end. reset_parser(State = #wsocket_state{max_packet_size = PacketSize}) -> - State#wsocket_state{parser = emqttd_parser:initial_state(PacketSize)}. + State#wsocket_state{parser = emqx_parser:initial_state(PacketSize)}. diff --git a/src/emqttd_ws_client.erl b/src/emqx_ws_client.erl similarity index 83% rename from src/emqttd_ws_client.erl rename to src/emqx_ws_client.erl index a583611a4..e1861684b 100644 --- a/src/emqttd_ws_client.erl +++ b/src/emqx_ws_client.erl @@ -16,19 +16,19 @@ %% @doc MQTT WebSocket Connection. --module(emqttd_ws_client). +-module(emqx_ws_client). -behaviour(gen_server2). -author("Feng Lee "). --include("emqttd.hrl"). +-include("emqx.hrl"). --include("emqttd_protocol.hrl"). +-include("emqx_mqtt.hrl"). --include("emqttd_internal.hrl"). +-include("emqx_internal.hrl"). --import(proplists, [get_value/3]). +-import(proplists, [get_value/2, get_value/3]). %% API Exports -export([start_link/4]). @@ -96,11 +96,11 @@ init([Env, WsPid, Req, ReplyChannel]) -> Headers = mochiweb_headers:to_list( mochiweb_request:get(headers, Req)), Conn = Req:get(connection), - ProtoState = emqttd_protocol:init(Conn, Peername, send_fun(ReplyChannel), - [{ws_initial_headers, Headers} | Env]), + ProtoState = emqx_protocol:init(Conn, Peername, send_fun(ReplyChannel), + [{ws_initial_headers, Headers} | Env]), IdleTimeout = get_value(client_idle_timeout, Env, 30000), EnableStats = get_value(client_enable_stats, Env, false), - ForceGcCount = emqttd_gc:conn_max_gc_count(), + ForceGcCount = emqx_gc:conn_max_gc_count(), {ok, #wsclient_state{connection = Conn, ws_pid = WsPid, peername = Peername, @@ -117,24 +117,24 @@ prioritise_info(Msg, _Len, _State) -> handle_pre_hibernate(State = #wsclient_state{ws_pid = WsPid}) -> erlang:garbage_collect(WsPid), - {hibernate, emqttd_gc:reset_conn_gc_count(#wsclient_state.force_gc_count, emit_stats(State))}. + {hibernate, emqx_gc:reset_conn_gc_count(#wsclient_state.force_gc_count, emit_stats(State))}. handle_call(info, From, State = #wsclient_state{peername = Peername, proto_state = ProtoState}) -> - Info = [{websocket, true}, {peername, Peername} | emqttd_protocol:info(ProtoState)], + Info = [{websocket, true}, {peername, Peername} | emqx_protocol:info(ProtoState)], {reply, Stats, _, _} = handle_call(stats, From, State), reply(lists:append(Info, Stats), State); handle_call(stats, _From, State = #wsclient_state{proto_state = ProtoState}) -> - reply(lists:append([emqttd_misc:proc_stats(), + reply(lists:append([emqx_misc:proc_stats(), wsock_stats(State), - emqttd_protocol:stats(ProtoState)]), State); + emqx_protocol:stats(ProtoState)]), State); handle_call(kick, _From, State) -> {stop, {shutdown, kick}, ok, State}; handle_call(session, _From, State = #wsclient_state{proto_state = ProtoState}) -> - reply(emqttd_protocol:session(ProtoState), State); + reply(emqx_protocol:session(ProtoState), State); handle_call({clean_acl_cache, Topic}, _From, State) -> erase({acl, publish, Topic}), @@ -145,8 +145,8 @@ handle_call(Req, _From, State) -> reply({error, unexpected_request}, State). handle_cast({received, Packet}, State = #wsclient_state{proto_state = ProtoState}) -> - emqttd_metrics:received(Packet), - case emqttd_protocol:received(Packet, ProtoState) of + emqx_metrics:received(Packet), + case emqx_protocol:received(Packet, ProtoState) of {ok, ProtoState1} -> {noreply, gc(State#wsclient_state{proto_state = ProtoState1}), hibernate}; {error, Error} -> @@ -165,32 +165,36 @@ handle_cast(Msg, State) -> handle_info({subscribe, TopicTable}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:subscribe(TopicTable, ProtoState) + emqx_protocol:subscribe(TopicTable, ProtoState) end, State); handle_info({unsubscribe, Topics}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:unsubscribe(Topics, ProtoState) + emqx_protocol:unsubscribe(Topics, ProtoState) end, State); handle_info({suback, PacketId, GrantedQos}, State) -> with_proto( fun(ProtoState) -> Packet = ?SUBACK_PACKET(PacketId, GrantedQos), - emqttd_protocol:send(Packet, ProtoState) + emqx_protocol:send(Packet, ProtoState) end, State); +%% Fastlane +handle_info({dispatch, _Topic, Message}, State) -> + handle_info({deliver, Message#mqtt_message{qos = ?QOS_0}}, State); + handle_info({deliver, Message}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:send(Message, ProtoState) + emqx_protocol:send(Message, ProtoState) end, gc(State)); handle_info({redeliver, {?PUBREL, PacketId}}, State) -> with_proto( fun(ProtoState) -> - emqttd_protocol:pubrel(PacketId, ProtoState) + emqx_protocol:pubrel(PacketId, ProtoState) end, State); handle_info(emit_stats, State) -> @@ -205,7 +209,7 @@ handle_info({shutdown, conflict, {ClientId, NewPid}}, State) -> handle_info({keepalive, start, Interval}, State = #wsclient_state{connection = Conn}) -> ?WSLOG(debug, "Keepalive at the interval of ~p", [Interval], State), - case emqttd_keepalive:start(stat_fun(Conn), Interval, {keepalive, check}) of + case emqx_keepalive:start(stat_fun(Conn), Interval, {keepalive, check}) of {ok, KeepAlive} -> {noreply, State#wsclient_state{keepalive = KeepAlive}, hibernate}; {error, Error} -> @@ -214,7 +218,7 @@ handle_info({keepalive, start, Interval}, State = #wsclient_state{connection = C end; handle_info({keepalive, check}, State = #wsclient_state{keepalive = KeepAlive}) -> - case emqttd_keepalive:check(KeepAlive) of + case emqx_keepalive:check(KeepAlive) of {ok, KeepAlive1} -> {noreply, emit_stats(State#wsclient_state{keepalive = KeepAlive1}), hibernate}; {error, timeout} -> @@ -234,7 +238,7 @@ handle_info({'EXIT', WsPid, Reason}, State = #wsclient_state{ws_pid = WsPid}) -> %% The session process exited unexpectedly. handle_info({'EXIT', Pid, Reason}, State = #wsclient_state{proto_state = ProtoState}) -> - case emqttd_protocol:session(ProtoState) of + case emqx_protocol:session(ProtoState) of Pid -> stop(Reason, State); _ -> ?WSLOG(error, "Unexpected EXIT: ~p, Reason: ~p", [Pid, Reason], State), {noreply, State, hibernate} @@ -245,12 +249,12 @@ handle_info(Info, State) -> {noreply, State, hibernate}. terminate(Reason, #wsclient_state{proto_state = ProtoState, keepalive = KeepAlive}) -> - emqttd_keepalive:cancel(KeepAlive), + emqx_keepalive:cancel(KeepAlive), case Reason of {shutdown, Error} -> - emqttd_protocol:shutdown(Error, ProtoState); + emqx_protocol:shutdown(Error, ProtoState); _ -> - emqttd_protocol:shutdown(Reason, ProtoState) + emqx_protocol:shutdown(Reason, ProtoState) end. code_change(_OldVsn, State, _Extra) -> @@ -262,8 +266,8 @@ code_change(_OldVsn, State, _Extra) -> send_fun(ReplyChannel) -> fun(Packet) -> - Data = emqttd_serializer:serialize(Packet), - emqttd_metrics:inc('bytes/sent', iolist_size(Data)), + Data = emqx_serializer:serialize(Packet), + emqx_metrics:inc('bytes/sent', iolist_size(Data)), ReplyChannel({binary, Data}) end. @@ -276,7 +280,7 @@ stat_fun(Conn) -> end. emit_stats(State = #wsclient_state{proto_state = ProtoState}) -> - emit_stats(emqttd_protocol:clientid(ProtoState), State). + emit_stats(emqx_protocol:clientid(ProtoState), State). emit_stats(_ClientId, State = #wsclient_state{enable_stats = false}) -> State; @@ -284,7 +288,7 @@ emit_stats(undefined, State) -> State; emit_stats(ClientId, State) -> {reply, Stats, _, _} = handle_call(stats, undefined, State), - emqttd_stats:set_client_stats(ClientId, Stats), + emqx_stats:set_client_stats(ClientId, Stats), State. wsock_stats(#wsclient_state{connection = Conn}) -> @@ -308,5 +312,5 @@ stop(Reason, State) -> gc(State) -> Cb = fun() -> emit_stats(State) end, - emqttd_gc:maybe_force_gc(#wsclient_state.force_gc_count, State, Cb). + emqx_gc:maybe_force_gc(#wsclient_state.force_gc_count, State, Cb). diff --git a/src/emqttd_ws_client_sup.erl b/src/emqx_ws_client_sup.erl similarity index 86% rename from src/emqttd_ws_client_sup.erl rename to src/emqx_ws_client_sup.erl index 21f683eaa..9fdbbcfc7 100644 --- a/src/emqttd_ws_client_sup.erl +++ b/src/emqx_ws_client_sup.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_ws_client_sup). +-module(emqx_ws_client_sup). -author("Feng Lee "). @@ -39,8 +39,8 @@ start_client(WsPid, Req, ReplyChannel) -> %%-------------------------------------------------------------------- init([]) -> - Env = lists:append(emqttd:env(client, []), emqttd:env(protocol, [])), + Env = lists:append(emqx:env(client, []), emqx:env(protocol, [])), {ok, {{simple_one_for_one, 0, 1}, - [{ws_client, {emqttd_ws_client, start_link, [Env]}, - temporary, 5000, worker, [emqttd_ws_client]}]}}. + [{ws_client, {emqx_ws_client, start_link, [Env]}, + temporary, 5000, worker, [emqx_ws_client]}]}}. diff --git a/test/emqttd_inflight_SUITE.erl b/test/emqttd_inflight_SUITE.erl deleted file mode 100644 index de5391f1a..000000000 --- a/test/emqttd_inflight_SUITE.erl +++ /dev/null @@ -1,51 +0,0 @@ -%% -%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) -%% - --module(emqttd_inflight_SUITE). - --author("Feng Lee "). - --include_lib("eunit/include/eunit.hrl"). - -%% CT --compile(export_all). - -all() -> [t_contain, t_lookup, t_insert, t_update, t_delete, t_window, - t_is_full, t_is_empty]. - -t_contain(_) -> - Inflight = emqttd_inflight:new(0), - ?assertNot(Inflight:contain(k)), - Inflight1 = Inflight:insert(k, v), - ?assert(Inflight1:contain(k)). - -t_lookup(_) -> - Inflight = (emqttd_inflight:new(0)):insert(k, v), - ?assertEqual(v, Inflight:lookup(k)). - -t_insert(_) -> - Inflight = ((emqttd_inflight:new(0)):insert(k1, v1)):insert(k2, v2), - ?assertEqual(v2, Inflight:lookup(k2)). - -t_update(_) -> - Inflight = ((emqttd_inflight:new(0)):insert(k, v1)):update(k, v2), - ?assertEqual(v2, Inflight:lookup(k)). - -t_delete(_) -> - Inflight = ((emqttd_inflight:new(0)):insert(k, v1)):delete(k), - ?assert(Inflight:is_empty()). - -t_window(_) -> - ?assertEqual([], (emqttd_inflight:new(10)):window()), - Inflight = ((emqttd_inflight:new(0)):insert(1, 1)):insert(2, 2), - ?assertEqual([1, 2], Inflight:window()). - -t_is_full(_) -> - Inflight = ((emqttd_inflight:new(1)):insert(k, v1)), - ?assert(Inflight:is_full()). - -t_is_empty(_) -> - Inflight = ((emqttd_inflight:new(1)):insert(k, v1)), - ?assertNot(Inflight:is_empty()). - diff --git a/test/emqttd_SUITE.erl b/test/emqx_SUITE.erl similarity index 58% rename from test/emqttd_SUITE.erl rename to test/emqx_SUITE.erl index 195820248..c803244ab 100644 --- a/test/emqttd_SUITE.erl +++ b/test/emqx_SUITE.erl @@ -14,18 +14,20 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_SUITE). +-module(emqx_SUITE). -compile(export_all). --include("emqttd.hrl"). +-include("emqx.hrl"). + +-include("emqx_mqtt.hrl"). + +-define(APP, emqx). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(APP, emqttd). - -define(CONTENT_TYPE, "application/json"). -define(MQTT_SSL_TWOWAY, [{cacertfile, "certs/cacert.pem"}, @@ -67,15 +69,14 @@ all() -> {group, http}, {group, alarms}, {group, cli}, - {group, get_api}, + {group, rest_api}, {group, cleanSession}]. groups() -> [{protocol, [sequence], [mqtt_connect, - mqtt_ssl_twoway, - mqtt_ssl_oneway - ]}, + mqtt_ssl_oneway, + mqtt_ssl_twoway]}, {pubsub, [sequence], [subscribe_unsubscribe, publish, pubsub, @@ -121,18 +122,22 @@ groups() -> conflict_listeners ]}, cli_vm]}, - {cleanSession, [sequence], - [cleanSession_validate]}, - {get_api, [sequence], [get_api_lists]}]. + {cleanSession, [sequence], + [cleanSession_validate, + cleanSession_validate1] + }, + {rest_api, [sequence], [get_api_lists]} + ]. init_per_suite(Config) -> NewConfig = generate_config(), lists:foreach(fun set_app_env/1, NewConfig), - application:ensure_all_started(?APP), + Apps = application:ensure_all_started(?APP), + ct:log("Apps:~p", [Apps]), Config. end_per_suite(_Config) -> - emqttd:shutdown(). + emqx:shutdown(). %%-------------------------------------------------------------------- %% Protocol Test @@ -153,12 +158,12 @@ connect_broker_(Packet, RecvSize) -> Data. mqtt_ssl_oneway(_) -> - emqttd:stop(), + emqx:stop(), change_opts(ssl_oneway), - emqttd:start(), - timer:sleep(6000), + emqx:start(), {ok, SslOneWay} = emqttc:start_link([{host, "localhost"}, {port, 8883}, + {logger, debug}, {client_id, <<"ssloneway">>}, ssl]), timer:sleep(100), emqttc:subscribe(SslOneWay, <<"topic">>, qos1), @@ -174,13 +179,12 @@ mqtt_ssl_oneway(_) -> emqttc:disconnect(SslOneWay), emqttc:disconnect(Pub). -mqtt_ssl_twoway(_) -> - emqttd:stop(), +mqtt_ssl_twoway(_Config) -> + emqx:stop(), change_opts(ssl_twoway), - emqttd:start(), - timer:sleep(6000), - ClientSSl = [{Key, local_path(["etc", File])} || - {Key, File} <- ?MQTT_SSL_CLIENT], + emqx:start(), + timer:sleep(3000), + ClientSSl = [{Key, local_path(["etc", File])} || {Key, File} <- ?MQTT_SSL_CLIENT], {ok, SslTwoWay} = emqttc:start_link([{host, "localhost"}, {port, 8883}, {client_id, <<"ssltwoway">>}, @@ -202,82 +206,82 @@ mqtt_ssl_twoway(_) -> %%-------------------------------------------------------------------- subscribe_unsubscribe(_) -> - ok = emqttd:subscribe(<<"topic">>, <<"clientId">>), - ok = emqttd:subscribe(<<"topic/1">>, <<"clientId">>, [{qos, 1}]), - ok = emqttd:subscribe(<<"topic/2">>, <<"clientId">>, [{qos, 2}]), - ok = emqttd:unsubscribe(<<"topic">>, <<"clientId">>), - ok = emqttd:unsubscribe(<<"topic/1">>, <<"clientId">>), - ok = emqttd:unsubscribe(<<"topic/2">>, <<"clientId">>). + ok = emqx:subscribe(<<"topic">>, <<"clientId">>), + ok = emqx:subscribe(<<"topic/1">>, <<"clientId">>, [{qos, 1}]), + ok = emqx:subscribe(<<"topic/2">>, <<"clientId">>, [{qos, 2}]), + ok = emqx:unsubscribe(<<"topic">>, <<"clientId">>), + ok = emqx:unsubscribe(<<"topic/1">>, <<"clientId">>), + ok = emqx:unsubscribe(<<"topic/2">>, <<"clientId">>). publish(_) -> - Msg = emqttd_message:make(ct, <<"test/pubsub">>, <<"hello">>), - ok = emqttd:subscribe(<<"test/+">>), + Msg = emqx_message:make(ct, <<"test/pubsub">>, <<"hello">>), + ok = emqx:subscribe(<<"test/+">>), timer:sleep(10), - emqttd:publish(Msg), + emqx:publish(Msg), ?assert(receive {dispatch, <<"test/+">>, Msg} -> true after 5 -> false end). pubsub(_) -> Self = self(), - ok = emqttd:subscribe(<<"a/b/c">>, Self, [{qos, 1}]), - ?assertMatch({error, _}, emqttd:subscribe(<<"a/b/c">>, Self, [{qos, 2}])), + ok = emqx:subscribe(<<"a/b/c">>, Self, [{qos, 1}]), + ?assertMatch({error, _}, emqx:subscribe(<<"a/b/c">>, Self, [{qos, 2}])), timer:sleep(10), [{Self, <<"a/b/c">>}] = ets:lookup(mqtt_subscription, Self), [{<<"a/b/c">>, Self}] = ets:lookup(mqtt_subscriber, <<"a/b/c">>), - emqttd:publish(emqttd_message:make(ct, <<"a/b/c">>, <<"hello">>)), + emqx:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), ?assert(receive {dispatch, <<"a/b/c">>, _} -> true after 2 -> false end), spawn(fun() -> - emqttd:subscribe(<<"a/b/c">>), - emqttd:subscribe(<<"c/d/e">>), + emqx:subscribe(<<"a/b/c">>), + emqx:subscribe(<<"c/d/e">>), timer:sleep(10), - emqttd:unsubscribe(<<"a/b/c">>) + emqx:unsubscribe(<<"a/b/c">>) end), timer:sleep(20), - emqttd:unsubscribe(<<"a/b/c">>). + emqx:unsubscribe(<<"a/b/c">>). t_local_subscribe(_) -> - emqttd:subscribe("$local/topic0"), - emqttd:subscribe("$local/topic1", <<"x">>), - emqttd:subscribe("$local/topic2", <<"x">>, [{qos, 2}]), + emqx:subscribe("$local/topic0"), + emqx:subscribe("$local/topic1", <<"x">>), + emqx:subscribe("$local/topic2", <<"x">>, [{qos, 2}]), timer:sleep(10), - ?assertEqual([self()], emqttd:subscribers("$local/topic0")), - ?assertEqual([<<"x">>], emqttd:subscribers("$local/topic1")), - ?assertEqual([{<<"$local/topic1">>,<<"x">>,[]},{<<"$local/topic2">>,<<"x">>,[{qos,2}]}], emqttd:subscriptions(<<"x">>)), + ?assertEqual([self()], emqx:subscribers("$local/topic0")), + ?assertEqual([<<"x">>], emqx:subscribers("$local/topic1")), + ?assertEqual([{<<"$local/topic1">>,<<"x">>,[]},{<<"$local/topic2">>,<<"x">>,[{qos,2}]}], emqx:subscriptions(<<"x">>)), - ?assertEqual(ok, emqttd:unsubscribe("$local/topic0")), - ?assertMatch({error, {subscription_not_found, _}}, emqttd:unsubscribe("$local/topic0")), - ?assertEqual(ok, emqttd:unsubscribe("$local/topic1", <<"x">>)), - ?assertEqual(ok, emqttd:unsubscribe("$local/topic2", <<"x">>)), - ?assertEqual([], emqttd:subscribers("topic1")), - ?assertEqual([], emqttd:subscriptions(<<"x">>)). + ?assertEqual(ok, emqx:unsubscribe("$local/topic0")), + ?assertMatch({error, {subscription_not_found, _}}, emqx:unsubscribe("$local/topic0")), + ?assertEqual(ok, emqx:unsubscribe("$local/topic1", <<"x">>)), + ?assertEqual(ok, emqx:unsubscribe("$local/topic2", <<"x">>)), + ?assertEqual([], emqx:subscribers("topic1")), + ?assertEqual([], emqx:subscriptions(<<"x">>)). t_shared_subscribe(_) -> - emqttd:subscribe("$local/$share/group1/topic1"), - emqttd:subscribe("$share/group2/topic2"), - emqttd:subscribe("$queue/topic3"), + emqx:subscribe("$local/$share/group1/topic1"), + emqx:subscribe("$share/group2/topic2"), + emqx:subscribe("$queue/topic3"), timer:sleep(10), - ?assertEqual([self()], emqttd:subscribers(<<"$local/$share/group1/topic1">>)), + ?assertEqual([self()], emqx:subscribers(<<"$local/$share/group1/topic1">>)), ?assertEqual([{<<"$local/$share/group1/topic1">>, self(), []}, {<<"$queue/topic3">>, self(), []}, {<<"$share/group2/topic2">>, self(), []}], - lists:sort(emqttd:subscriptions(self()))), - emqttd:unsubscribe("$local/$share/group1/topic1"), - emqttd:unsubscribe("$share/group2/topic2"), - emqttd:unsubscribe("$queue/topic3"), - ?assertEqual([], lists:sort(emqttd:subscriptions(self()))). + lists:sort(emqx:subscriptions(self()))), + emqx:unsubscribe("$local/$share/group1/topic1"), + emqx:unsubscribe("$share/group2/topic2"), + emqx:unsubscribe("$queue/topic3"), + ?assertEqual([], lists:sort(emqx:subscriptions(self()))). 'pubsub#'(_) -> - emqttd:subscribe(<<"a/#">>), + emqx:subscribe(<<"a/#">>), timer:sleep(10), - emqttd:publish(emqttd_message:make(ct, <<"a/b/c">>, <<"hello">>)), + emqx:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), ?assert(receive {dispatch, <<"a/#">>, _} -> true after 2 -> false end), - emqttd:unsubscribe(<<"a/#">>). + emqx:unsubscribe(<<"a/#">>). 'pubsub+'(_) -> - emqttd:subscribe(<<"a/+/+">>), + emqx:subscribe(<<"a/+/+">>), timer:sleep(10), - emqttd:publish(emqttd_message:make(ct, <<"a/b/c">>, <<"hello">>)), + emqx:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), ?assert(receive {dispatch, <<"a/+/+">>, _} -> true after 1 -> false end), - emqttd:unsubscribe(<<"a/+/+">>). + emqx:unsubscribe(<<"a/+/+">>). loop_recv(Topic, Timeout) -> loop_recv(Topic, Timeout, []). @@ -296,42 +300,42 @@ loop_recv(Topic, Timeout, Acc) -> router_add_del(_) -> %% Add - emqttd_router:add_route(<<"#">>), - emqttd_router:add_route(<<"a/b/c">>), - emqttd_router:add_route(<<"+/#">>, node()), + emqx_router:add_route(<<"#">>), + emqx_router:add_route(<<"a/b/c">>), + emqx_router:add_route(<<"+/#">>, node()), Routes = [R1, R2 | _] = [ #mqtt_route{topic = <<"#">>, node = node()}, #mqtt_route{topic = <<"+/#">>, node = node()}, #mqtt_route{topic = <<"a/b/c">>, node = node()}], - Routes = lists:sort(emqttd_router:match(<<"a/b/c">>)), + Routes = lists:sort(emqx_router:match(<<"a/b/c">>)), %% Batch Add - emqttd_router:add_routes(Routes), - Routes = lists:sort(emqttd_router:match(<<"a/b/c">>)), + emqx_router:add_routes(Routes), + Routes = lists:sort(emqx_router:match(<<"a/b/c">>)), %% Del - emqttd_router:del_route(<<"a/b/c">>), - [R1, R2] = lists:sort(emqttd_router:match(<<"a/b/c">>)), - {atomic, []} = mnesia:transaction(fun emqttd_trie:lookup/1, [<<"a/b/c">>]), + emqx_router:del_route(<<"a/b/c">>), + [R1, R2] = lists:sort(emqx_router:match(<<"a/b/c">>)), + {atomic, []} = mnesia:transaction(fun emqx_trie:lookup/1, [<<"a/b/c">>]), %% Batch Del R3 = #mqtt_route{topic = <<"#">>, node = 'a@127.0.0.1'}, - emqttd_router:add_route(R3), - emqttd_router:del_routes([R1, R2]), - emqttd_router:del_route(R3), - [] = lists:sort(emqttd_router:match(<<"a/b/c">>)). + emqx_router:add_route(R3), + emqx_router:del_routes([R1, R2]), + emqx_router:del_route(R3), + [] = lists:sort(emqx_router:match(<<"a/b/c">>)). router_print(_) -> Routes = [#mqtt_route{topic = <<"a/b/c">>, node = node()}, #mqtt_route{topic = <<"#">>, node = node()}, #mqtt_route{topic = <<"+/#">>, node = node()}], - emqttd_router:add_routes(Routes), - emqttd_router:print(<<"a/b/c">>). + emqx_router:add_routes(Routes), + emqx_router:print(<<"a/b/c">>). router_unused(_) -> - gen_server:call(emqttd_router, bad_call), - gen_server:cast(emqttd_router, bad_msg), - emqttd_router ! bad_info. + gen_server:call(emqx_router, bad_call), + gen_server:cast(emqx_router, bad_msg), + emqx_router ! bad_info. recv_loop(Msgs) -> receive @@ -346,17 +350,17 @@ recv_loop(Msgs) -> %%-------------------------------------------------------------------- start_session(_) -> - {ok, ClientPid} = emqttd_mock_client:start_link(<<"clientId">>), - {ok, SessPid} = emqttd_mock_client:start_session(ClientPid), - Message = emqttd_message:make(<<"clientId">>, 2, <<"topic">>, <<"hello">>), + {ok, ClientPid} = emqx_mock_client:start_link(<<"clientId">>), + {ok, SessPid} = emqx_mock_client:start_session(ClientPid), + Message = emqx_message:make(<<"clientId">>, 2, <<"topic">>, <<"hello">>), Message1 = Message#mqtt_message{pktid = 1}, - emqttd_session:publish(SessPid, Message1), - emqttd_session:pubrel(SessPid, 1), - emqttd_session:subscribe(SessPid, [{<<"topic/session">>, [{qos, 2}]}]), - Message2 = emqttd_message:make(<<"clientId">>, 1, <<"topic/session">>, <<"test">>), - emqttd_session:publish(SessPid, Message2), - emqttd_session:unsubscribe(SessPid, [{<<"topic/session">>, []}]), - emqttd_mock_client:stop(ClientPid). + emqx_session:publish(SessPid, Message1), + emqx_session:pubrel(SessPid, 1), + emqx_session:subscribe(SessPid, [{<<"topic/session">>, [{qos, 2}]}]), + Message2 = emqx_message:make(<<"clientId">>, 1, <<"topic/session">>, <<"test">>), + emqx_session:publish(SessPid, Message2), + emqx_session:unsubscribe(SessPid, [{<<"topic/session">>, []}]), + emqx_mock_client:stop(ClientPid). %%-------------------------------------------------------------------- %% Broker Group @@ -368,55 +372,55 @@ hook_unhook(_) -> %% Metric Group %%-------------------------------------------------------------------- inc_dec_metric(_) -> - emqttd_metrics:inc(gauge, 'messages/retained', 10), - emqttd_metrics:dec(gauge, 'messages/retained', 10). + emqx_metrics:inc(gauge, 'messages/retained', 10), + emqx_metrics:dec(gauge, 'messages/retained', 10). %%-------------------------------------------------------------------- %% Stats Group %%-------------------------------------------------------------------- set_get_stat(_) -> - emqttd_stats:setstat('retained/max', 99), - 99 = emqttd_stats:getstat('retained/max'). + emqx_stats:setstat('retained/max', 99), + 99 = emqx_stats:getstat('retained/max'). %%-------------------------------------------------------------------- %% Hook Test %%-------------------------------------------------------------------- add_delete_hook(_) -> - ok = emqttd:hook(test_hook, fun ?MODULE:hook_fun1/1, []), - ok = emqttd:hook(test_hook, {tag, fun ?MODULE:hook_fun2/1}, []), - {error, already_hooked} = emqttd:hook(test_hook, {tag, fun ?MODULE:hook_fun2/1}, []), + ok = emqx:hook(test_hook, fun ?MODULE:hook_fun1/1, []), + ok = emqx:hook(test_hook, {tag, fun ?MODULE:hook_fun2/1}, []), + {error, already_hooked} = emqx:hook(test_hook, {tag, fun ?MODULE:hook_fun2/1}, []), Callbacks = [{callback, undefined, fun ?MODULE:hook_fun1/1, [], 0}, {callback, tag, fun ?MODULE:hook_fun2/1, [], 0}], - Callbacks = emqttd_hooks:lookup(test_hook), - ok = emqttd:unhook(test_hook, fun ?MODULE:hook_fun1/1), - ct:print("Callbacks: ~p~n", [emqttd_hooks:lookup(test_hook)]), - ok = emqttd:unhook(test_hook, {tag, fun ?MODULE:hook_fun2/1}), - {error, not_found} = emqttd:unhook(test_hook1, {tag, fun ?MODULE:hook_fun2/1}), - [] = emqttd_hooks:lookup(test_hook), + Callbacks = emqx_hooks:lookup(test_hook), + ok = emqx:unhook(test_hook, fun ?MODULE:hook_fun1/1), + ct:print("Callbacks: ~p~n", [emqx_hooks:lookup(test_hook)]), + ok = emqx:unhook(test_hook, {tag, fun ?MODULE:hook_fun2/1}), + {error, not_found} = emqx:unhook(test_hook1, {tag, fun ?MODULE:hook_fun2/1}), + [] = emqx_hooks:lookup(test_hook), - ok = emqttd:hook(emqttd_hook, fun ?MODULE:hook_fun1/1, [], 9), - ok = emqttd:hook(emqttd_hook, {"tag", fun ?MODULE:hook_fun2/1}, [], 8), + ok = emqx:hook(emqx_hook, fun ?MODULE:hook_fun1/1, [], 9), + ok = emqx:hook(emqx_hook, {"tag", fun ?MODULE:hook_fun2/1}, [], 8), Callbacks2 = [{callback, "tag", fun ?MODULE:hook_fun2/1, [], 8}, {callback, undefined, fun ?MODULE:hook_fun1/1, [], 9}], - Callbacks2 = emqttd_hooks:lookup(emqttd_hook), - ok = emqttd:unhook(emqttd_hook, fun ?MODULE:hook_fun1/1), - ok = emqttd:unhook(emqttd_hook, {"tag", fun ?MODULE:hook_fun2/1}), - [] = emqttd_hooks:lookup(emqttd_hook). + Callbacks2 = emqx_hooks:lookup(emqx_hook), + ok = emqx:unhook(emqx_hook, fun ?MODULE:hook_fun1/1), + ok = emqx:unhook(emqx_hook, {"tag", fun ?MODULE:hook_fun2/1}), + [] = emqx_hooks:lookup(emqx_hook). run_hooks(_) -> - ok = emqttd:hook(foldl_hook, fun ?MODULE:hook_fun3/4, [init]), - ok = emqttd:hook(foldl_hook, {tag, fun ?MODULE:hook_fun3/4}, [init]), - ok = emqttd:hook(foldl_hook, fun ?MODULE:hook_fun4/4, [init]), - ok = emqttd:hook(foldl_hook, fun ?MODULE:hook_fun5/4, [init]), - {stop, [r3, r2]} = emqttd:run_hooks(foldl_hook, [arg1, arg2], []), - {ok, []} = emqttd:run_hooks(unknown_hook, [], []), + ok = emqx:hook(foldl_hook, fun ?MODULE:hook_fun3/4, [init]), + ok = emqx:hook(foldl_hook, {tag, fun ?MODULE:hook_fun3/4}, [init]), + ok = emqx:hook(foldl_hook, fun ?MODULE:hook_fun4/4, [init]), + ok = emqx:hook(foldl_hook, fun ?MODULE:hook_fun5/4, [init]), + {stop, [r3, r2]} = emqx:run_hooks(foldl_hook, [arg1, arg2], []), + {ok, []} = emqx:run_hooks(unknown_hook, [], []), - ok = emqttd:hook(foreach_hook, fun ?MODULE:hook_fun6/2, [initArg]), - ok = emqttd:hook(foreach_hook, {tag, fun ?MODULE:hook_fun6/2}, [initArg]), - ok = emqttd:hook(foreach_hook, fun ?MODULE:hook_fun7/2, [initArg]), - ok = emqttd:hook(foreach_hook, fun ?MODULE:hook_fun8/2, [initArg]), - stop = emqttd:run_hooks(foreach_hook, [arg]). + ok = emqx:hook(foreach_hook, fun ?MODULE:hook_fun6/2, [initArg]), + ok = emqx:hook(foreach_hook, {tag, fun ?MODULE:hook_fun6/2}, [initArg]), + ok = emqx:hook(foreach_hook, fun ?MODULE:hook_fun7/2, [initArg]), + ok = emqx:hook(foreach_hook, fun ?MODULE:hook_fun8/2, [initArg]), + stop = emqx:run_hooks(foreach_hook, [arg]). hook_fun1([]) -> ok. hook_fun2([]) -> {ok, []}. @@ -440,7 +444,7 @@ request_status(_) -> false -> not_running; {value, _Val} -> running end, - Status = iolist_to_binary(io_lib:format("Node ~s is ~s~nemqttd is ~s", + Status = iolist_to_binary(io_lib:format("Node ~s is ~s~nemqx is ~s", [node(), InternalStatus, AppStatus])), Url = "http://127.0.0.1:8080/status", {ok, {{"HTTP/1.1", 200, "OK"}, _, Return}} = @@ -462,7 +466,7 @@ request_publish(_) -> UnSubParams = "{\"topic\" : \"a\/b\/c\", \"client_id\" :\"random\"}", ?assert(connect_emqttd_pubsub_(post, "api/v2/mqtt/unsubscribe", UnSubParams, auth_header_("", ""))). -connect_emqttd_pubsub_(Method, Api, Params, Auth) -> +connect_emqx_publish_(Method, Api, Params, Auth) -> Url = "http://127.0.0.1:8080/" ++ Api, case httpc:request(Method, {Url, [Auth], ?CONTENT_TYPE, Params}, [], []) of {error, socket_closed_remotely} -> @@ -479,33 +483,34 @@ auth_header_(User, Pass) -> Encoded = base64:encode_to_string(lists:append([User,":",Pass])), {"Authorization","Basic " ++ Encoded}. +%%TODO: ... websocket_test(_) -> Conn = esockd_connection:new(esockd_transport, nil, []), Req = mochiweb_request:new(Conn, 'GET', "/mqtt", {1, 1}, mochiweb_headers:make([{"Sec-WebSocket-Key","Xn3fdKyc3qEXPuj2A3O+ZA=="}])), - ct:log("Req:~p", [Req]), - emqttd_http:handle_request(Req). + ct:log("Req:~p", [Req]). + %%emqx_http:handle_request(Req). set_alarms(_) -> AlarmTest = #mqtt_alarm{id = <<"1">>, severity = error, title="alarm title", summary="alarm summary"}, - emqttd_alarm:set_alarm(AlarmTest), - Alarms = emqttd_alarm:get_alarms(), + emqx_alarm:set_alarm(AlarmTest), + Alarms = emqx_alarm:get_alarms(), ?assertEqual(1, length(Alarms)), - emqttd_alarm:clear_alarm(<<"1">>), - [] = emqttd_alarm:get_alarms(). + emqx_alarm:clear_alarm(<<"1">>), + [] = emqx_alarm:get_alarms(). %%-------------------------------------------------------------------- %% Cli group %%-------------------------------------------------------------------- ctl_register_cmd(_) -> - emqttd_ctl:register_cmd(test_cmd, {?MODULE, test_cmd}), + emqx_ctl:register_cmd(test_cmd, {?MODULE, test_cmd}), erlang:yield(), timer:sleep(5), - [{?MODULE, test_cmd}] = emqttd_ctl:lookup(test_cmd), - emqttd_ctl:run(["test_cmd", "arg1", "arg2"]), - emqttd_ctl:unregister_cmd(test_cmd). + [{?MODULE, test_cmd}] = emqx_ctl:lookup(test_cmd), + emqx_ctl:run(["test_cmd", "arg1", "arg2"]), + emqx_ctl:unregister_cmd(test_cmd). test_cmd(["arg1", "arg2"]) -> ct:print("test_cmd is called"); @@ -514,55 +519,55 @@ test_cmd([]) -> io:format("test command"). cli_status(_) -> - emqttd_cli:status([]). + emqx_cli:status([]). cli_broker(_) -> - emqttd_cli:broker([]), - emqttd_cli:broker(["stats"]), - emqttd_cli:broker(["metrics"]), - emqttd_cli:broker(["pubsub"]). + emqx_cli:broker([]), + emqx_cli:broker(["stats"]), + emqx_cli:broker(["metrics"]), + emqx_cli:broker(["pubsub"]). cli_clients(_) -> - emqttd_cli:clients(["list"]), - emqttd_cli:clients(["show", "clientId"]), - emqttd_cli:clients(["kick", "clientId"]). + emqx_cli:clients(["list"]), + emqx_cli:clients(["show", "clientId"]), + emqx_cli:clients(["kick", "clientId"]). cli_sessions(_) -> - emqttd_cli:sessions(["list"]), - emqttd_cli:sessions(["list", "persistent"]), - emqttd_cli:sessions(["list", "transient"]), - emqttd_cli:sessions(["show", "clientId"]). + emqx_cli:sessions(["list"]), + emqx_cli:sessions(["list", "persistent"]), + emqx_cli:sessions(["list", "transient"]), + emqx_cli:sessions(["show", "clientId"]). cli_routes(_) -> - emqttd:subscribe(<<"topic/route">>), - emqttd_cli:routes(["list"]), - emqttd_cli:routes(["show", "topic/route"]), - emqttd:unsubscribe(<<"topic/route">>). + emqx:subscribe(<<"topic/route">>), + emqx_cli:routes(["list"]), + emqx_cli:routes(["show", "topic/route"]), + emqx:unsubscribe(<<"topic/route">>). cli_topics(_) -> - emqttd:subscribe(<<"topic">>), - emqttd_cli:topics(["list"]), - emqttd_cli:topics(["show", "topic"]), - emqttd:unsubscribe(<<"topic">>). + emqx:subscribe(<<"topic">>), + emqx_cli:topics(["list"]), + emqx_cli:topics(["show", "topic"]), + emqx:unsubscribe(<<"topic">>). cli_subscriptions(_) -> - emqttd_cli:subscriptions(["list"]), - emqttd_cli:subscriptions(["show", "clientId"]), - emqttd_cli:subscriptions(["add", "clientId", "topic", "2"]), - emqttd_cli:subscriptions(["del", "clientId", "topic"]). + emqx_cli:subscriptions(["list"]), + emqx_cli:subscriptions(["show", "clientId"]), + emqx_cli:subscriptions(["add", "clientId", "topic", "2"]), + emqx_cli:subscriptions(["del", "clientId", "topic"]). cli_plugins(_) -> - emqttd_cli:plugins(["list"]), - emqttd_cli:plugins(["load", "emqttd_plugin_template"]), - emqttd_cli:plugins(["unload", "emqttd_plugin_template"]). + emqx_cli:plugins(["list"]), + emqx_cli:plugins(["load", "emqx_plugin_template"]), + emqx_cli:plugins(["unload", "emqx_plugin_template"]). cli_bridges(_) -> - emqttd_cli:bridges(["list"]), - emqttd_cli:bridges(["start", "a@127.0.0.1", "topic"]), - emqttd_cli:bridges(["stop", "a@127.0.0.1", "topic"]). + emqx_cli:bridges(["list"]), + emqx_cli:bridges(["start", "a@127.0.0.1", "topic"]), + emqx_cli:bridges(["stop", "a@127.0.0.1", "topic"]). cli_listeners(_) -> - emqttd_cli:listeners([]). + emqx_cli:listeners([]). conflict_listeners(_) -> F = @@ -595,8 +600,8 @@ conflict_listeners(_) -> emqttc:disconnect(C2). cli_vm(_) -> - emqttd_cli:vm([]), - emqttd_cli:vm(["ports"]). + emqx_cli:vm([]), + emqx_cli:vm(["ports"]). cleanSession_validate(_) -> {ok, C1} = emqttc:start_link([{host, "localhost"}, @@ -605,6 +610,7 @@ cleanSession_validate(_) -> {clean_sess, false}]), timer:sleep(10), emqttc:subscribe(C1, <<"topic">>, qos0), + ok = emqx_cli:sessions(["list", "persistent"]), emqttc:disconnect(C1), {ok, Pub} = emqttc:start_link([{host, "localhost"}, {port, 1883}, @@ -617,15 +623,136 @@ cleanSession_validate(_) -> {client_id, <<"c1">>}, {clean_sess, false}]), timer:sleep(100), - Metrics = emqttd_metrics:all(), + Metrics = emqx_metrics:all(), + ct:log("Metrics:~p~n", [Metrics]), ?assertEqual(1, proplists:get_value('messages/qos0/sent', Metrics)), ?assertEqual(1, proplists:get_value('messages/qos0/received', Metrics)), emqttc:disconnect(Pub), emqttc:disconnect(C11). +cleanSession_validate1(_) -> + {ok, C1} = emqttc:start_link([{host, "localhost"}, + {port, 1883}, + {client_id, <<"c1">>}, + {clean_sess, true}]), + timer:sleep(10), + emqttc:subscribe(C1, <<"topic">>, qos1), + ok = emqx_cli:sessions(["list", "transient"]), + emqttc:disconnect(C1), + {ok, Pub} = emqttc:start_link([{host, "localhost"}, + {port, 1883}, + {client_id, <<"pub">>}]), + + emqttc:publish(Pub, <<"topic">>, <<"m1">>, [{qos, 1}]), + timer:sleep(10), + {ok, C11} = emqttc:start_link([{host, "localhost"}, + {port, 1883}, + {client_id, <<"c1">>}, + {clean_sess, false}]), + timer:sleep(100), + Metrics = emqx_metrics:all(), + ?assertEqual(0, proplists:get_value('messages/qos1/sent', Metrics)), + ?assertEqual(1, proplists:get_value('messages/qos1/received', Metrics)), + emqttc:disconnect(Pub), + emqttc:disconnect(C11). + get_api_lists(_Config) -> lists:foreach(fun request/1, ?GET_API). +request_publish(_) -> + emqttc:start_link([{host, "localhost"}, + {port, 1883}, + {client_id, <<"random">>}, + {clean_sess, false}]), + SubParams = "{\"qos\":1, \"topic\" : \"a\/b\/c\", \"client_id\" :\"random\"}", + ?assert(connect_emqx_pubsub_(post, "api/v2/mqtt/subscribe", SubParams, auth_header_("", ""))), + ok = emqx:subscribe(<<"a/b/c">>, self(), [{qos, 1}]), + Params = "{\"qos\":1, \"retain\":false, \"topic\" : \"a\/b\/c\", \"messages\" :\"hello\"}", + ?assert(connect_emqx_pubsub_(post, "api/v2/mqtt/publish", Params, auth_header_("", ""))), + ?assert(receive {dispatch, <<"a/b/c">>, _} -> true after 2 -> false end), + + UnSubParams = "{\"topic\" : \"a\/b\/c\", \"client_id\" :\"random\"}", + ?assert(connect_emqx_pubsub_(post, "api/v2/mqtt/unsubscribe", UnSubParams, auth_header_("", ""))). + +connect_emqx_pubsub_(Method, Api, Params, Auth) -> + Url = "http://127.0.0.1:8080/" ++ Api, + case httpc:request(Method, {Url, [Auth], ?CONTENT_TYPE, Params}, [], []) of + {error, socket_closed_remotely} -> + false; + {ok, {{"HTTP/1.1", 200, "OK"}, _, _Return} } -> + true; + {ok, {{"HTTP/1.1", 400, _}, _, []}} -> + false; + {ok, {{"HTTP/1.1", 404, _}, _, []}} -> + false + end. + +request(Path) -> + http_get(get, Path). + +http_get(Method, Path) -> + req(Method, Path, []). + +http_put(Method, Path, Params) -> + req(Method, Path, format_for_upload(Params)). + +http_post(Method, Path, Params) -> + req(Method, Path, format_for_upload(Params)). + +req(Method, Path, Body) -> + Url = ?URL ++ Path, + Headers = auth_header_("", ""), + case httpc:request(Method, {Url, [Headers]}, [], []) of + {error, R} -> + ct:log("R:~p~n", [R]), + false; + {ok, {{"HTTP/1.1", 200, "OK"}, _, _Return} } -> + true; + {ok, {{"HTTP/1.1", 400, _}, _, []}} -> + false; + {ok, {{"HTTP/1.1", 404, _}, _, []}} -> + false + end. + +format_for_upload(none) -> + <<"">>; +format_for_upload(List) -> + iolist_to_binary(mochijson2:encode(List)). + +ensure_ok(ok) -> ok; +ensure_ok({error, {already_started, _}}) -> ok. + +host() -> ct:print("!!!! Node: ~p~n", [node()]), [_, Host] = string:tokens(atom_to_list(node()), "@"), Host. + +wait_running(Node) -> + wait_running(Node, 30000). + +wait_running(Node, Timeout) when Timeout < 0 -> + throw({wait_timeout, Node}); + +wait_running(Node, Timeout) -> + case rpc:call(Node, emqx, is_running, [Node]) of + true -> ok; + false -> timer:sleep(100), + wait_running(Node, Timeout - 100) + end. + +slave(emqx, Node) -> + {ok, Slave} = slave:start(host(), Node, "-config ../../test/emqx_SUITE_data/slave.config " ++ ensure_slave()), + ct:log("Slave:~p~n", [Slave]), + rpc:call(Slave, application, ensure_all_started, [emqx]), + Slave; + +slave(node, Node) -> + {ok, N} = slave:start(host(), Node, ensure_slave()), + N. + +ensure_slave() -> + EbinDir = local_path(["ebin"]), + DepsDir = local_path(["deps", "*", "ebin"]), + RpcDir = local_path(["deps", "gen_rpc", "_build", "dev", "lib", "*", "ebin"]), + "-pa " ++ EbinDir ++ " -pa " ++ DepsDir ++ " -pa " ++ RpcDir. + change_opts(SslType) -> {ok, Listeners} = application:get_env(?APP, listeners), NewListeners = @@ -658,8 +785,8 @@ change_opts(SslType) -> application:set_env(?APP, listeners, NewListeners). generate_config() -> - Schema = cuttlefish_schema:files([local_path(["priv", "emq.schema"])]), - Conf = conf_parse:file([local_path(["etc", "emq.conf"])]), + Schema = cuttlefish_schema:files([local_path(["priv", "emqx.schema"])]), + Conf = conf_parse:file([local_path(["etc", "emqx.conf"])]), cuttlefish_generator:map(Schema, Conf). get_base_dir(Module) -> @@ -710,3 +837,4 @@ format_for_upload(none) -> <<"">>; format_for_upload(List) -> iolist_to_binary(mochijson2:encode(List)). + diff --git a/test/emqx_SUITE_data/acl.conf b/test/emqx_SUITE_data/acl.conf new file mode 100644 index 000000000..3cb3b8c52 --- /dev/null +++ b/test/emqx_SUITE_data/acl.conf @@ -0,0 +1,29 @@ +%%-------------------------------------------------------------------- +%% +%% [ACL](https://github.com/emqtt/emqttd/wiki/ACL) +%% +%% -type who() :: all | binary() | +%% {ipaddr, esockd_access:cidr()} | +%% {client, binary()} | +%% {user, binary()}. +%% +%% -type access() :: subscribe | publish | pubsub. +%% +%% -type topic() :: binary(). +%% +%% -type rule() :: {allow, all} | +%% {allow, who(), access(), list(topic())} | +%% {deny, all} | +%% {deny, who(), access(), list(topic())}. +%% +%%-------------------------------------------------------------------- + +{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. + +{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}. + +{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. + +{allow, all}. + + diff --git a/test/emqx_SUITE_data/slave.config b/test/emqx_SUITE_data/slave.config new file mode 100644 index 000000000..dd3a5f32b --- /dev/null +++ b/test/emqx_SUITE_data/slave.config @@ -0,0 +1,60 @@ +[{emqx, + [{plugins_loaded_file,"loaded_plugins"}, + {plugins_etc_dir,"plugins/"}, + {broker_sys_interval,60}, + {cache_acl,true}, + {allow_anonymous,true}, + {license_file,"../../etc/emqx.lic"}, + {protocol,[{max_clientid_len,1024},{max_packet_size,65536}]}, + {client, + [{max_publish_rate,5},{idle_timeout,30000},{enable_stats,60000}]}, + {session, + [{max_subscriptions,0}, + {upgrade_qos,false}, + {max_inflight,32}, + {retry_interval,20000}, + {max_awaiting_rel,100}, + {await_rel_timeout,20000}, + {enable_stats,60000}, + {expiry_interval,7200000}]}, + {mqueue, + [{priority,[]}, + {type,simple}, + {max_length,infinity}, + {low_watermark,0.2}, + {high_watermark,0.6}, + {store_qos0,true}]}, + {pubsub,[{pool_size,8},{by_clientid,true},{async,true}]}, + {bridge,[{max_queue_len,10000},{ping_down_interval,1}]}, + {listeners, []}, + {sysmon, + [{long_gc,false}, + {long_schedule,240}, + {large_heap,8388608}, + {busy_port,false}, + {busy_dist_port,true}]}]}, + {sasl,[{sasl_error_logger,false}]}, + {lager, + [{error_logger_hwm,1000}, + {error_logger_redirect,true}, + {log_dir,"{{ platform_log_dir }}"}, + {handlers, + [{lager_console_backend,error}, + {lager_file_backend, + [{file,"{{ platform_log_dir }}/error.log"}, + {level,error}, + {size,10485760}, + {date,"$D0"}, + {count,5}]}, + {lager_syslog_backend,["emq",local0,error]}]}, + {crash_log,"{{ platform_log_dir }}/crash.log"}]}, + {gen_rpc, + [{socket_keepalive_count,2}, + {socket_keepalive_interval,5}, + {socket_keepalive_idle,5}, + {call_receive_timeout,15000}, + {authentication_timeout,5000}, + {send_timeout,5000}, + {connect_timeout,5000}, + {tcp_client_port,5369}, + {tcp_server_port,7369}]}]. diff --git a/test/emqttd_access_SUITE.erl b/test/emqx_access_SUITE.erl similarity index 85% rename from test/emqttd_access_SUITE.erl rename to test/emqx_access_SUITE.erl index 762ae6f40..d3eef923e 100644 --- a/test/emqttd_access_SUITE.erl +++ b/test/emqx_access_SUITE.erl @@ -14,15 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_access_SUITE). +-module(emqx_access_SUITE). -compile(export_all). --include("emqttd.hrl"). +-include("emqx.hrl"). --define(AC, emqttd_access_control). +-define(AC, emqx_access_control). --import(emqttd_access_rule, [compile/1, match/3]). +-import(emqx_access_rule, [compile/1, match/3]). all() -> [{group, access_control}, @@ -39,7 +39,7 @@ groups() -> match_rule]}]. init_per_group(access_control, Config) -> - application:load(emqttd), + application:load(emqx), prepare_config(), Config; @@ -59,8 +59,8 @@ prepare_config() -> Config = [{auth, anonymous, []}, {acl, internal, [{config, "access_SUITE_acl.conf"}, {nomatch, allow}]}], - write_config("access_SUITE_emqttd.conf", Config), - application:set_env(emqttd, conf, "access_SUITE_emqttd.conf"). + write_config("access_SUITE_emqx.conf", Config), + application:set_env(emqx, conf, "access_SUITE_emqx.conf"). write_config(Filename, Terms) -> file:write_file(Filename, [io_lib:format("~tp.~n", [Term]) || Term <- Terms]). @@ -87,31 +87,31 @@ end_per_testcase(_TestCase, _Config) -> ok. %%-------------------------------------------------------------------- -%% emqttd_access_control +%% emqx_access_control %%-------------------------------------------------------------------- reload_acl(_) -> - [] = ?AC:reload_acl(). + [ok] = ?AC:reload_acl(). register_mod(_) -> - ok = ?AC:register_mod(acl, emqttd_acl_test_mod, []), - {error, already_existed} = ?AC:register_mod(acl, emqttd_acl_test_mod, []), - [{emqttd_acl_test_mod, _, 0}] = ?AC:lookup_mods(acl), - ok = ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]), - ok = ?AC:register_mod(auth, emqttd_auth_dashboard, [], 99), - [{emqttd_auth_dashboard, _, 99}, - {emqttd_auth_anonymous_test_mod, _, 0}] = ?AC:lookup_mods(auth). + ok = ?AC:register_mod(acl, emqx_acl_test_mod, []), + {error, already_existed} = ?AC:register_mod(acl, emqx_acl_test_mod, []), + {emqx_acl_test_mod, _, 0} = hd(?AC:lookup_mods(acl)), + ok = ?AC:register_mod(auth, emqx_auth_anonymous_test_mod,[]), + ok = ?AC:register_mod(auth, emqx_auth_dashboard, [], 99), + [{emqx_auth_dashboard, _, 99}, + {emqx_auth_anonymous_test_mod, _, 0}] = ?AC:lookup_mods(auth). unregister_mod(_) -> - ok = ?AC:register_mod(acl, emqttd_acl_test_mod, []), - [{emqttd_acl_test_mod, _, 0}] = ?AC:lookup_mods(acl), - ok = ?AC:unregister_mod(acl, emqttd_acl_test_mod), + ok = ?AC:register_mod(acl, emqx_acl_test_mod, []), + {emqx_acl_test_mod, _, 0} = hd(?AC:lookup_mods(acl)), + ok = ?AC:unregister_mod(acl, emqx_acl_test_mod), timer:sleep(5), - [] = ?AC:lookup_mods(acl), - ok = ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]), - [{emqttd_auth_anonymous_test_mod, _, 0}] = ?AC:lookup_mods(auth), + {emqx_acl_internal, _, 0}= hd(?AC:lookup_mods(acl)), + ok = ?AC:register_mod(auth, emqx_auth_anonymous_test_mod,[]), + [{emqx_auth_anonymous_test_mod, _, 0}] = ?AC:lookup_mods(auth), - ok = ?AC:unregister_mod(auth, emqttd_auth_anonymous_test_mod), + ok = ?AC:unregister_mod(auth, emqx_auth_anonymous_test_mod), timer:sleep(5), [] = ?AC:lookup_mods(auth). @@ -126,7 +126,7 @@ check_acl(_) -> allow = ?AC:check_acl(User2, subscribe, <<"a/b/c">>). %%-------------------------------------------------------------------- -%% emqttd_access_rule +%% emqx_access_rule %%-------------------------------------------------------------------- compile_rule(_) -> diff --git a/test/emqx_access_SUITE_data/acl.conf b/test/emqx_access_SUITE_data/acl.conf new file mode 100644 index 000000000..03416f002 --- /dev/null +++ b/test/emqx_access_SUITE_data/acl.conf @@ -0,0 +1,16 @@ +{allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}. + +{allow, {user, "testuser"}, subscribe, ["a/b/c", "d/e/f/#"]}. + +{allow, {user, "admin"}, pubsub, ["a/b/c", "d/e/f/#"]}. + +{allow, {client, "testClient"}, subscribe, ["testTopics/testClient"]}. + +{allow, all, subscribe, ["clients/%c"]}. + +{allow, all, pubsub, ["users/%u/#"]}. + +{deny, all, subscribe, ["$SYS/#", "#"]}. + +{deny, all}. + diff --git a/test/emqttd_acl_test_mod.erl b/test/emqx_acl_test_mod.erl similarity index 97% rename from test/emqttd_acl_test_mod.erl rename to test/emqx_acl_test_mod.erl index 08f1f9c94..4b9c14b14 100644 --- a/test/emqttd_acl_test_mod.erl +++ b/test/emqx_acl_test_mod.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_acl_test_mod). +-module(emqx_acl_test_mod). %% ACL callbacks -export([init/1, check_acl/2, reload_acl/1, description/0]). @@ -30,3 +30,4 @@ reload_acl(_State) -> description() -> "Test ACL Mod". + diff --git a/test/emqttd_auth_anonymous_test_mod.erl b/test/emqx_auth_anonymous_test_mod.erl similarity index 92% rename from test/emqttd_auth_anonymous_test_mod.erl rename to test/emqx_auth_anonymous_test_mod.erl index be6a14bf8..9fb52f419 100644 --- a/test/emqttd_auth_anonymous_test_mod.erl +++ b/test/emqx_auth_anonymous_test_mod.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_auth_anonymous_test_mod). +-module(emqx_auth_anonymous_test_mod). %% ACL callbacks -export([init/1, check/3, description/0]). @@ -26,4 +26,4 @@ check(_Client, _Password, _Opts) -> allow. description() -> - "Test emqttd_auth_anonymous Mod". + "Test emqx_auth_anonymous Mod". diff --git a/test/emqttd_auth_dashboard.erl b/test/emqx_auth_dashboard.erl similarity index 92% rename from test/emqttd_auth_dashboard.erl rename to test/emqx_auth_dashboard.erl index 49f54c377..eae612dd3 100644 --- a/test/emqttd_auth_dashboard.erl +++ b/test/emqx_auth_dashboard.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_auth_dashboard). +-module(emqx_auth_dashboard). %% Auth callbacks -export([init/1, check/3, description/0]). @@ -26,4 +26,5 @@ check(_Client, _Password, _Opts) -> allow. description() -> - "Test emqttd_auth_dashboard Mod". + "Test Auth Mod". + diff --git a/test/emqttd_config_SUITE.erl b/test/emqx_config_SUITE.erl similarity index 100% rename from test/emqttd_config_SUITE.erl rename to test/emqx_config_SUITE.erl diff --git a/test/emqx_inflight_SUITE.erl b/test/emqx_inflight_SUITE.erl new file mode 100644 index 000000000..c391d08ea --- /dev/null +++ b/test/emqx_inflight_SUITE.erl @@ -0,0 +1,63 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_inflight_SUITE). + +-author("Feng Lee "). + +-include_lib("eunit/include/eunit.hrl"). + +%% CT +-compile(export_all). + +all() -> [t_contain, t_lookup, t_insert, t_update, t_delete, t_window, + t_is_full, t_is_empty]. + +t_contain(_) -> + Inflight = emqx_inflight:new(0), + ?assertNot(Inflight:contain(k)), + Inflight1 = Inflight:insert(k, v), + ?assert(Inflight1:contain(k)). + +t_lookup(_) -> + Inflight = (emqx_inflight:new(0)):insert(k, v), + ?assertEqual(v, Inflight:lookup(k)). + +t_insert(_) -> + Inflight = ((emqx_inflight:new(0)):insert(k1, v1)):insert(k2, v2), + ?assertEqual(v2, Inflight:lookup(k2)). + +t_update(_) -> + Inflight = ((emqx_inflight:new(0)):insert(k, v1)):update(k, v2), + ?assertEqual(v2, Inflight:lookup(k)). + +t_delete(_) -> + Inflight = ((emqx_inflight:new(0)):insert(k, v1)):delete(k), + ?assert(Inflight:is_empty()). + +t_window(_) -> + ?assertEqual([], (emqx_inflight:new(10)):window()), + Inflight = ((emqx_inflight:new(0)):insert(1, 1)):insert(2, 2), + ?assertEqual([1, 2], Inflight:window()). + +t_is_full(_) -> + Inflight = ((emqx_inflight:new(1)):insert(k, v1)), + ?assert(Inflight:is_full()). + +t_is_empty(_) -> + Inflight = ((emqx_inflight:new(1)):insert(k, v1)), + ?assertNot(Inflight:is_empty()). + diff --git a/test/emqttd_lib_SUITE.erl b/test/emqx_lib_SUITE.erl similarity index 71% rename from test/emqttd_lib_SUITE.erl rename to test/emqx_lib_SUITE.erl index a808fbcc8..e39b8178d 100644 --- a/test/emqttd_lib_SUITE.erl +++ b/test/emqx_lib_SUITE.erl @@ -14,7 +14,9 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_lib_SUITE). +-module(emqx_lib_SUITE). + +-author("Feng Lee "). -include_lib("eunit/include/eunit.hrl"). @@ -28,13 +30,13 @@ {nodelay, true} ]). --define(PQ, priority_queue). +-define(PQ, emqx_pqueue). --define(BASE62, emqttd_base62). +-define(BASE62, emqx_base62). all() -> [{group, guid}, {group, opts}, {group, ?PQ}, {group, time}, - {group, base62}]. + {group, node}, {group, base62}]. groups() -> [{guid, [], [guid_gen, guid_hexstr, guid_base62]}, @@ -42,40 +44,41 @@ groups() -> {?PQ, [], [priority_queue_plen, priority_queue_out2]}, {time, [], [time_now_to_]}, + {node, [], [node_is_aliving, node_parse_name]}, {base62, [], [base62_encode]}]. %%-------------------------------------------------------------------- -%% emqttd_guid +%% emqx_guid %%-------------------------------------------------------------------- guid_gen(_) -> - Guid1 = emqttd_guid:gen(), - Guid2 = emqttd_guid:gen(), + Guid1 = emqx_guid:gen(), + Guid2 = emqx_guid:gen(), <<_:128>> = Guid1, true = (Guid2 >= Guid1), - {Ts1, _, 0} = emqttd_guid:new(), - Ts2 = emqttd_guid:timestamp(emqttd_guid:gen()), + {Ts1, _, 0} = emqx_guid:new(), + Ts2 = emqx_guid:timestamp(emqx_guid:gen()), true = Ts2 > Ts1. guid_hexstr(_) -> - Guid = emqttd_guid:gen(), - ?assertEqual(Guid, emqttd_guid:from_hexstr(emqttd_guid:to_hexstr(Guid))). + Guid = emqx_guid:gen(), + ?assertEqual(Guid, emqx_guid:from_hexstr(emqx_guid:to_hexstr(Guid))). guid_base62(_) -> - Guid = emqttd_guid:gen(), - ?assertEqual(Guid, emqttd_guid:from_base62(emqttd_guid:to_base62(Guid))). + Guid = emqx_guid:gen(), + ?assertEqual(Guid, emqx_guid:from_base62(emqx_guid:to_base62(Guid))). %%-------------------------------------------------------------------- -%% emqttd_opts +%% emqx_opts %%-------------------------------------------------------------------- opts_merge(_) -> - Opts = emqttd_misc:merge_opts(?SOCKOPTS, [raw, - binary, - {backlog, 1024}, - {nodelay, false}, - {max_clients, 1024}, - {acceptors, 16}]), + Opts = emqx_misc:merge_opts(?SOCKOPTS, [raw, + binary, + {backlog, 1024}, + {nodelay, false}, + {max_clients, 1024}, + {acceptors, 16}]), 1024 = proplists:get_value(backlog, Opts), 1024 = proplists:get_value(max_clients, Opts), [binary, raw, @@ -135,13 +138,26 @@ priority_queue_out2(_) -> {empty, _Q7} = ?PQ:out(Q6). %%-------------------------------------------------------------------- -%% emqttd_time +%% emqx_time %%-------------------------------------------------------------------- time_now_to_(_) -> - emqttd_time:seed(), - emqttd_time:now_secs(), - emqttd_time:now_ms(). + emqx_time:seed(), + emqx_time:now_secs(), + emqx_time:now_ms(). + +%%-------------------------------------------------------------------- +%% emqx_node +%%-------------------------------------------------------------------- + +node_is_aliving(_) -> + io:format("Node: ~p~n", [node()]), + true = emqx_node:is_aliving(node()), + false = emqx_node:is_aliving('x@127.0.0.1'). + +node_parse_name(_) -> + 'a@127.0.0.1' = emqx_node:parse_name("a@127.0.0.1"), + 'b@127.0.0.1' = emqx_node:parse_name("b"). %%-------------------------------------------------------------------- %% base62 encode decode @@ -152,8 +168,8 @@ base62_encode(_) -> 100 = ?BASE62:decode(?BASE62:encode(100)), 9999 = ?BASE62:decode(?BASE62:encode(9999)), 65535 = ?BASE62:decode(?BASE62:encode(65535)), - <> = emqttd_guid:gen(), - <> = emqttd_guid:gen(), + <> = emqx_guid:gen(), + <> = emqx_guid:gen(), X = ?BASE62:decode(?BASE62:encode(X)), Y = ?BASE62:decode(?BASE62:encode(Y)). diff --git a/test/emqttd_mock_client.erl b/test/emqx_mock_client.erl similarity index 51% rename from test/emqttd_mock_client.erl rename to test/emqx_mock_client.erl index f4d26fa30..2b18c348f 100644 --- a/test/emqttd_mock_client.erl +++ b/test/emqx_mock_client.erl @@ -1,27 +1,30 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io) +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- --module(emqttd_mock_client). +-module(emqx_mock_client). -behaviour(gen_server). -%% ------------------------------------------------------------------ -%% API Function Exports -%% ------------------------------------------------------------------ - -export([start_link/1, start_session/1, stop/1]). -%% ------------------------------------------------------------------ -%% gen_server Function Exports -%% ------------------------------------------------------------------ - -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {clientid, session}). -%% ------------------------------------------------------------------ -%% API Function Definitions -%% ------------------------------------------------------------------ - start_link(ClientId) -> gen_server:start_link(?MODULE, [ClientId], []). @@ -31,15 +34,11 @@ start_session(CPid) -> stop(CPid) -> gen_server:call(CPid, stop). -%% ------------------------------------------------------------------ -%% gen_server Function Definitions -%% ------------------------------------------------------------------ - init([ClientId]) -> {ok, #state{clientid = ClientId}}. handle_call(start_session, _From, State = #state{clientid = ClientId}) -> - {ok, SessPid, _} = emqttd_sm:start_session(true, {ClientId, undefined}), + {ok, SessPid, _} = emqx_sm:start_session(true, {ClientId, undefined}), {reply, {ok, SessPid}, State#state{session = SessPid}}; handle_call(stop, _From, State) -> @@ -60,4 +59,3 @@ terminate(_Reason, _State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. - diff --git a/test/emqttd_mod_SUITE.erl b/test/emqx_mod_SUITE.erl similarity index 100% rename from test/emqttd_mod_SUITE.erl rename to test/emqx_mod_SUITE.erl diff --git a/test/emqttd_mqueue_SUITE.erl b/test/emqx_mqueue_SUITE.erl similarity index 74% rename from test/emqttd_mqueue_SUITE.erl rename to test/emqx_mqueue_SUITE.erl index 93ccc9833..db4bbbc73 100644 --- a/test/emqttd_mqueue_SUITE.erl +++ b/test/emqx_mqueue_SUITE.erl @@ -14,13 +14,17 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_mqueue_SUITE). +-module(emqx_mqueue_SUITE). + +-author("Feng Lee "). -compile(export_all). --include("emqttd.hrl"). +-include("emqx.hrl"). --define(Q, emqttd_mqueue). +-include_lib("eunit/include/eunit.hrl"). + +-define(Q, emqx_mqueue). all() -> [t_in, t_in_qos0, t_out, t_simple_mqueue, t_priority_mqueue, t_priority_mqueue2, t_infinity_priority_mqueue, @@ -30,24 +34,24 @@ t_in(_) -> Opts = [{max_length, 5}, {store_qos0, true}], Q = ?Q:new(<<"testQ">>, Opts, alarm_fun()), - true = ?Q:is_empty(Q), + ?assert(?Q:is_empty(Q)), Q1 = ?Q:in(#mqtt_message{}, Q), - 1 = ?Q:len(Q1), + ?assertEqual(1, ?Q:len(Q1)), Q2 = ?Q:in(#mqtt_message{qos = 1}, Q1), - 2 = ?Q:len(Q2), + ?assertEqual(2, ?Q:len(Q2)), Q3 = ?Q:in(#mqtt_message{qos = 2}, Q2), Q4 = ?Q:in(#mqtt_message{}, Q3), Q5 = ?Q:in(#mqtt_message{}, Q4), - 5 = ?Q:len(Q5). + ?assertEqual(5, ?Q:len(Q5)). t_in_qos0(_) -> Opts = [{max_length, 5}, {store_qos0, false}], Q = ?Q:new(<<"testQ">>, Opts, alarm_fun()), Q1 = ?Q:in(#mqtt_message{}, Q), - true = ?Q:is_empty(Q1), + ?assert(?Q:is_empty(Q1)), Q2 = ?Q:in(#mqtt_message{qos = 0}, Q1), - true = ?Q:is_empty(Q2). + ?assert(?Q:is_empty(Q2)). t_out(_) -> Opts = [{max_length, 5}, @@ -56,8 +60,8 @@ t_out(_) -> {empty, Q} = ?Q:out(Q), Q1 = ?Q:in(#mqtt_message{}, Q), {Value, Q2} = ?Q:out(Q1), - 0 = ?Q:len(Q2), - {value, #mqtt_message{}} = Value. + ?assertEqual(0, ?Q:len(Q2)), + ?assertEqual({value, #mqtt_message{}}, Value). t_simple_mqueue(_) -> Opts = [{type, simple}, @@ -66,18 +70,18 @@ t_simple_mqueue(_) -> {high_watermark, 0.6}, {store_qos0, false}], Q = ?Q:new("simple_queue", Opts, alarm_fun()), - simple = ?Q:type(Q), - 3 = ?Q:max_len(Q), - <<"simple_queue">> = ?Q:name(Q), - true = ?Q:is_empty(Q), + ?assertEqual(simple, ?Q:type(Q)), + ?assertEqual(3, ?Q:max_len(Q)), + ?assertEqual(<<"simple_queue">>, ?Q:name(Q)), + ?assert(?Q:is_empty(Q)), Q1 = ?Q:in(#mqtt_message{qos = 1, payload = <<"1">>}, Q), Q2 = ?Q:in(#mqtt_message{qos = 1, payload = <<"2">>}, Q1), Q3 = ?Q:in(#mqtt_message{qos = 1, payload = <<"3">>}, Q2), Q4 = ?Q:in(#mqtt_message{qos = 1, payload = <<"4">>}, Q3), - 3 = ?Q:len(Q4), + ?assertEqual(3, ?Q:len(Q4)), {{value, Msg}, Q5} = ?Q:out(Q4), - <<"2">> = Msg#mqtt_message.payload, - [{len, 2}, {max_len, 3}, {dropped, 1}] = ?Q:stats(Q5). + ?assertEqual(<<"2">>, Msg#mqtt_message.payload), + ?assertEqual([{len, 2}, {max_len, 3}, {dropped, 1}], ?Q:stats(Q5)). t_infinity_simple_mqueue(_) -> Opts = [{type, simple}, @@ -86,15 +90,15 @@ t_infinity_simple_mqueue(_) -> {high_watermark, 0.6}, {store_qos0, false}], Q = ?Q:new("infinity_simple_queue", Opts, alarm_fun()), - true = ?Q:is_empty(Q), - 0 = ?Q:max_len(Q), + ?assert(?Q:is_empty(Q)), + ?assertEqual(0, ?Q:max_len(Q)), Qx = lists:foldl(fun(I, AccQ) -> ?Q:in(#mqtt_message{qos = 1, payload = iolist_to_binary([I])}, AccQ) end, Q, lists:seq(1, 255)), - 255 = ?Q:len(Qx), - [{len, 255}, {max_len, 0}, {dropped, 0}] = ?Q:stats(Qx), + ?assertEqual(255, ?Q:len(Qx)), + ?assertEqual([{len, 255}, {max_len, 0}, {dropped, 0}], ?Q:stats(Qx)), {{value, V}, _Qy} = ?Q:out(Qx), - <<1>> = V#mqtt_message.payload. + ?assertEqual(<<1>>, V#mqtt_message.payload). t_priority_mqueue(_) -> Opts = [{type, priority}, @@ -104,23 +108,23 @@ t_priority_mqueue(_) -> {high_watermark, 0.6}, {store_qos0, false}], Q = ?Q:new("priority_queue", Opts, alarm_fun()), - priority = ?Q:type(Q), - 3 = ?Q:max_len(Q), - <<"priority_queue">> = ?Q:name(Q), + ?assertEqual(priority, ?Q:type(Q)), + ?assertEqual(3, ?Q:max_len(Q)), + ?assertEqual(<<"priority_queue">>, ?Q:name(Q)), - true = ?Q:is_empty(Q), + ?assert(?Q:is_empty(Q)), Q1 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q), Q2 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t">>}, Q1), Q3 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t2">>}, Q2), - 3 = ?Q:len(Q3), + ?assertEqual(3, ?Q:len(Q3)), Q4 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q3), - 4 = ?Q:len(Q4), + ?assertEqual(4, ?Q:len(Q4)), Q5 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q4), - 5 = ?Q:len(Q5), + ?assertEqual(5, ?Q:len(Q5)), Q6 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q5), - 5 = ?Q:len(Q6), + ?assertEqual(5, ?Q:len(Q6)), {{value, Msg}, _Q7} = ?Q:out(Q6), - <<"t">> = Msg#mqtt_message.topic. + ?assertEqual(<<"t">>, Msg#mqtt_message.topic). t_infinity_priority_mqueue(_) -> Opts = [{type, priority}, @@ -128,14 +132,14 @@ t_infinity_priority_mqueue(_) -> {max_length, 0}, {store_qos0, false}], Q = ?Q:new("infinity_priority_queue", Opts, alarm_fun()), - 0 = ?Q:max_len(Q), + ?assertEqual(0, ?Q:max_len(Q)), Qx = lists:foldl(fun(I, AccQ) -> AccQ1 = ?Q:in(#mqtt_message{topic = <<"t1">>, qos = 1, payload = iolist_to_binary([I])}, AccQ), ?Q:in(#mqtt_message{topic = <<"t">>, qos = 1, payload = iolist_to_binary([I])}, AccQ1) end, Q, lists:seq(1, 255)), - 510 = ?Q:len(Qx), - [{len, 510}, {max_len, 0}, {dropped, 0}] = ?Q:stats(Qx). + ?assertEqual(510, ?Q:len(Qx)), + ?assertEqual([{len, 510}, {max_len, 0}, {dropped, 0}], ?Q:stats(Qx)). t_priority_mqueue2(_) -> Opts = [{type, priority}, @@ -144,14 +148,14 @@ t_priority_mqueue2(_) -> {high_watermark, 0.6}, {store_qos0, false}], Q = ?Q:new("priority_queue2_test", Opts, alarm_fun()), - 2 = ?Q:max_len(Q), + ?assertEqual(2, ?Q:max_len(Q)), Q1 = ?Q:in(#mqtt_message{topic = <<"x">>, qos = 1, payload = <<1>>}, Q), Q2 = ?Q:in(#mqtt_message{topic = <<"x">>, qos = 1, payload = <<2>>}, Q1), Q3 = ?Q:in(#mqtt_message{topic = <<"y">>, qos = 1, payload = <<3>>}, Q2), Q4 = ?Q:in(#mqtt_message{topic = <<"y">>, qos = 1, payload = <<4>>}, Q3), - 4 = ?Q:len(Q4), + ?assertEqual(4, ?Q:len(Q4)), {{value, _Val}, Q5} = ?Q:out(Q4), - 3 = ?Q:len(Q5). + ?assertEqual(3, ?Q:len(Q5)). alarm_fun() -> fun(_, _) -> alarm_fun() end. diff --git a/test/emqttd_net_SUITE.erl b/test/emqx_net_SUITE.erl similarity index 89% rename from test/emqttd_net_SUITE.erl rename to test/emqx_net_SUITE.erl index 78abb50c9..dd3ea0015 100644 --- a/test/emqttd_net_SUITE.erl +++ b/test/emqx_net_SUITE.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_net_SUITE). +-module(emqx_net_SUITE). %% CT -compile(export_all). @@ -28,13 +28,13 @@ groups() -> [{keepalive, [], [t_keepalive]}]. %%-------------------------------------------------------------------- t_keepalive(_) -> - {ok, KA} = emqttd_keepalive:start(fun() -> {ok, 1} end, 1, {keepalive, timeout}), + {ok, KA} = emqx_keepalive:start(fun() -> {ok, 1} end, 1, {keepalive, timeout}), [resumed, timeout] = lists:reverse(keepalive_recv(KA, [])). keepalive_recv(KA, Acc) -> receive {keepalive, timeout} -> - case emqttd_keepalive:check(KA) of + case emqx_keepalive:check(KA) of {ok, KA1} -> keepalive_recv(KA1, [resumed | Acc]); {error, timeout} -> [timeout | Acc] end diff --git a/test/emqttd_protocol_SUITE.erl b/test/emqx_protocol_SUITE.erl similarity index 78% rename from test/emqttd_protocol_SUITE.erl rename to test/emqx_protocol_SUITE.erl index 21428f0c7..4cf21b73a 100644 --- a/test/emqttd_protocol_SUITE.erl +++ b/test/emqx_protocol_SUITE.erl @@ -14,17 +14,17 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_protocol_SUITE). +-module(emqx_protocol_SUITE). -compile(export_all). --import(emqttd_serializer, [serialize/1]). +-include("emqx.hrl"). --include("emqttd.hrl"). +-include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). --include("emqttd_protocol.hrl"). +-import(emqx_serializer, [serialize/1]). all() -> [{group, parser}, @@ -73,7 +73,7 @@ groups() -> %%-------------------------------------------------------------------- parse_connect(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %% CONNECT(Q0, R0, D0, ClientId=mosqpub/10451-iMac.loca, ProtoName=MQIsdp, ProtoVsn=3, CleanSess=true, KeepAlive=60, Username=undefined, Password=undefined) V31ConnBin = <<16,37,0,6,77,81,73,115,100,112,3,2,0,60,0,23,109,111,115,113,112,117,98,47,49,48,52,53,49,45,105,77,97,99,46,108,111,99,97>>, {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT, @@ -84,7 +84,7 @@ parse_connect(_) -> proto_name = <<"MQIsdp">>, client_id = <<"mosqpub/10451-iMac.loca">>, clean_sess = true, - keep_alive = 60}}, <<>>} = emqttd_parser:parse(V31ConnBin, Parser), + keep_alive = 60}}, <<>>} = emqx_parser:parse(V31ConnBin, Parser), %% CONNECT(Q0, R0, D0, ClientId=mosqpub/10451-iMac.loca, ProtoName=MQTT, ProtoVsn=4, CleanSess=true, KeepAlive=60, Username=undefined, Password=undefined) V311ConnBin = <<16,35,0,4,77,81,84,84,4,2,0,60,0,23,109,111,115,113,112,117,98,47,49,48,52,53,49,45,105,77,97,99,46,108,111,99,97>>, {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT, @@ -95,7 +95,7 @@ parse_connect(_) -> proto_name = <<"MQTT">>, client_id = <<"mosqpub/10451-iMac.loca">>, clean_sess = true, - keep_alive = 60 } }, <<>>} = emqttd_parser:parse(V311ConnBin, Parser), + keep_alive = 60 } }, <<>>} = emqx_parser:parse(V311ConnBin, Parser), %% CONNECT(Qos=0, Retain=false, Dup=false, ClientId="", ProtoName=MQTT, ProtoVsn=4, CleanSess=true, KeepAlive=60) V311ConnWithoutClientId = <<16,12,0,4,77,81,84,84,4,2,0,60,0,0>>, @@ -107,7 +107,7 @@ parse_connect(_) -> proto_name = <<"MQTT">>, client_id = <<>>, clean_sess = true, - keep_alive = 60 } }, <<>>} = emqttd_parser:parse(V311ConnWithoutClientId, Parser), + keep_alive = 60 } }, <<>>} = emqx_parser:parse(V311ConnWithoutClientId, Parser), %%CONNECT(Q0, R0, D0, ClientId=mosqpub/10452-iMac.loca, ProtoName=MQIsdp, ProtoVsn=3, CleanSess=true, KeepAlive=60, %% Username=test, Password=******, Will(Qos=1, Retain=false, Topic=/will, Msg=willmsg)) ConnBinWithWill = <<16,67,0,6,77,81,73,115,100,112,3,206,0,60,0,23,109,111,115,113,112,117,98,47,49,48,52,53,50,45,105,77,97,99,46,108,111,99,97,0,5,47,119,105,108,108,0,7,119,105,108,108,109,115,103,0,4,116,101,115,116,0,6,112,117,98,108,105,99>>, @@ -126,18 +126,18 @@ parse_connect(_) -> will_topic = <<"/will">>, will_msg = <<"willmsg">>, username = <<"test">>, - password = <<"public">>}}, <<>>} = emqttd_parser:parse(ConnBinWithWill, Parser), + password = <<"public">>}}, <<>>} = emqx_parser:parse(ConnBinWithWill, Parser), ok. parse_bridge(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), Data = <<16,86,0,6,77,81,73,115,100,112,131,44,0,60,0,19,67,95,48,48,58,48,67,58,50,57,58,50,66,58,55,55,58,53,50, 0,48,36,83,89,83,47,98,114,111,107,101,114,47,99,111,110,110,101,99,116,105,111,110,47,67,95,48,48,58,48, 67,58,50,57,58,50,66,58,55,55,58,53,50,47,115,116,97,116,101,0,1,48>>, %% CONNECT(Q0, R0, D0, ClientId=C_00:0C:29:2B:77:52, ProtoName=MQIsdp, ProtoVsn=131, CleanSess=false, KeepAlive=60, %% Username=undefined, Password=undefined, Will(Q1, R1, Topic=$SYS/broker/connection/C_00:0C:29:2B:77:52/state, Msg=0)) - {ok, #mqtt_packet{variable = Variable}, <<>>} = emqttd_parser:parse(Data, Parser), + {ok, #mqtt_packet{variable = Variable}, <<>>} = emqx_parser:parse(Data, Parser), #mqtt_packet_connect{client_id = <<"C_00:0C:29:2B:77:52">>, proto_ver = 16#03, proto_name = <<"MQIsdp">>, @@ -150,7 +150,7 @@ parse_bridge(_) -> will_msg = <<"0">>} = Variable. parse_publish(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %%PUBLISH(Qos=1, Retain=false, Dup=false, TopicName=a/b/c, PacketId=1, Payload=<<"hahah">>) PubBin = <<50,14,0,5,97,47,98,47,99,0,1,104,97,104,97,104>>, {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH, @@ -159,7 +159,7 @@ parse_publish(_) -> retain = false}, variable = #mqtt_packet_publish{topic_name = <<"a/b/c">>, packet_id = 1}, - payload = <<"hahah">> }, <<>>} = emqttd_parser:parse(PubBin, Parser), + payload = <<"hahah">> }, <<>>} = emqx_parser:parse(PubBin, Parser), %PUBLISH(Qos=0, Retain=false, Dup=false, TopicName=xxx/yyy, PacketId=undefined, Payload=<<"hello">>) %DISCONNECT(Qos=0, Retain=false, Dup=false) @@ -170,43 +170,43 @@ parse_publish(_) -> retain = false}, variable = #mqtt_packet_publish{topic_name = <<"xxx/yyy">>, packet_id = undefined}, - payload = <<"hello">> }, <<224,0>>} = emqttd_parser:parse(PubBin1, Parser), + payload = <<"hello">> }, <<224,0>>} = emqx_parser:parse(PubBin1, Parser), {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?DISCONNECT, dup = false, qos = 0, - retain = false}}, <<>>} = emqttd_parser:parse(<<224, 0>>, Parser). + retain = false}}, <<>>} = emqx_parser:parse(<<224, 0>>, Parser). parse_puback(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %%PUBACK(Qos=0, Retain=false, Dup=false, PacketId=1) {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBACK, dup = false, qos = 0, - retain = false}}, <<>>} = emqttd_parser:parse(<<64,2,0,1>>, Parser). + retain = false}}, <<>>} = emqx_parser:parse(<<64,2,0,1>>, Parser). parse_pubrec(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %%PUBREC(Qos=0, Retain=false, Dup=false, PacketId=1) {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBREC, dup = false, qos = 0, - retain = false}}, <<>>} = emqttd_parser:parse(<<5:4,0:4,2,0,1>>, Parser). + retain = false}}, <<>>} = emqx_parser:parse(<<5:4,0:4,2,0,1>>, Parser). parse_pubrel(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBREL, dup = false, qos = 1, - retain = false}}, <<>>} = emqttd_parser:parse(<<6:4,2:4,2,0,1>>, Parser). + retain = false}}, <<>>} = emqx_parser:parse(<<6:4,2:4,2,0,1>>, Parser). parse_pubcomp(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBCOMP, dup = false, qos = 0, - retain = false}}, <<>>} = emqttd_parser:parse(<<7:4,0:4,2,0,1>>, Parser). + retain = false}}, <<>>} = emqx_parser:parse(<<7:4,0:4,2,0,1>>, Parser). parse_subscribe(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %% SUBSCRIBE(Q1, R0, D0, PacketId=2, TopicTable=[{<<"TopicA">>,2}]) {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?SUBSCRIBE, dup = false, @@ -214,10 +214,10 @@ parse_subscribe(_) -> retain = false}, variable = #mqtt_packet_subscribe{packet_id = 2, topic_table = [{<<"TopicA">>,2}]} }, <<>>} - = emqttd_parser:parse(<<130,11,0,2,0,6,84,111,112,105,99,65,2>>, Parser). + = emqx_parser:parse(<<130,11,0,2,0,6,84,111,112,105,99,65,2>>, Parser). parse_unsubscribe(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %% UNSUBSCRIBE(Q1, R0, D0, PacketId=2, TopicTable=[<<"TopicA">>]) {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?UNSUBSCRIBE, dup = false, @@ -225,24 +225,24 @@ parse_unsubscribe(_) -> retain = false}, variable = #mqtt_packet_unsubscribe{packet_id = 2, topics = [<<"TopicA">>]}}, <<>>} - = emqttd_parser:parse(<<162,10,0,2,0,6,84,111,112,105,99,65>>, Parser). + = emqx_parser:parse(<<162,10,0,2,0,6,84,111,112,105,99,65>>, Parser). parse_pingreq(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PINGREQ, dup = false, qos = 0, retain = false}}, <<>>} - = emqttd_parser:parse(<>, Parser). + = emqx_parser:parse(<>, Parser). parse_disconnect(_) -> - Parser = emqttd_parser:initial_state(), + Parser = emqx_parser:initial_state(), %DISCONNECT(Qos=0, Retain=false, Dup=false) Bin = <<224, 0>>, {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?DISCONNECT, dup = false, qos = 0, - retain = false}}, <<>>} = emqttd_parser:parse(Bin, Parser). + retain = false}}, <<>>} = emqx_parser:parse(Bin, Parser). %%-------------------------------------------------------------------- %% Serialize Cases @@ -305,72 +305,72 @@ long_payload() -> %%-------------------------------------------------------------------- packet_proto_name(_) -> - ?assertEqual(<<"MQIsdp">>, emqttd_packet:protocol_name(3)), - ?assertEqual(<<"MQTT">>, emqttd_packet:protocol_name(4)). + ?assertEqual(<<"MQIsdp">>, emqx_packet:protocol_name(3)), + ?assertEqual(<<"MQTT">>, emqx_packet:protocol_name(4)). packet_type_name(_) -> - ?assertEqual('CONNECT', emqttd_packet:type_name(?CONNECT)), - ?assertEqual('UNSUBSCRIBE', emqttd_packet:type_name(?UNSUBSCRIBE)). + ?assertEqual('CONNECT', emqx_packet:type_name(?CONNECT)), + ?assertEqual('UNSUBSCRIBE', emqx_packet:type_name(?UNSUBSCRIBE)). packet_connack_name(_) -> - ?assertEqual('CONNACK_ACCEPT', emqttd_packet:connack_name(?CONNACK_ACCEPT)), - ?assertEqual('CONNACK_PROTO_VER', emqttd_packet:connack_name(?CONNACK_PROTO_VER)), - ?assertEqual('CONNACK_INVALID_ID', emqttd_packet:connack_name(?CONNACK_INVALID_ID)), - ?assertEqual('CONNACK_SERVER', emqttd_packet:connack_name(?CONNACK_SERVER)), - ?assertEqual('CONNACK_CREDENTIALS', emqttd_packet:connack_name(?CONNACK_CREDENTIALS)), - ?assertEqual('CONNACK_AUTH', emqttd_packet:connack_name(?CONNACK_AUTH)). + ?assertEqual('CONNACK_ACCEPT', emqx_packet:connack_name(?CONNACK_ACCEPT)), + ?assertEqual('CONNACK_PROTO_VER', emqx_packet:connack_name(?CONNACK_PROTO_VER)), + ?assertEqual('CONNACK_INVALID_ID', emqx_packet:connack_name(?CONNACK_INVALID_ID)), + ?assertEqual('CONNACK_SERVER', emqx_packet:connack_name(?CONNACK_SERVER)), + ?assertEqual('CONNACK_CREDENTIALS', emqx_packet:connack_name(?CONNACK_CREDENTIALS)), + ?assertEqual('CONNACK_AUTH', emqx_packet:connack_name(?CONNACK_AUTH)). packet_format(_) -> - io:format("~s", [emqttd_packet:format(?CONNECT_PACKET(#mqtt_packet_connect{}))]), - io:format("~s", [emqttd_packet:format(?CONNACK_PACKET(?CONNACK_SERVER))]), - io:format("~s", [emqttd_packet:format(?PUBLISH_PACKET(?QOS_1, 1))]), - io:format("~s", [emqttd_packet:format(?PUBLISH_PACKET(?QOS_2, <<"topic">>, 10, <<"payload">>))]), - io:format("~s", [emqttd_packet:format(?PUBACK_PACKET(?PUBACK, 98))]), - io:format("~s", [emqttd_packet:format(?PUBREL_PACKET(99))]), - io:format("~s", [emqttd_packet:format(?SUBSCRIBE_PACKET(15, [{<<"topic">>, ?QOS0}, {<<"topic1">>, ?QOS1}]))]), - io:format("~s", [emqttd_packet:format(?SUBACK_PACKET(40, [?QOS0, ?QOS1]))]), - io:format("~s", [emqttd_packet:format(?UNSUBSCRIBE_PACKET(89, [<<"t">>, <<"t2">>]))]), - io:format("~s", [emqttd_packet:format(?UNSUBACK_PACKET(90))]). + io:format("~s", [emqx_packet:format(?CONNECT_PACKET(#mqtt_packet_connect{}))]), + io:format("~s", [emqx_packet:format(?CONNACK_PACKET(?CONNACK_SERVER))]), + io:format("~s", [emqx_packet:format(?PUBLISH_PACKET(?QOS_1, 1))]), + io:format("~s", [emqx_packet:format(?PUBLISH_PACKET(?QOS_2, <<"topic">>, 10, <<"payload">>))]), + io:format("~s", [emqx_packet:format(?PUBACK_PACKET(?PUBACK, 98))]), + io:format("~s", [emqx_packet:format(?PUBREL_PACKET(99))]), + io:format("~s", [emqx_packet:format(?SUBSCRIBE_PACKET(15, [{<<"topic">>, ?QOS0}, {<<"topic1">>, ?QOS1}]))]), + io:format("~s", [emqx_packet:format(?SUBACK_PACKET(40, [?QOS0, ?QOS1]))]), + io:format("~s", [emqx_packet:format(?UNSUBSCRIBE_PACKET(89, [<<"t">>, <<"t2">>]))]), + io:format("~s", [emqx_packet:format(?UNSUBACK_PACKET(90))]). %%-------------------------------------------------------------------- %% Message Cases %%-------------------------------------------------------------------- message_make(_) -> - Msg = emqttd_message:make(<<"clientid">>, <<"topic">>, <<"payload">>), + Msg = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>), ?assertEqual(0, Msg#mqtt_message.qos), - Msg1 = emqttd_message:make(<<"clientid">>, qos2, <<"topic">>, <<"payload">>), + Msg1 = emqx_message:make(<<"clientid">>, qos2, <<"topic">>, <<"payload">>), ?assert(is_binary(Msg1#mqtt_message.id)), ?assertEqual(2, Msg1#mqtt_message.qos). message_from_packet(_) -> - Msg = emqttd_message:from_packet(?PUBLISH_PACKET(1, <<"topic">>, 10, <<"payload">>)), + Msg = emqx_message:from_packet(?PUBLISH_PACKET(1, <<"topic">>, 10, <<"payload">>)), ?assertEqual(1, Msg#mqtt_message.qos), ?assertEqual(10, Msg#mqtt_message.pktid), ?assertEqual(<<"topic">>, Msg#mqtt_message.topic), - WillMsg = emqttd_message:from_packet(#mqtt_packet_connect{will_flag = true, + WillMsg = emqx_message:from_packet(#mqtt_packet_connect{will_flag = true, will_topic = <<"WillTopic">>, will_msg = <<"WillMsg">>}), ?assertEqual(<<"WillTopic">>, WillMsg#mqtt_message.topic), ?assertEqual(<<"WillMsg">>, WillMsg#mqtt_message.payload), - Msg2 = emqttd_message:from_packet(<<"username">>, <<"clientid">>, + Msg2 = emqx_message:from_packet(<<"username">>, <<"clientid">>, ?PUBLISH_PACKET(1, <<"topic">>, 20, <<"payload">>)), ?assertEqual({<<"clientid">>, <<"username">>}, Msg2#mqtt_message.from), - io:format("~s", [emqttd_message:format(Msg2)]). + io:format("~s", [emqx_message:format(Msg2)]). message_flag(_) -> Pkt = ?PUBLISH_PACKET(1, <<"t">>, 2, <<"payload">>), - Msg2 = emqttd_message:from_packet(<<"clientid">>, Pkt), - Msg3 = emqttd_message:set_flag(retain, Msg2), - Msg4 = emqttd_message:set_flag(dup, Msg3), + Msg2 = emqx_message:from_packet(<<"clientid">>, Pkt), + Msg3 = emqx_message:set_flag(retain, Msg2), + Msg4 = emqx_message:set_flag(dup, Msg3), ?assert(Msg4#mqtt_message.dup), ?assert(Msg4#mqtt_message.retain), - Msg5 = emqttd_message:set_flag(Msg4), - Msg6 = emqttd_message:unset_flag(dup, Msg5), - Msg7 = emqttd_message:unset_flag(retain, Msg6), + Msg5 = emqx_message:set_flag(Msg4), + Msg6 = emqx_message:unset_flag(dup, Msg5), + Msg7 = emqx_message:unset_flag(retain, Msg6), ?assertNot(Msg7#mqtt_message.dup), ?assertNot(Msg7#mqtt_message.retain), - emqttd_message:unset_flag(Msg7), - emqttd_message:to_packet(Msg7). + emqx_message:unset_flag(Msg7), + emqx_message:to_packet(Msg7). diff --git a/test/emqttd_topic_SUITE.erl b/test/emqx_topic_SUITE.erl similarity index 96% rename from test/emqttd_topic_SUITE.erl rename to test/emqx_topic_SUITE.erl index b1ea4d8ed..ffdc65c1a 100644 --- a/test/emqttd_topic_SUITE.erl +++ b/test/emqx_topic_SUITE.erl @@ -14,15 +14,17 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_topic_SUITE). +-module(emqx_topic_SUITE). + +-author("Feng Lee "). -include_lib("eunit/include/eunit.hrl"). %% CT -compile(export_all). --import(emqttd_topic, [wildcard/1, match/2, validate/1, triples/1, join/1, - words/1, systop/1, feed_var/3, parse/1, parse/2]). +-import(emqx_topic, [wildcard/1, match/2, validate/1, triples/1, join/1, + words/1, systop/1, feed_var/3, parse/1, parse/2]). -define(N, 10000). @@ -185,5 +187,6 @@ t_parse(_) -> ?assertEqual({<<"topic">>, [{share, <<"group">>}]}, parse(<<"$share/group/topic">>)), ?assertEqual({<<"topic">>, [local]}, parse(<<"$local/topic">>)), ?assertEqual({<<"topic">>, [{share, '$queue'}, local]}, parse(<<"$local/$queue/topic">>)), - ?assertEqual({<<"/a/b/c">>, [{share, <<"group">>}, local]}, parse(<<"$local/$share/group//a/b/c">>)). + ?assertEqual({<<"/a/b/c">>, [{share, <<"group">>}, local]}, parse(<<"$local/$share/group//a/b/c">>)), + ?assertEqual({<<"topic">>, [fastlane]}, parse(<<"$fastlane/topic">>)). diff --git a/test/emqttd_trie_SUITE.erl b/test/emqx_trie_SUITE.erl similarity index 92% rename from test/emqttd_trie_SUITE.erl rename to test/emqx_trie_SUITE.erl index a81a132f5..6562575a7 100644 --- a/test/emqttd_trie_SUITE.erl +++ b/test/emqx_trie_SUITE.erl @@ -14,13 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_trie_SUITE). +-module(emqx_trie_SUITE). + +-author("Feng Lee "). -compile(export_all). --include("emqttd_trie.hrl"). +-include("emqx_trie.hrl"). --define(TRIE, emqttd_trie). +-define(TRIE, emqx_trie). -include_lib("eunit/include/eunit.hrl"). @@ -81,10 +83,10 @@ t_match2(_) -> t_match3(_) -> Topics = [<<"d/#">>, <<"a/b/c">>, <<"a/b/+">>, <<"a/#">>, <<"#">>, <<"$SYS/#">>], - mnesia:transaction(fun() -> [emqttd_trie:insert(Topic) || Topic <- Topics] end), - Matched = mnesia:async_dirty(fun emqttd_trie:match/1, [<<"a/b/c">>]), + mnesia:transaction(fun() -> [emqx_trie:insert(Topic) || Topic <- Topics] end), + Matched = mnesia:async_dirty(fun emqx_trie:match/1, [<<"a/b/c">>]), ?assertEqual(4, length(Matched)), - SysMatched = mnesia:async_dirty(fun emqttd_trie:match/1, [<<"$SYS/a/b/c">>]), + SysMatched = mnesia:async_dirty(fun emqx_trie:match/1, [<<"$SYS/a/b/c">>]), ?assertEqual([<<"$SYS/#">>], SysMatched). t_delete(_) -> diff --git a/test/emqttd_vm_SUITE.erl b/test/emqx_vm_SUITE.erl similarity index 87% rename from test/emqttd_vm_SUITE.erl rename to test/emqx_vm_SUITE.erl index ef0ac2946..3263b85e7 100644 --- a/test/emqttd_vm_SUITE.erl +++ b/test/emqx_vm_SUITE.erl @@ -14,7 +14,7 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqttd_vm_SUITE). +-module(emqx_vm_SUITE). -compile(export_all). @@ -102,73 +102,73 @@ all() -> get_process_limit]. load(_Config) -> - Loads = emqttd_vm:loads(), + Loads = emqx_vm:loads(), [{load1, _}, {load5, _}, {load15, _}] = Loads. systeminfo(_Config) -> - Keys = [Key || {Key, _} <- emqttd_vm:get_system_info()], + Keys = [Key || {Key, _} <- emqx_vm:get_system_info()], ?SYSTEM_INFO = Keys. mem_info(_Config) -> application:ensure_all_started(os_mon), - MemInfo = emqttd_vm:mem_info(), + MemInfo = emqx_vm:mem_info(), [{total_memory, _}, {used_memory, _}]= MemInfo, application:stop(os_mon). process_list(_Config) -> Pid = self(), - ProcessInfo = emqttd_vm:get_process_list(), + ProcessInfo = emqx_vm:get_process_list(), true = lists:member({pid, Pid}, lists:concat(ProcessInfo)). process_info(_Config) -> - ProcessInfos = emqttd_vm:get_process_info(), + ProcessInfos = emqx_vm:get_process_info(), ProcessInfo = lists:last(ProcessInfos), Keys = [K || {K, _V}<- ProcessInfo], ?PROCESS_INFO = Keys. process_gc(_Config) -> - ProcessGcs = emqttd_vm:get_process_gc(), + ProcessGcs = emqx_vm:get_process_gc(), ProcessGc = lists:last(ProcessGcs), Keys = [K || {K, _V}<- ProcessGc], ?PROCESS_GC = Keys. get_ets_list(_Config) -> ets:new(test, [named_table]), - Ets = emqttd_vm:get_ets_list(), + Ets = emqx_vm:get_ets_list(), true = lists:member(test, Ets). get_ets_info(_Config) -> ets:new(test, [named_table]), - [] = emqttd_vm:get_ets_info(test1), - EtsInfo = emqttd_vm:get_ets_info(test), + [] = emqx_vm:get_ets_info(test1), + EtsInfo = emqx_vm:get_ets_info(test), test = proplists:get_value(name, EtsInfo). get_ets_object(_Config) -> ets:new(test, [named_table]), ets:insert(test, {k, v}), - [{k, v}] = emqttd_vm:get_ets_object(test). + [{k, v}] = emqx_vm:get_ets_object(test). get_port_types(_Config) -> - emqttd_vm:get_port_types(). + emqx_vm:get_port_types(). get_port_info(_Config) -> - emqttd_vm:get_port_info(). + emqx_vm:get_port_info(). scheduler_usage(_Config) -> - emqttd_vm:scheduler_usage(5000). + emqx_vm:scheduler_usage(5000). get_memory(_Config) -> - emqttd_vm:get_memory(). + emqx_vm:get_memory(). microsecs(_Config) -> - emqttd_vm:microsecs(). + emqx_vm:microsecs(). schedulers(_Config) -> - emqttd_vm:schedulers(). + emqx_vm:schedulers(). get_process_group_leader_info(_Config) -> - emqttd_vm:get_process_group_leader_info(self()). + emqx_vm:get_process_group_leader_info(self()). get_process_limit(_Config) -> - emqttd_vm:get_process_limit(). + emqx_vm:get_process_limit(). diff --git a/test/ws_client.erl b/test/ws_client.erl new file mode 100644 index 000000000..f049e3256 --- /dev/null +++ b/test/ws_client.erl @@ -0,0 +1,77 @@ +-module(ws_client). + +-behaviour(websocket_client_handler). + +-export([ + start_link/0, + start_link/1, + send_binary/2, + send_ping/2, + recv/2, + recv/1, + stop/1 + ]). + +-export([ + init/2, + websocket_handle/3, + websocket_info/3, + websocket_terminate/3 + ]). + +-record(state, { + buffer = [] :: list(), + waiting = undefined :: undefined | pid() + }). + +start_link() -> + start_link("ws://localhost:8083/mqtt"). + +start_link(Url) -> + websocket_client:start_link(Url, ?MODULE, [], [{extra_headers, [{"Sec-Websocket-Protocol", "mqtt"}]}]). + +stop(Pid) -> + Pid ! stop. + +send_binary(Pid, Msg) -> + websocket_client:cast(Pid, {binary, Msg}). + +send_ping(Pid, Msg) -> + websocket_client:cast(Pid, {ping, Msg}). + +recv(Pid) -> + recv(Pid, 5000). + +recv(Pid, Timeout) -> + Pid ! {recv, self()}, + receive + M -> M + after + Timeout -> error + end. + +init(_, _WSReq) -> + {ok, #state{}}. + +websocket_handle(Frame, _, State = #state{waiting = undefined, buffer = Buffer}) -> + lager:info("Client received frame~p", [Frame]), + {ok, State#state{buffer = [Frame|Buffer]}}; +websocket_handle(Frame, _, State = #state{waiting = From}) -> + lager:info("Client received frame~p", [Frame]), + From ! Frame, + {ok, State#state{waiting = undefined}}. + +websocket_info({send_text, Text}, WSReq, State) -> + websocket_client:send({text, Text}, WSReq), + {ok, State}; +websocket_info({recv, From}, _, State = #state{buffer = []}) -> + {ok, State#state{waiting = From}}; +websocket_info({recv, From}, _, State = #state{buffer = [Top|Rest]}) -> + From ! Top, + {ok, State#state{buffer = Rest}}; +websocket_info(stop, _, State) -> + {close, <<>>, State}. + +websocket_terminate(Close, _, State) -> + io:format("Websocket closed with frame ~p and state ~p", [Close, State]), + ok.