Merge with EMQ X project
This commit is contained in:
parent
d9f14dacaf
commit
4b8cd18f5d
|
@ -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
|
||||
|
|
|
@ -2,6 +2,7 @@ language: erlang
|
|||
|
||||
otp_release:
|
||||
- 20.0
|
||||
- 20.1
|
||||
|
||||
script:
|
||||
- make
|
||||
|
|
|
@ -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.]
|
31
Makefile
31
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/
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)},
|
|
@ -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 <feng@emqtt.io>"]},
|
||||
{licenses,["Apache-2.0"]},
|
||||
{links,[{"Github","https://github.com/emqtt/emqttd"}]}]}.
|
187
src/emqttd.erl
187
src/emqttd.erl
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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()]).
|
||||
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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.
|
||||
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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}, []}}.
|
||||
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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()]).
|
||||
|
|
@ -14,13 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_access_control).
|
||||
-module(emqx_access_control).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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;
|
|
@ -14,12 +14,11 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_access_rule).
|
||||
-module(emqx_access_rule).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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, []).
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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.
|
|
@ -14,11 +14,11 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_acl_mod).
|
||||
-module(emqx_acl_mod).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-include("emqttd.hrl").
|
||||
-include("emqx.hrl").
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% ACL behavihour
|
|
@ -14,13 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_alarm).
|
||||
-module(emqx_alarm).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-behaviour(gen_event).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
-include("emqx.hrl").
|
||||
|
||||
-define(ALARM_MGR, ?MODULE).
|
||||
|
||||
|
@ -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">>).
|
||||
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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().
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_auth_mod).
|
||||
-module(emqx_auth_mod).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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(<<X:128/big-unsigned-integer>>) ->
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_base62).
|
||||
-module(emqx_base62).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_boot).
|
||||
-module(emqx_boot).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -14,17 +14,17 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_bridge).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
-module(emqx_bridge).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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),
|
||||
MQueue = emqx_mqueue:new(qname(Node, Topic),
|
||||
[{max_len, State#state.max_queue_len}],
|
||||
emqttd_alarm:alarm_fun()),
|
||||
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} ->
|
|
@ -14,7 +14,9 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_bridge_sup).
|
||||
-module(emqx_bridge_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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).
|
||||
|
|
@ -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]}.
|
||||
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_broker).
|
||||
-module(emqx_broker).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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,
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_cli).
|
||||
-module(emqx_cli).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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 <ClientId>", "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 <ClientId>", "Show subscriptions of a client"},
|
||||
|
@ -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 <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.
|
|
@ -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".
|
||||
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
%% @doc MQTT/TCP Connection.
|
||||
|
||||
-module(emqttd_client).
|
||||
-module(emqx_client).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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).
|
||||
|
|
@ -16,15 +16,15 @@
|
|||
|
||||
%% @doc MQTT Client Manager
|
||||
|
||||
-module(emqttd_cm).
|
||||
-module(emqx_cm).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
%% @doc Client Manager Supervisor.
|
||||
|
||||
-module(emqttd_cm_sup).
|
||||
-module(emqx_cm_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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]}}.
|
||||
|
|
@ -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.
|
||||
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_ctl).
|
||||
-module(emqx_ctl).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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
|
||||
}.
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
%% GC Utility functions.
|
||||
|
||||
-module(emqttd_gc).
|
||||
-module(emqx_gc).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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
|
|
@ -14,14 +14,10 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc emqttd gen_mod behaviour
|
||||
|
||||
-module(emqttd_gen_mod).
|
||||
-module(emqx_gen_mod).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-ifdef(use_specs).
|
||||
|
||||
-callback(load(Opts :: any()) -> ok | {error, any()}).
|
|
@ -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), <<I:128>>.
|
||||
|
||||
to_base62(<<I:128>>) ->
|
||||
emqttd_base62:encode(I).
|
||||
emqx_base62:encode(I).
|
||||
|
||||
from_base62(S) ->
|
||||
I = emqttd_base62:decode(S), <<I:128>>.
|
||||
I = emqx_base62:decode(S), <<I:128>>.
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_hooks).
|
||||
-module(emqx_hooks).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -16,19 +16,21 @@
|
|||
|
||||
%% @doc HTTP publish API and websocket client.
|
||||
|
||||
-module(emqttd_http).
|
||||
-module(emqx_http).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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} ->
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
%% @doc Inflight Window that wraps the gb_trees.
|
||||
|
||||
-module(emqttd_inflight).
|
||||
-module(emqx_inflight).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
%% @doc Client Keepalive
|
||||
|
||||
-module(emqttd_keepalive).
|
||||
-module(emqx_keepalive).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(lager_emqtt_backend).
|
||||
-module(emqx_lager_backend).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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]))).
|
||||
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
%% @doc MQTT Message Functions
|
||||
|
||||
-module(emqttd_message).
|
||||
-module(emqx_message).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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,
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_metrics).
|
||||
-module(emqx_metrics).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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)).
|
||||
|
|
@ -14,15 +14,17 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_mgmt).
|
||||
-module(emqx_mgmt).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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,17 +246,54 @@ 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),
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_misc).
|
||||
-module(emqx_misc).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -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]).
|
|
@ -41,13 +41,13 @@
|
|||
%%
|
||||
%% @end
|
||||
|
||||
-module(emqttd_mqueue).
|
||||
-module(emqx_mqueue).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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()}).
|
||||
|
|
@ -14,7 +14,9 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_net).
|
||||
-module(emqx_net).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-include_lib("kernel/include/inet.hrl").
|
||||
|
|
@ -14,13 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_packet).
|
||||
-module(emqx_packet).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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]).
|
|
@ -15,13 +15,13 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc MQTT Packet Parser
|
||||
-module(emqttd_parser).
|
||||
-module(emqx_parser).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-include("emqttd.hrl").
|
||||
-include("emqx.hrl").
|
||||
|
||||
-include("emqttd_protocol.hrl").
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
%% API
|
||||
-export([initial_state/0, initial_state/1, parse/2]).
|
|
@ -14,11 +14,11 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_plugins).
|
||||
-module(emqx_plugins).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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) ->
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_pmon).
|
||||
-module(emqx_pmon).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Common Pool Supervisor
|
||||
-module(emqttd_pool_sup).
|
||||
-module(emqx_pool_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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]).
|
||||
|
|
@ -14,11 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_pooler).
|
||||
-module(emqx_pooler).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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
|
|
@ -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.
|
||||
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_protocol).
|
||||
-module(emqx_protocol).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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,
|
||||
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()},
|
||||
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.
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_pubsub).
|
||||
-module(emqx_pubsub).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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.
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc PubSub Supervisor.
|
||||
-module(emqttd_pubsub_sup).
|
||||
-module(emqx_pubsub_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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
|
|
@ -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) ->
|
||||
|
@ -326,7 +327,7 @@ publish('POST', Params) ->
|
|||
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
|
||||
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}]};
|
|
@ -14,13 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_router).
|
||||
-module(emqx_router).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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)).
|
||||
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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).
|
||||
|
|
@ -15,13 +15,13 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc MQTT Packet Serializer
|
||||
-module(emqttd_serializer).
|
||||
-module(emqx_serializer).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-include("emqttd.hrl").
|
||||
-include("emqx.hrl").
|
||||
|
||||
-include("emqttd_protocol.hrl").
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
%% API
|
||||
-export([serialize/1]).
|
|
@ -14,17 +14,17 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_server).
|
||||
-module(emqx_server).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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}],
|
||||
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}) ->
|
||||
lager:debug([{client, From}, {topic, Topic}],
|
||||
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',
|
||||
emqx_stats:setstats('subscriptions/count', 'subscriptions/max',
|
||||
ets:info(mqtt_subscription, size)), State.
|
||||
|
|
@ -43,19 +43,19 @@
|
|||
%% @end
|
||||
%%
|
||||
|
||||
-module(emqttd_session).
|
||||
-module(emqx_session).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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).
|
||||
-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).
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Session Supervisor.
|
||||
-module(emqttd_session_sup).
|
||||
-module(emqx_session_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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]}]}}.
|
||||
|
|
@ -14,15 +14,15 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_sm).
|
||||
-module(emqx_sm).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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} ->
|
||||
|
@ -280,14 +282,14 @@ resume_session(Session = #mqtt_session{client_id = ClientId, sess_pid = SessPid}
|
|||
%% Local node
|
||||
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} ->
|
|
@ -15,15 +15,15 @@
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Session Helper.
|
||||
-module(emqttd_sm_helper).
|
||||
-module(emqx_sm_helper).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
-include("emqx.hrl").
|
||||
|
||||
-include("emqttd_internal.hrl").
|
||||
-include("emqx_internal.hrl").
|
||||
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
%% @doc Session Manager Supervisor.
|
||||
|
||||
-module(emqttd_sm_sup).
|
||||
-module(emqx_sm_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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]}}.
|
||||
|
|
@ -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)).
|
||||
|
|
@ -14,13 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_stats).
|
||||
-module(emqx_stats).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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)).
|
||||
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-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)]
|
||||
}}.
|
||||
|
|
@ -14,14 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc VM System Monitor
|
||||
-module(emqttd_sysmon).
|
||||
-module(emqx_sysmon).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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(),
|
||||
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};
|
|
@ -14,7 +14,9 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_sysmon_sup).
|
||||
-module(emqx_sysmon_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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]}}.
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_time).
|
||||
-module(emqx_time).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
|
@ -14,13 +14,13 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_topic).
|
||||
-module(emqx_topic).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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()).
|
|
@ -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 <feng@emqtt.io>").
|
||||
|
||||
-include("emqttd_internal.hrl").
|
||||
-include("emqx_internal.hrl").
|
||||
|
||||
%% API Function Exports
|
||||
-export([start_link/0]).
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_trace_sup).
|
||||
-module(emqx_trace_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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]}}.
|
||||
|
|
@ -18,11 +18,11 @@
|
|||
%% [Trie](http://en.wikipedia.org/wiki/Trie)
|
||||
%% @end
|
||||
|
||||
-module(emqttd_trie).
|
||||
-module(emqx_trie).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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});
|
||||
[] ->
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_vm).
|
||||
-module(emqx_vm).
|
||||
|
||||
-export([schedulers/0]).
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_ws).
|
||||
-module(emqx_ws).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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)}.
|
||||
|
|
@ -16,19 +16,19 @@
|
|||
|
||||
%% @doc MQTT WebSocket Connection.
|
||||
|
||||
-module(emqttd_ws_client).
|
||||
-module(emqx_ws_client).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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),
|
||||
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).
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_ws_client_sup).
|
||||
-module(emqx_ws_client_sup).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
|
@ -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]}]}}.
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
%%
|
||||
%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io)
|
||||
%%
|
||||
|
||||
-module(emqttd_inflight_SUITE).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-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()).
|
||||
|
|
@ -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,
|
||||
|
@ -122,17 +123,21 @@ groups() ->
|
|||
]},
|
||||
cli_vm]},
|
||||
{cleanSession, [sequence],
|
||||
[cleanSession_validate]},
|
||||
{get_api, [sequence], [get_api_lists]}].
|
||||
[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)).
|
||||
|
|
@ -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}.
|
||||
|
||||
|
|
@ -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}]}].
|
|
@ -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(_) ->
|
|
@ -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}.
|
||||
|
|
@ -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".
|
||||
|
|
@ -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".
|
|
@ -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".
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue