Merge pull request #452 from emqtt/0.16
0.16 - Licensed under the Apache 2.0. Improve the design of cluster, route and trie.
This commit is contained in:
commit
4cfa07d774
|
|
@ -19,3 +19,10 @@ log/
|
|||
*.so
|
||||
examples
|
||||
docs/build/*
|
||||
.erlang.mk/
|
||||
cover/
|
||||
emqttd.d
|
||||
eunit.coverdata
|
||||
test/ct.cover.spec
|
||||
logs
|
||||
ct.coverdata
|
||||
|
|
|
|||
38
CHANGELOG.md
38
CHANGELOG.md
|
|
@ -1,6 +1,42 @@
|
|||
|
||||
emqttd ChangeLog
|
||||
==================
|
||||
=================
|
||||
|
||||
0.16.0-beta(2016-02-16)
|
||||
------------------------
|
||||
|
||||
#### Highlights
|
||||
|
||||
Licensed under the Apache License, Version 2.0 Now.
|
||||
|
||||
Improve the design of cluster, support to join or leave the cluster (#449):
|
||||
|
||||
```
|
||||
$ ./bin/emqttd_ctl cluster
|
||||
cluster join <Node> #Join the cluster
|
||||
cluster leave #Leave the cluster
|
||||
cluster remove <Node> #Remove the node from cluster
|
||||
cluster status #Cluster status
|
||||
```
|
||||
|
||||
Improve the design of Trie and Route, only the wildcard topics stored in Trie.
|
||||
|
||||
Common Test to replace EUnit.
|
||||
|
||||
#### Enhancements
|
||||
|
||||
mqtt_message record: add 'sender' field (#440)
|
||||
|
||||
refactor the emqttd, emqttd_time, emqttd_opts, emqttd_node modules.
|
||||
|
||||
#### BugFix
|
||||
|
||||
noproc error when call to gen_server2:call(false, {add_route,Topic,<0.685.0>}, infinity) (#446)
|
||||
|
||||
#### Plugins
|
||||
|
||||
Changed the license of all plugins.
|
||||
|
||||
|
||||
0.15.0-beta (2016-01-31)
|
||||
------------------------
|
||||
|
|
|
|||
214
LICENSE
214
LICENSE
|
|
@ -1,25 +1,201 @@
|
|||
The MIT License (MIT)
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
1. Definitions.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
The source files 'gen_server2.erl' and 'priority_queue.erl' are from RabbitMQ
|
||||
v3.5.4 and licensed under MPL license.
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
|
|
|||
3
Makefile
3
Makefile
|
|
@ -26,7 +26,8 @@ clean:
|
|||
@$(REBAR) clean
|
||||
|
||||
test:
|
||||
@$(REBAR) skip_deps=true eunit
|
||||
ERL_FLAGS="-config rel/files/test.config" $(REBAR) -v skip_deps=true ct
|
||||
#$(REBAR) skip_deps=true eunit
|
||||
|
||||
edoc:
|
||||
@$(REBAR) doc
|
||||
|
|
|
|||
|
|
@ -145,5 +145,5 @@ Feng Lee <feng@emqtt.io>
|
|||
|
||||
## License
|
||||
|
||||
The MIT License (MIT)
|
||||
Apache License Version 2.0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +1,28 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% MQTT Broker Header.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Broker Header
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Banner
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-define(COPYRIGHT, "Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-define(LICENSE_MESSAGE, "Licensed under MIT").
|
||||
-define(LICENSE_MESSAGE, "Licensed under the Apache License, Version 2.0").
|
||||
|
||||
-define(PROTOCOL_VERSION, "MQTT/3.1.1").
|
||||
|
||||
|
|
@ -42,16 +34,17 @@
|
|||
%% Queue Topics.
|
||||
-define(QTop, <<"$Q">>).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% PubSub
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-type pubsub() :: publish | subscribe.
|
||||
|
||||
-define(IS_PUBSUB(PS), (PS =:= publish orelse PS =:= subscribe)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Topic
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_topic, {
|
||||
topic :: binary(),
|
||||
node :: node()
|
||||
|
|
@ -59,9 +52,9 @@
|
|||
|
||||
-type mqtt_topic() :: #mqtt_topic{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Subscription
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_subscription, {
|
||||
subid :: binary() | atom(),
|
||||
topic :: binary(),
|
||||
|
|
@ -70,12 +63,12 @@
|
|||
|
||||
-type mqtt_subscription() :: #mqtt_subscription{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Client
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-type header_key() :: atom() | binary() | string().
|
||||
-type header_val() :: atom() | binary() | string() | integer().
|
||||
-type ws_header_key() :: atom() | binary() | string().
|
||||
-type ws_header_val() :: atom() | binary() | string() | integer().
|
||||
|
||||
-record(mqtt_client, {
|
||||
client_id :: binary() | undefined,
|
||||
|
|
@ -86,15 +79,15 @@
|
|||
proto_ver :: 3 | 4,
|
||||
keepalive = 0,
|
||||
will_topic :: undefined | binary(),
|
||||
ws_initial_headers :: list({header_key(), header_val()}),
|
||||
ws_initial_headers :: list({ws_header_key(), ws_header_val()}),
|
||||
connected_at :: erlang:timestamp()
|
||||
}).
|
||||
|
||||
-type mqtt_client() :: #mqtt_client{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Session
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_session, {
|
||||
client_id :: binary(),
|
||||
sess_pid :: pid(),
|
||||
|
|
@ -103,30 +96,32 @@
|
|||
|
||||
-type mqtt_session() :: #mqtt_session{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Message
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-type mqtt_msgid() :: binary() | undefined.
|
||||
-type mqtt_pktid() :: 1..16#ffff | undefined.
|
||||
|
||||
-record(mqtt_message, {
|
||||
msgid :: mqtt_msgid(), %% Global unique message ID
|
||||
pktid :: mqtt_pktid(), %% PacketId
|
||||
topic :: binary(), %% Topic that the message is published to
|
||||
from :: binary() | atom(), %% ClientId of publisher
|
||||
qos = 0 :: 0 | 1 | 2, %% Message QoS
|
||||
retain = false :: boolean(), %% Retain flag
|
||||
dup = false :: boolean(), %% Dup flag
|
||||
sys = false :: boolean(), %% $SYS flag
|
||||
payload :: binary(), %% Payload
|
||||
timestamp :: erlang:timestamp() %% os:timestamp
|
||||
msgid :: mqtt_msgid(), %% Global unique message ID
|
||||
pktid :: mqtt_pktid(), %% PacketId
|
||||
topic :: binary(), %% Topic that the message is published to
|
||||
from :: binary() | atom(), %% ClientId of the publisher
|
||||
sender :: binary() | undefined, %% Username of the publisher
|
||||
qos = 0 :: 0 | 1 | 2, %% Message QoS
|
||||
flags = [] :: [retain | dup | sys], %% Message Flags
|
||||
retain = false :: boolean(), %% Retain flag
|
||||
dup = false :: boolean(), %% Dup flag
|
||||
sys = false :: boolean(), %% $SYS flag
|
||||
payload :: binary(), %% Payload
|
||||
timestamp :: erlang:timestamp() %% os:timestamp
|
||||
}).
|
||||
|
||||
-type mqtt_message() :: #mqtt_message{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Alarm
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_alarm, {
|
||||
id :: binary(),
|
||||
severity :: warning | error | critical,
|
||||
|
|
@ -137,9 +132,9 @@
|
|||
|
||||
-type mqtt_alarm() :: #mqtt_alarm{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Plugin
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_plugin, {
|
||||
name,
|
||||
version,
|
||||
|
|
@ -150,10 +145,10 @@
|
|||
|
||||
-type mqtt_plugin() :: #mqtt_plugin{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT CLI Command
|
||||
%% For example: 'broker metrics'
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_cli, {
|
||||
name,
|
||||
action,
|
||||
|
|
|
|||
|
|
@ -1,34 +1,24 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-define(PRINT(Format, Args),
|
||||
io:format(Format, Args)).
|
||||
-define(PRINT_MSG(Msg), io:format(Msg)).
|
||||
|
||||
-define(PRINT_MSG(Msg),
|
||||
io:format(Msg)).
|
||||
-define(PRINT(Format, Args), io:format(Format, Args)).
|
||||
|
||||
-define(PRINT_CMD(Cmd, Descr),
|
||||
io:format("~-40s#~s~n", [Cmd, Descr])).
|
||||
-define(PRINT_CMD(Cmd, Descr), io:format("~-40s#~s~n", [Cmd, Descr])).
|
||||
|
||||
-define(USAGE(CmdList),
|
||||
[?PRINT_CMD(Cmd, Descr) || {Cmd, Descr} <- CmdList]).
|
||||
-define(USAGE(CmdList), [?PRINT_CMD(Cmd, Descr) || {Cmd, Descr} <- CmdList]).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Internal Header File
|
||||
%%%
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% Internal Header File
|
||||
|
||||
-define(GPROC_POOL(JoinOrLeave, Pool, I),
|
||||
(begin
|
||||
|
|
@ -31,6 +24,8 @@
|
|||
end
|
||||
end)).
|
||||
|
||||
-define(PROC_NAME(M, I), (list_to_atom(lists:concat([M, "_", I])))).
|
||||
|
||||
-define(record_to_proplist(Def, Rec),
|
||||
lists:zip(record_info(fields, Def),
|
||||
tl(tuple_to_list(Rec)))).
|
||||
|
|
@ -57,3 +52,9 @@
|
|||
{noreply, State}
|
||||
end)).
|
||||
|
||||
-define(IF(Cond, TrueFun,FalseFun),
|
||||
(case (Cond) of
|
||||
true -> (TrueFun);
|
||||
false-> (FalseFun)
|
||||
end)).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,24 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% MQTT Protocol Header.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Protocol Header
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Protocol Version and Levels
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-define(MQTT_PROTO_V31, 3).
|
||||
-define(MQTT_PROTO_V311, 4).
|
||||
|
||||
|
|
@ -37,9 +28,9 @@
|
|||
|
||||
-type mqtt_vsn() :: ?MQTT_PROTO_V31 | ?MQTT_PROTO_V311.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT QoS
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-define(QOS_0, 0). %% At most once
|
||||
-define(QOS_1, 1). %% At least once
|
||||
-define(QOS_2, 2). %% Exactly once
|
||||
|
|
@ -71,15 +62,14 @@
|
|||
end)
|
||||
end).
|
||||
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Max ClientId Length. Why 1024? NiDongDe!
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Max ClientId Length. Why 1024? NiDongDe...
|
||||
%%--------------------------------------------------------------------
|
||||
-define(MAX_CLIENTID_LEN, 1024).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Control Packet Types
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-define(RESERVED, 0). %% Reserved
|
||||
-define(CONNECT, 1). %% Client request to connect to Server
|
||||
-define(CONNACK, 2). %% Server to Client: Connect acknowledgment
|
||||
|
|
@ -114,9 +104,9 @@
|
|||
|
||||
-type mqtt_packet_type() :: ?RESERVED..?DISCONNECT.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Connect Return Codes
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-define(CONNACK_ACCEPT, 0). %% Connection accepted
|
||||
-define(CONNACK_PROTO_VER, 1). %% Unacceptable protocol version
|
||||
-define(CONNACK_INVALID_ID, 2). %% Client Identifier is correct UTF-8 but not allowed by the Server
|
||||
|
|
@ -126,25 +116,25 @@
|
|||
|
||||
-type mqtt_connack() :: ?CONNACK_ACCEPT..?CONNACK_AUTH.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Parser and Serialiser
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Parser and Serializer
|
||||
%%--------------------------------------------------------------------
|
||||
-define(MAX_LEN, 16#fffffff).
|
||||
-define(HIGHBIT, 2#10000000).
|
||||
-define(LOWBITS, 2#01111111).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Packet Fixed Header
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_packet_header, {
|
||||
type = ?RESERVED :: mqtt_packet_type(),
|
||||
dup = false :: boolean(),
|
||||
qos = ?QOS_0 :: mqtt_qos(),
|
||||
retain = false :: boolean()}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Packets
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-type mqtt_client_id() :: binary().
|
||||
-type mqtt_packet_id() :: 1..16#ffff | undefined.
|
||||
|
||||
|
|
@ -188,9 +178,9 @@
|
|||
-record(mqtt_packet_unsuback, {
|
||||
packet_id :: mqtt_packet_id() }).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Control Packet
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-record(mqtt_packet, {
|
||||
header :: #mqtt_packet_header{},
|
||||
variable :: #mqtt_packet_connect{} | #mqtt_packet_connack{}
|
||||
|
|
@ -202,9 +192,9 @@
|
|||
|
||||
-type mqtt_packet() :: #mqtt_packet{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Packet Match
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
-define(CONNECT_PACKET(Var),
|
||||
#mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT}, variable = Var}).
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2016 Feng Lee <feng@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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-type trie_node_id() :: binary() | atom().
|
||||
|
||||
-record(trie_node, {
|
||||
node_id :: trie_node_id(),
|
||||
edge_count = 0 :: non_neg_integer(),
|
||||
topic :: binary() | undefined,
|
||||
flags :: [retained | static]
|
||||
}).
|
||||
|
||||
-record(trie_edge, {
|
||||
node_id :: trie_node_id(),
|
||||
word :: binary() | atom()
|
||||
}).
|
||||
|
||||
-record(trie, {
|
||||
edge :: #trie_edge{},
|
||||
node_id :: trie_node_id()
|
||||
}).
|
||||
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 2a1de2c79fe97a91b6c1e4da19af94273b874b21
|
||||
Subproject commit 18d36e902828f04fd7e72af581d0329ddd854d62
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit fc6ae569d7f13cbf547484a82502c1523894e181
|
||||
Subproject commit 4319d09935eead1d72b24088ac96dff0dd50ed80
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit b8934cf4d4eefba3e6e3ed35ab8ca55cf3ceaffd
|
||||
Subproject commit 5acb9f356a8413d196ac6b38dfa1971e46f4fff3
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit c6a532d49d2b479551bfd3b8d278d40c99e96ae3
|
||||
Subproject commit 831f718486d34e8d15c1bc0e93528b7a4449b278
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit b9a1296cbf3acb52e0f31db3ef14269bf920d076
|
||||
Subproject commit 821dccbd13e7fa34af7906da34454dacbd7115b3
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 287b0329bbc9fcbcfe64c5b67cd837ec61b36868
|
||||
Subproject commit 32cd9fd5413998aafeddd145f5569cf0d24bcd1d
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 42802eefadc235c5468cf4d1921fcb2e96f7d519
|
||||
Subproject commit 81136e0ed52a9f9bcf81d0ce1176cf0b0e456a1c
|
||||
23
rebar.config
23
rebar.config
|
|
@ -11,25 +11,32 @@
|
|||
{i, "include"},
|
||||
{src_dirs, ["src"]}]}.
|
||||
|
||||
{eunit_opts, [verbose]}.
|
||||
|
||||
{xref_checks, [undefined_function_calls]}.
|
||||
{cover_enabled, true}.
|
||||
|
||||
{validate_app_modules, true}.
|
||||
|
||||
{erl_first_files, ["src/gen_server2.erl",
|
||||
"src/emqttd_auth_mod.erl",
|
||||
"src/emqttd_acl_mod.erl"]}.
|
||||
|
||||
{eunit_opts, []}. %%verbose
|
||||
|
||||
{ct_dir, "test"}.
|
||||
|
||||
{ct_log_dir, "logs"}.
|
||||
|
||||
{ct_extra_params, "-name ct_emqttd@127.0.0.1 -config rel/files/test.config"}.
|
||||
|
||||
{ct_use_short_names, false}.
|
||||
|
||||
{xref_checks, [undefined_function_calls]}.
|
||||
|
||||
{cover_enabled, true}.
|
||||
|
||||
%% plugins cannot find emqttd.hrl without ".." lib dirs:(
|
||||
%% but this setting will make deps apps collision
|
||||
%% comment in 0.13.0 release
|
||||
%% {lib_dirs, ["../"]}.
|
||||
|
||||
{sub_dirs, [
|
||||
"rel",
|
||||
"plugins/*/"]}.
|
||||
{sub_dirs, ["rel", "plugins/*/"]}.
|
||||
|
||||
{deps, [
|
||||
{gproc, ".*", {git, "git://github.com/uwiger/gproc.git", {branch, "master"}}},
|
||||
|
|
|
|||
|
|
@ -69,9 +69,9 @@
|
|||
%% Packet
|
||||
{packet, [
|
||||
%% Max ClientId Length Allowed
|
||||
{max_clientid_len, 1024},
|
||||
{max_clientid_len, 512},
|
||||
%% Max Packet Size Allowed, 64K default
|
||||
{max_packet_size, 65536}
|
||||
{max_packet_size, 65536}
|
||||
]},
|
||||
%% Client
|
||||
{client, [
|
||||
|
|
@ -206,7 +206,7 @@
|
|||
{acceptors, 16},
|
||||
|
||||
%% Maximum number of concurrent clients
|
||||
{max_clients, 8192},
|
||||
{max_clients, 512},
|
||||
|
||||
%% Socket Access Control
|
||||
{access, [{allow, all}]},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,311 @@
|
|||
% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
|
||||
%% ex: ft=erlang ts=4 sw=4 et
|
||||
[{kernel, [
|
||||
{start_timer, true},
|
||||
{start_pg2, true}
|
||||
]},
|
||||
{sasl, [
|
||||
{sasl_error_logger, {file, "emqttd_sasl.log"}}
|
||||
]},
|
||||
{ssl, [
|
||||
%{versions, ['tlsv1.2', 'tlsv1.1']}
|
||||
]},
|
||||
{lager, [
|
||||
{colored, true},
|
||||
{async_threshold, 1000},
|
||||
{error_logger_redirect, false},
|
||||
{crash_log, "log/emqttd_crash.log"},
|
||||
{handlers, [
|
||||
{lager_console_backend, info},
|
||||
%%NOTICE: Level >= error
|
||||
%%{lager_emqtt_backend, error},
|
||||
{lager_file_backend, [
|
||||
{formatter_config, [time, " ", pid, " [",severity,"] ", message, "\n"]},
|
||||
{file, "log/emqttd_info.log"},
|
||||
{level, info},
|
||||
{size, 104857600},
|
||||
{date, "$D0"},
|
||||
{count, 30}
|
||||
]},
|
||||
{lager_file_backend, [
|
||||
{formatter_config, [time, " ", pid, " [",severity,"] ", message, "\n"]},
|
||||
{file, "log/emqttd_error.log"},
|
||||
{level, error},
|
||||
{size, 104857600},
|
||||
{date, "$D0"},
|
||||
{count, 30}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
{esockd, [
|
||||
{logger, {lager, info}}
|
||||
]},
|
||||
{emqttd, [
|
||||
%% Authentication and Authorization
|
||||
{access, [
|
||||
%% Authetication. Anonymous Default
|
||||
{auth, [
|
||||
%% Authentication with username, password
|
||||
%{username, []},
|
||||
|
||||
%% Authentication with clientid
|
||||
%{clientid, [{password, no}, {file, "etc/clients.config"}]},
|
||||
|
||||
%% Authentication with LDAP
|
||||
% {ldap, [
|
||||
% {servers, ["localhost"]},
|
||||
% {port, 389},
|
||||
% {timeout, 30},
|
||||
% {user_dn, "uid=$u,ou=People,dc=example,dc=com"},
|
||||
% {ssl, fasle},
|
||||
% {sslopts, [
|
||||
% {"certfile", "ssl.crt"},
|
||||
% {"keyfile", "ssl.key"}]}
|
||||
% ]},
|
||||
|
||||
%% Allow all
|
||||
{anonymous, []}
|
||||
]},
|
||||
%% ACL config
|
||||
{acl, [
|
||||
%% Internal ACL module
|
||||
%% {internal, [{file, "testdata/test_acl.config"}, {nomatch, allow}]}
|
||||
]}
|
||||
]},
|
||||
%% MQTT Protocol Options
|
||||
{mqtt, [
|
||||
%% Packet
|
||||
{packet, [
|
||||
%% Max ClientId Length Allowed
|
||||
{max_clientid_len, 1024},
|
||||
%% Max Packet Size Allowed, 64K default
|
||||
{max_packet_size, 65536}
|
||||
]},
|
||||
%% Client
|
||||
{client, [
|
||||
%% Socket is connected, but no 'CONNECT' packet received
|
||||
{idle_timeout, 10} %% seconds
|
||||
]},
|
||||
%% Session
|
||||
{session, [
|
||||
%% Max number of QoS 1 and 2 messages that can be “in flight” at one time.
|
||||
%% 0 means no limit
|
||||
{max_inflight, 100},
|
||||
|
||||
%% Retry interval for redelivering QoS1/2 messages.
|
||||
{unack_retry_interval, 20},
|
||||
|
||||
%% Awaiting PUBREL Timeout
|
||||
{await_rel_timeout, 20},
|
||||
|
||||
%% Max Packets that Awaiting PUBREL, 0 means no limit
|
||||
{max_awaiting_rel, 0},
|
||||
|
||||
%% Statistics Collection Interval(seconds)
|
||||
{collect_interval, 20},
|
||||
|
||||
%% Expired after 2 days
|
||||
{expired_after, 48}
|
||||
|
||||
]},
|
||||
%% Queue
|
||||
{queue, [
|
||||
%% simple | priority
|
||||
{type, simple},
|
||||
|
||||
%% Topic Priority: 0~255, Default is 0
|
||||
%% {priority, [{"topic/1", 10}, {"topic/2", 8}]},
|
||||
|
||||
%% Max queue length. Enqueued messages when persistent client disconnected,
|
||||
%% or inflight window is full.
|
||||
{max_length, infinity},
|
||||
|
||||
%% Low-water mark of queued messages
|
||||
{low_watermark, 0.2},
|
||||
|
||||
%% High-water mark of queued messages
|
||||
{high_watermark, 0.6},
|
||||
|
||||
%% Queue Qos0 messages?
|
||||
{queue_qos0, true}
|
||||
]}
|
||||
]},
|
||||
%% Broker Options
|
||||
{broker, [
|
||||
%% System interval of publishing broker $SYS messages
|
||||
{sys_interval, 60},
|
||||
|
||||
%% Retained messages
|
||||
{retained, [
|
||||
%% Expired after seconds, never expired if 0
|
||||
{expired_after, 0},
|
||||
|
||||
%% Max number of retained messages
|
||||
{max_message_num, 100000},
|
||||
|
||||
%% Max Payload Size of retained message
|
||||
{max_playload_size, 65536}
|
||||
]},
|
||||
|
||||
%% PubSub and Router
|
||||
{pubsub, [
|
||||
%% Default should be scheduler numbers
|
||||
{pool_size, 8},
|
||||
|
||||
%% Subscription: disc | ram | false
|
||||
{subscription, ram},
|
||||
|
||||
%% Route shard
|
||||
{route_shard, false},
|
||||
|
||||
%% Route delay, false | integer
|
||||
{route_delay, false},
|
||||
|
||||
%% Route aging time(seconds)
|
||||
{route_aging, 5}
|
||||
]},
|
||||
|
||||
%% Bridge
|
||||
{bridge, [
|
||||
%%TODO: bridge queue size
|
||||
{max_queue_len, 10000},
|
||||
|
||||
%% Ping Interval of bridge node
|
||||
{ping_down_interval, 1} %seconds
|
||||
]}
|
||||
]},
|
||||
%% Modules
|
||||
{modules, [
|
||||
%% Client presence management module.
|
||||
%% Publish messages when client connected or disconnected
|
||||
{presence, [{qos, 0}]},
|
||||
|
||||
%% Subscribe topics automatically when client connected
|
||||
{subscription, [
|
||||
%% Subscription from stored table
|
||||
stored,
|
||||
|
||||
%% $u will be replaced with username
|
||||
{"$Q/username/$u", 1},
|
||||
|
||||
%% $c will be replaced with clientid
|
||||
{"$Q/client/$c", 1}
|
||||
]}
|
||||
|
||||
%% Rewrite rules
|
||||
%% {rewrite, [{file, "etc/rewrite.config"}]}
|
||||
]},
|
||||
%% Plugins
|
||||
{plugins, [
|
||||
%% Plugin App Library Dir
|
||||
{plugins_dir, "./plugins"},
|
||||
|
||||
%% File to store loaded plugin names.
|
||||
{loaded_file, "./data/loaded_plugins"}
|
||||
]},
|
||||
|
||||
%% Listeners
|
||||
{listeners, [
|
||||
{mqtt, 1883, [
|
||||
%% Size of acceptor pool
|
||||
{acceptors, 16},
|
||||
|
||||
%% Maximum number of concurrent clients
|
||||
{max_clients, 512},
|
||||
|
||||
%% Socket Access Control
|
||||
{access, [{allow, all}]},
|
||||
|
||||
%% Connection Options
|
||||
{connopts, [
|
||||
%% Rate Limit. Format is 'burst, rate', Unit is KB/Sec
|
||||
%% {rate_limit, "100,10"} %% 100K burst, 10K rate
|
||||
]},
|
||||
|
||||
%% Socket Options
|
||||
{sockopts, [
|
||||
%Set buffer if hight thoughtput
|
||||
%{recbuf, 4096},
|
||||
%{sndbuf, 4096},
|
||||
%{buffer, 4096},
|
||||
%{nodelay, true},
|
||||
{backlog, 512}
|
||||
]}
|
||||
]},
|
||||
|
||||
{mqtts, 8883, [
|
||||
%% Size of acceptor pool
|
||||
{acceptors, 4},
|
||||
|
||||
%% Maximum number of concurrent clients
|
||||
{max_clients, 512},
|
||||
|
||||
%% Socket Access Control
|
||||
{access, [{allow, all}]},
|
||||
|
||||
%% SSL certificate and key files
|
||||
{ssl, [{certfile, "etc/ssl/ssl.crt"},
|
||||
{keyfile, "etc/ssl/ssl.key"}]},
|
||||
|
||||
%% Socket Options
|
||||
{sockopts, [
|
||||
{backlog, 1024}
|
||||
%{buffer, 4096},
|
||||
]}
|
||||
]},
|
||||
%% WebSocket over HTTPS Listener
|
||||
%% {https, 8083, [
|
||||
%% %% Size of acceptor pool
|
||||
%% {acceptors, 4},
|
||||
%% %% Maximum number of concurrent clients
|
||||
%% {max_clients, 512},
|
||||
%% %% Socket Access Control
|
||||
%% {access, [{allow, all}]},
|
||||
%% %% SSL certificate and key files
|
||||
%% {ssl, [{certfile, "etc/ssl/ssl.crt"},
|
||||
%% {keyfile, "etc/ssl/ssl.key"}]},
|
||||
%% %% Socket Options
|
||||
%% {sockopts, [
|
||||
%% %{buffer, 4096},
|
||||
%% {backlog, 1024}
|
||||
%% ]}
|
||||
%%]},
|
||||
|
||||
%% HTTP and WebSocket Listener
|
||||
{http, 8083, [
|
||||
%% Size of acceptor pool
|
||||
{acceptors, 4},
|
||||
%% Maximum number of concurrent clients
|
||||
{max_clients, 64},
|
||||
%% Socket Access Control
|
||||
{access, [{allow, all}]},
|
||||
%% Socket Options
|
||||
{sockopts, [
|
||||
{backlog, 1024}
|
||||
%{buffer, 4096},
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
|
||||
%% Erlang System Monitor
|
||||
{sysmon, [
|
||||
%% Long GC
|
||||
{long_gc, 100},
|
||||
|
||||
%% Long Schedule(ms)
|
||||
{long_schedule, 100},
|
||||
|
||||
%% 8M words. 32MB on 32-bit VM, 64MB on 64-bit VM.
|
||||
%% 8 * 1024 * 1024
|
||||
{large_heap, 8388608},
|
||||
|
||||
%% Busy Port
|
||||
{busy_port, true},
|
||||
|
||||
%% Busy Dist Port
|
||||
{busy_dist_port, true}
|
||||
|
||||
]}
|
||||
]}
|
||||
].
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
{application, emqttd,
|
||||
[
|
||||
{id, "emqttd"},
|
||||
{vsn, "0.15.0"},
|
||||
{description, "Erlang MQTT Broker"},
|
||||
{vsn, "0.16.0"},
|
||||
{id, "emqttd"},
|
||||
{modules, []},
|
||||
{registered, []},
|
||||
{applications, [kernel,
|
||||
|
|
|
|||
134
src/emqttd.erl
134
src/emqttd.erl
|
|
@ -1,38 +1,23 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd main module.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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).
|
||||
|
||||
-export([start/0, env/1, env/2,
|
||||
start_listeners/0, stop_listeners/0,
|
||||
load_all_mods/0, is_mod_enabled/1,
|
||||
is_running/1, seed_now/0]).
|
||||
|
||||
%% Utility functions.
|
||||
-export([reg_name/2]).
|
||||
-export([start/0, env/1, env/2, start_listeners/0, stop_listeners/0,
|
||||
load_all_mods/0, is_mod_enabled/1, is_running/1]).
|
||||
|
||||
-define(MQTT_SOCKOPTS, [
|
||||
binary,
|
||||
|
|
@ -45,86 +30,66 @@
|
|||
|
||||
-type listener() :: {atom(), inet:port_number(), [esockd:option()]}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start emqttd application.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start() -> ok | {error, any()}.
|
||||
start() ->
|
||||
application:start(?APP).
|
||||
start() -> application:start(?APP).
|
||||
|
||||
%% @doc Group environment
|
||||
-spec env(Group :: atom()) -> list().
|
||||
env(Group) -> application:get_env(?APP, Group, []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get environment
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec env(atom()) -> list().
|
||||
env(Group) ->
|
||||
application:get_env(?APP, Group, []).
|
||||
-spec env(Group :: atom(), Name :: atom()) -> undefined | any().
|
||||
env(Group, Name) -> proplists:get_value(Name, env(Group)).
|
||||
|
||||
-spec env(atom(), atom()) -> undefined | any().
|
||||
env(Group, Name) ->
|
||||
proplists:get_value(Name, env(Group)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start Listeners
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start Listeners of the broker.
|
||||
-spec start_listeners() -> any().
|
||||
start_listeners() ->
|
||||
{ok, Listeners} = application:get_env(?APP, listeners),
|
||||
lists:foreach(fun start_listener/1, Listeners).
|
||||
start_listeners() -> lists:foreach(fun start_listener/1, env(listeners)).
|
||||
|
||||
%% Start mqtt listener
|
||||
-spec start_listener(listener()) -> any().
|
||||
start_listener({mqtt, Port, Options}) ->
|
||||
start_listener(mqtt, Port, Options);
|
||||
start_listener({mqtt, Port, Opts}) -> start_listener(mqtt, Port, Opts);
|
||||
|
||||
%% Start mqtt(SSL) listener
|
||||
start_listener({mqtts, Port, Options}) ->
|
||||
start_listener(mqtts, Port, Options);
|
||||
start_listener({mqtts, Port, Opts}) -> start_listener(mqtts, Port, Opts);
|
||||
|
||||
%% Start http listener
|
||||
start_listener({http, Port, Options}) ->
|
||||
MFArgs = {emqttd_http, handle_request, []},
|
||||
mochiweb:start_http(Port, Options, MFArgs);
|
||||
start_listener({http, Port, Opts}) ->
|
||||
mochiweb:start_http(Port, Opts, {emqttd_http, handle_request, []});
|
||||
|
||||
%% Start https listener
|
||||
start_listener({https, Port, Options}) ->
|
||||
MFArgs = {emqttd_http, handle_request, []},
|
||||
mochiweb:start_http(Port, Options, MFArgs).
|
||||
start_listener({https, Port, Opts}) ->
|
||||
mochiweb:start_http(Port, Opts, {emqttd_http, handle_request, []}).
|
||||
|
||||
start_listener(Protocol, Port, Options) ->
|
||||
start_listener(Protocol, Port, Opts) ->
|
||||
MFArgs = {emqttd_client, start_link, [env(mqtt)]},
|
||||
esockd:open(Protocol, Port, merge_sockopts(Options) , MFArgs).
|
||||
esockd:open(Protocol, Port, merge_sockopts(Opts), MFArgs).
|
||||
|
||||
merge_sockopts(Options) ->
|
||||
SockOpts = emqttd_opts:merge(?MQTT_SOCKOPTS,
|
||||
proplists:get_value(sockopts, Options, [])),
|
||||
emqttd_opts:merge(Options, [{sockopts, SockOpts}]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Stop Listeners
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
stop_listeners() ->
|
||||
{ok, Listeners} = application:get_env(?APP, listeners),
|
||||
lists:foreach(fun stop_listener/1, Listeners).
|
||||
stop_listeners() -> lists:foreach(fun stop_listener/1, env(listeners)).
|
||||
|
||||
stop_listener({Protocol, Port, _Options}) ->
|
||||
esockd:close({Protocol, Port}).
|
||||
stop_listener({Protocol, Port, _Opts}) -> esockd:close({Protocol, Port}).
|
||||
|
||||
%% @doc load all modules
|
||||
load_all_mods() ->
|
||||
lists:foreach(fun load_mod/1, env(modules)).
|
||||
|
||||
load_mod({Name, Opts}) ->
|
||||
Mod = list_to_atom("emqttd_mod_" ++ atom_to_list(Name)),
|
||||
case catch Mod:load(Opts) of
|
||||
{ok, _State} -> lager:info("load module ~s successfully", [Name]);
|
||||
{'EXIT', Reason} -> lager:error("load module ~s error: ~p", [Name, Reason])
|
||||
ok -> lager:info("Load module ~s successfully", [Name]);
|
||||
{error, Error} -> lager:error("Load module ~s error: ~p", [Name, Error]);
|
||||
{'EXIT', Reason} -> lager:error("Load module ~s error: ~p", [Name, Reason])
|
||||
end.
|
||||
|
||||
is_mod_enabled(Name) ->
|
||||
env(modules, Name) =/= undefined.
|
||||
%% @doc Is module enabled?
|
||||
-spec is_mod_enabled(Name :: atom()) -> boolean().
|
||||
is_mod_enabled(Name) -> env(modules, Name) =/= undefined.
|
||||
|
||||
%% @doc Is running?
|
||||
-spec is_running(node()) -> boolean().
|
||||
|
|
@ -135,16 +100,3 @@ is_running(Node) ->
|
|||
Pid when is_pid(Pid) -> true
|
||||
end.
|
||||
|
||||
-spec reg_name(module(), pos_integer()) -> atom().
|
||||
reg_name(M, Id) when is_atom(M), is_integer(Id) ->
|
||||
list_to_atom(lists:concat([M, "_", Id])).
|
||||
|
||||
seed_now() ->
|
||||
case erlang:function_exported(erlang, timestamp, 0) of
|
||||
true -> %% R18
|
||||
random:seed(erlang:timestamp());
|
||||
false ->
|
||||
%% compress 'now()' warning...
|
||||
random:seed(os:timestamp())
|
||||
end.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Authentication and ACL Control Server
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_access_control).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -47,27 +38,24 @@
|
|||
|
||||
-define(ACCESS_CONTROL_TAB, mqtt_access_control).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
-type password() :: undefined | binary().
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start access control server
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(state, {}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Start access control server.
|
||||
-spec start_link() -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link() ->
|
||||
start_link(emqttd:env(access)).
|
||||
start_link() -> start_link(emqttd:env(access)).
|
||||
|
||||
-spec start_link(Opts :: list()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(Opts) ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Authenticate MQTT Client
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec auth(mqtt_client(), undefined | binary()) -> ok | {error, string()}.
|
||||
%% @doc Authenticate MQTT Client.
|
||||
-spec auth(Client :: mqtt_client(), Password :: password()) -> ok | {error, any()}.
|
||||
auth(Client, Password) when is_record(Client, mqtt_client) ->
|
||||
auth(Client, Password, lookup_mods(auth)).
|
||||
auth(_Client, _Password, []) ->
|
||||
|
|
@ -80,41 +68,32 @@ auth(Client, Password, [{Mod, State, _Seq} | Mods]) ->
|
|||
{'EXIT', Error} -> {error, Error}
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Check ACL
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec check_acl(Client, PubSub, Topic) -> allow | deny when
|
||||
Client :: mqtt_client(),
|
||||
PubSub :: pubsub(),
|
||||
Topic :: binary().
|
||||
check_acl(Client, PubSub, Topic) when ?IS_PUBSUB(PubSub) ->
|
||||
case lookup_mods(acl) of
|
||||
[] -> allow;
|
||||
[] -> allow;
|
||||
AclMods -> check_acl(Client, PubSub, Topic, AclMods)
|
||||
end.
|
||||
check_acl(#mqtt_client{client_id = ClientId}, PubSub, Topic, []) ->
|
||||
lager:error("ACL: nomatch when ~s ~s ~s", [ClientId, PubSub, Topic]),
|
||||
lager:error("ACL: nomatch for ~s ~s ~s", [ClientId, PubSub, Topic]),
|
||||
allow;
|
||||
check_acl(Client, PubSub, Topic, [{M, State, _Seq}|AclMods]) ->
|
||||
case M:check_acl({Client, PubSub, Topic}, State) of
|
||||
check_acl(Client, PubSub, Topic, [{Mod, State, _Seq}|AclMods]) ->
|
||||
case Mod:check_acl({Client, PubSub, Topic}, State) of
|
||||
allow -> allow;
|
||||
deny -> deny;
|
||||
ignore -> check_acl(Client, PubSub, Topic, AclMods)
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Reload ACL
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec reload_acl() -> list() | {error, any()}.
|
||||
%% @doc Reload ACL Rules.
|
||||
-spec reload_acl() -> list(ok | {error, any()}).
|
||||
reload_acl() ->
|
||||
[M:reload_acl(State) || {M, State, _Seq} <- lookup_mods(acl)].
|
||||
[Mod:reload_acl(State) || {Mod, State, _Seq} <- lookup_mods(acl)].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Register authentication or ACL module
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Register Authentication or ACL module.
|
||||
-spec register_mod(auth | acl, atom(), list()) -> ok | {error, any()}.
|
||||
register_mod(Type, Mod, Opts) when Type =:= auth; Type =:= acl->
|
||||
register_mod(Type, Mod, Opts, 0).
|
||||
|
|
@ -123,89 +102,71 @@ register_mod(Type, Mod, Opts) when Type =:= auth; Type =:= acl->
|
|||
register_mod(Type, Mod, Opts, Seq) when Type =:= auth; Type =:= acl->
|
||||
gen_server:call(?SERVER, {register_mod, Type, Mod, Opts, Seq}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unregister authentication or ACL module
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unregister_mod(Type :: auth | acl, Mod :: atom()) -> ok | {error, any()}.
|
||||
unregister_mod(Type, Mod) when Type =:= auth; Type =:= acl ->
|
||||
gen_server:call(?SERVER, {unregister_mod, Type, Mod}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup authentication or ACL modules
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup authentication or ACL modules.
|
||||
-spec lookup_mods(auth | acl) -> list().
|
||||
lookup_mods(Type) ->
|
||||
case ets:lookup(?ACCESS_CONTROL_TAB, tab_key(Type)) of
|
||||
[] -> [];
|
||||
[] -> [];
|
||||
[{_, Mods}] -> Mods
|
||||
end.
|
||||
|
||||
tab_key(auth) -> auth_modules;
|
||||
tab_key(acl) -> acl_modules.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Stop access control server
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
stop() ->
|
||||
gen_server:call(?MODULE, stop).
|
||||
%% @doc Stop access control server.
|
||||
stop() -> gen_server:call(?MODULE, stop).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Opts]) ->
|
||||
ets:new(?ACCESS_CONTROL_TAB, [set, named_table, protected, {read_concurrency, true}]),
|
||||
|
||||
ets:insert(?ACCESS_CONTROL_TAB, {auth_modules, init_mods(auth, proplists:get_value(auth, Opts))}),
|
||||
ets:insert(?ACCESS_CONTROL_TAB, {acl_modules, init_mods(acl, proplists:get_value(acl, Opts))}),
|
||||
{ok, state}.
|
||||
{ok, #state{}}.
|
||||
|
||||
init_mods(auth, AuthMods) ->
|
||||
[init_mod(fun authmod/1, Name, Opts) || {Name, Opts} <- AuthMods];
|
||||
[init_mod(authmod(Name), Opts) || {Name, Opts} <- AuthMods];
|
||||
|
||||
init_mods(acl, AclMods) ->
|
||||
[init_mod(fun aclmod/1, Name, Opts) || {Name, Opts} <- AclMods].
|
||||
[init_mod(aclmod(Name), Opts) || {Name, Opts} <- AclMods].
|
||||
|
||||
init_mod(Fun, Name, Opts) ->
|
||||
Module = Fun(Name),
|
||||
{ok, State} = Module:init(Opts),
|
||||
{Module, State, 0}.
|
||||
init_mod(Mod, Opts) ->
|
||||
{ok, State} = Mod:init(Opts), {Mod, State, 0}.
|
||||
|
||||
handle_call({register_mod, Type, Mod, Opts, Seq}, _From, State) ->
|
||||
Mods = lookup_mods(Type),
|
||||
Reply =
|
||||
case lists:keyfind(Mod, 1, Mods) of
|
||||
false ->
|
||||
case catch Mod:init(Opts) of
|
||||
{ok, ModState} ->
|
||||
NewMods =
|
||||
lists:sort(fun({_, _, Seq1}, {_, _, Seq2}) ->
|
||||
Seq1 >= Seq2
|
||||
end, [{Mod, ModState, Seq} | Mods]),
|
||||
ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), NewMods}),
|
||||
ok;
|
||||
{'EXIT', Error} ->
|
||||
lager:error("Access Control: register ~s error - ~p", [Mod, Error]),
|
||||
{error, Error}
|
||||
end;
|
||||
_ ->
|
||||
{error, existed}
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
Existed = lists:keyfind(Mod, 1, Mods),
|
||||
{reply, if_existed(Existed, fun() ->
|
||||
case catch Mod:init(Opts) of
|
||||
{ok, ModState} ->
|
||||
NewMods = lists:sort(fun({_, _, Seq1}, {_, _, Seq2}) ->
|
||||
Seq1 >= Seq2
|
||||
end, [{Mod, ModState, Seq} | Mods]),
|
||||
ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), NewMods}),
|
||||
ok;
|
||||
{error, Error} ->
|
||||
{error, Error};
|
||||
{'EXIT', Reason} ->
|
||||
{error, Reason}
|
||||
end
|
||||
end), State};
|
||||
|
||||
handle_call({unregister_mod, Type, Mod}, _From, State) ->
|
||||
Mods = lookup_mods(Type),
|
||||
Reply =
|
||||
case lists:keyfind(Mod, 1, Mods) of
|
||||
false ->
|
||||
{error, not_found};
|
||||
_ ->
|
||||
ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), lists:keydelete(Mod, 1, Mods)}), ok
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
false ->
|
||||
{reply, {error, not_found}, State};
|
||||
_ ->
|
||||
ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), lists:keydelete(Mod, 1, Mods)}),
|
||||
{reply, ok, State}
|
||||
end;
|
||||
|
||||
handle_call(stop, _From, State) ->
|
||||
{stop, normal, ok, State};
|
||||
|
|
@ -226,9 +187,9 @@ terminate(_Reason, _State) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
authmod(Name) when is_atom(Name) ->
|
||||
mod(emqttd_auth_, Name).
|
||||
|
|
@ -239,3 +200,6 @@ aclmod(Name) when is_atom(Name) ->
|
|||
mod(Prefix, Name) ->
|
||||
list_to_atom(lists:concat([Prefix, Name])).
|
||||
|
||||
if_existed(false, Fun) -> Fun();
|
||||
if_existed(true, _Fun) -> {error, existed}.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd ACL Rule
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_access_rule).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -47,10 +38,7 @@
|
|||
|
||||
-define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= deny))).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Compile access rule
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Compile Access Rule.
|
||||
compile({A, all}) when ?ALLOW_DENY(A) ->
|
||||
{A, all};
|
||||
|
||||
|
|
@ -96,10 +84,7 @@ bin(L) when is_list(L) ->
|
|||
bin(B) when is_binary(B) ->
|
||||
B.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Match rule
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Match Access Rule
|
||||
-spec match(mqtt_client(), topic(), rule()) -> {matched, allow} | {matched, deny} | nomatch.
|
||||
match(_Client, _Topic, {AllowDeny, all}) when (AllowDeny =:= allow) orelse (AllowDeny =:= deny) ->
|
||||
{matched, AllowDeny};
|
||||
|
|
|
|||
|
|
@ -1,36 +1,27 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Internal ACL that load rules from etc/acl.config
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_acl_internal).
|
||||
|
||||
-behaviour(emqttd_acl_mod).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-export([all_rules/0]).
|
||||
|
||||
-behaviour(emqttd_acl_mod).
|
||||
|
||||
%% ACL callbacks
|
||||
-export([init/1, check_acl/2, reload_acl/1, description/0]).
|
||||
|
||||
|
|
@ -38,14 +29,11 @@
|
|||
|
||||
-record(state, {acl_file, nomatch = allow}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Read all rules
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec all_rules() -> list(emqttd_access_rule:rule()).
|
||||
all_rules() ->
|
||||
case ets:lookup(?ACL_RULE_TAB, all_rules) of
|
||||
|
|
@ -53,21 +41,18 @@ all_rules() ->
|
|||
[{_, Rules}] -> Rules
|
||||
end.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% ACL callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% ACL callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Init internal ACL
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec init(AclOpts :: list()) -> {ok, State :: any()}.
|
||||
init(AclOpts) ->
|
||||
ets:new(?ACL_RULE_TAB, [set, public, named_table, {read_concurrency, true}]),
|
||||
AclFile = proplists:get_value(file, AclOpts),
|
||||
Default = proplists:get_value(nomatch, AclOpts, allow),
|
||||
State = #state{acl_file = AclFile, nomatch = Default},
|
||||
load_rules_from_file(State),
|
||||
true = load_rules_from_file(State),
|
||||
{ok, State}.
|
||||
|
||||
load_rules_from_file(#state{acl_file = AclFile}) ->
|
||||
|
|
@ -92,10 +77,7 @@ filter(subscribe, {_AllowDeny, _Who, subscribe, _Topics}) ->
|
|||
filter(_PubSub, {_AllowDeny, _Who, _, _Topics}) ->
|
||||
false.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Check ACL
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec check_acl({Client, PubSub, Topic}, State) -> allow | deny | ignore when
|
||||
Client :: mqtt_client(),
|
||||
PubSub :: pubsub(),
|
||||
|
|
@ -123,10 +105,7 @@ match(Client, Topic, [Rule|Rules]) ->
|
|||
{matched, AllowDeny} -> {matched, AllowDeny}
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Reload ACL
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec reload_acl(State :: #state{}) -> ok | {error, Reason :: any()}.
|
||||
reload_acl(State) ->
|
||||
case catch load_rules_from_file(State) of
|
||||
|
|
@ -134,10 +113,7 @@ reload_acl(State) ->
|
|||
_ -> ok
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc ACL Module Description
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec description() -> string().
|
||||
description() -> "Internal ACL with etc/acl.config".
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,26 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc ACL module behaviour
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_acl_mod).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
%%%=============================================================================
|
||||
%%% ACL behavihour
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% ACL behavihour
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-ifdef(use_specs).
|
||||
|
||||
|
|
@ -49,9 +40,9 @@
|
|||
-export([behaviour_info/1]).
|
||||
|
||||
behaviour_info(callbacks) ->
|
||||
[{init, 1}, {check_acl, 2}, {reload_acl, 1}, {description, 0}];
|
||||
[{init, 1}, {check_acl, 2}, {reload_acl, 1}, {description, 0}];
|
||||
behaviour_info(_Other) ->
|
||||
undefined.
|
||||
undefined.
|
||||
|
||||
-endif.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +1,25 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Copy alarm_handler
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_alarm).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-behaviour(gen_event).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-define(ALARM_MGR, ?MODULE).
|
||||
|
||||
%% API Function Exports
|
||||
|
|
@ -41,9 +32,9 @@
|
|||
-export([init/1, handle_event/2, handle_call/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
start_with(fun(Pid) -> gen_event:add_handler(Pid, ?MODULE, []) end).
|
||||
|
|
@ -54,8 +45,7 @@ start_with(Fun) ->
|
|||
Error -> Error
|
||||
end.
|
||||
|
||||
alarm_fun() ->
|
||||
alarm_fun(false).
|
||||
alarm_fun() -> alarm_fun(false).
|
||||
|
||||
alarm_fun(Bool) ->
|
||||
fun(alert, _Alarm) when Bool =:= true -> alarm_fun(true);
|
||||
|
|
@ -85,12 +75,11 @@ add_alarm_handler(Module, Args) when is_atom(Module) ->
|
|||
delete_alarm_handler(Module) when is_atom(Module) ->
|
||||
gen_event:delete_handler(?ALARM_MGR, Module, []).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Default Alarm handler
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Default Alarm handler
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init(_) ->
|
||||
{ok, []}.
|
||||
init(_) -> {ok, []}.
|
||||
|
||||
handle_event({set_alarm, Alarm = #mqtt_alarm{id = AlarmId,
|
||||
severity = Severity,
|
||||
|
|
@ -101,12 +90,12 @@ handle_event({set_alarm, Alarm = #mqtt_alarm{id = AlarmId,
|
|||
{severity, Severity},
|
||||
{title, iolist_to_binary(Title)},
|
||||
{summary, iolist_to_binary(Summary)},
|
||||
{ts, emqttd_util:now_to_secs(Timestamp)}]),
|
||||
{ts, emqttd_time:now_to_secs(Timestamp)}]),
|
||||
emqttd_pubsub:publish(alarm_msg(alert, AlarmId, Json)),
|
||||
{ok, [Alarm#mqtt_alarm{timestamp = Timestamp} | Alarms]};
|
||||
|
||||
handle_event({clear_alarm, AlarmId}, Alarms) ->
|
||||
Json = mochijson2:encode([{id, AlarmId}, {ts, emqttd_util:now_to_secs()}]),
|
||||
Json = mochijson2:encode([{id, AlarmId}, {ts, emqttd_time:now_to_secs()}]),
|
||||
emqttd_pubsub:publish(alarm_msg(clear, AlarmId, Json)),
|
||||
{ok, lists:keydelete(AlarmId, 2, Alarms), hibernate};
|
||||
|
||||
|
|
@ -131,9 +120,9 @@ terminate(_, _) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
alarm_msg(Type, AlarmId, Json) ->
|
||||
Msg = emqttd_message:make(alarm,
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd application.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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).
|
||||
|
||||
-include("emqttd_cli.hrl").
|
||||
|
|
@ -32,9 +23,9 @@
|
|||
%% Application callbacks
|
||||
-export([start/2, stop/1]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Application callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Application callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-spec start(StartType, StartArgs) -> {ok, pid()} | {ok, pid(), State} | {error, Reason} when
|
||||
StartType :: normal | {takeover, node()} | {failover, node()},
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Anonymous Authentication Module
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Anonymous Authentication Module
|
||||
-module(emqttd_auth_anonymous).
|
||||
|
||||
-behaviour(emqttd_auth_mod).
|
||||
|
|
|
|||
|
|
@ -1,34 +1,24 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc ClientId Authentication Module
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_auth_clientid).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-export([add_clientid/1, add_clientid/2,
|
||||
lookup_clientid/1, remove_clientid/1,
|
||||
-export([add_clientid/1, add_clientid/2, lookup_clientid/1, remove_clientid/1,
|
||||
all_clientids/0]).
|
||||
|
||||
-behaviour(emqttd_auth_mod).
|
||||
|
|
@ -40,87 +30,71 @@
|
|||
|
||||
-record(?AUTH_CLIENTID_TAB, {client_id, ipaddr, password}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Add clientid
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec add_clientid(binary()) -> {atomic, ok} | {aborted, any()}.
|
||||
add_clientid(ClientId) when is_binary(ClientId) ->
|
||||
R = #mqtt_auth_clientid{client_id = ClientId},
|
||||
mnesia:transaction(fun mnesia:write/1, [R]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Add clientid with password
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec add_clientid(binary(), binary()) -> {atomic, ok} | {aborted, any()}.
|
||||
add_clientid(ClientId, Password) ->
|
||||
R = #mqtt_auth_clientid{client_id = ClientId, password = Password},
|
||||
mnesia:transaction(fun mnesia:write/1, [R]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup clientid
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup_clientid(binary()) -> list().
|
||||
-spec lookup_clientid(binary()) -> list(#mqtt_auth_clientid{}).
|
||||
lookup_clientid(ClientId) ->
|
||||
mnesia:dirty_read(?AUTH_CLIENTID_TAB, ClientId).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup all clientids
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec all_clientids() -> list(binary()).
|
||||
all_clientids() ->
|
||||
mnesia:dirty_all_keys(?AUTH_CLIENTID_TAB).
|
||||
all_clientids() -> mnesia:dirty_all_keys(?AUTH_CLIENTID_TAB).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Remove clientid
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec remove_clientid(binary()) -> {atomic, ok} | {aborted, any()}.
|
||||
remove_clientid(ClientId) ->
|
||||
mnesia:transaction(fun mnesia:delete/1, [{?AUTH_CLIENTID_TAB, ClientId}]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% emqttd_auth_mod callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% emqttd_auth_mod callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init(Opts) ->
|
||||
mnesia:create_table(?AUTH_CLIENTID_TAB, [
|
||||
{ram_copies, [node()]},
|
||||
{attributes, record_info(fields, ?AUTH_CLIENTID_TAB)}]),
|
||||
mnesia:add_table_copy(?AUTH_CLIENTID_TAB, node(), ram_copies),
|
||||
case proplists:get_value(file, Opts) of
|
||||
undefined -> ok;
|
||||
File -> load(File)
|
||||
end,
|
||||
load(proplists:get_value(file, Opts)),
|
||||
{ok, Opts}.
|
||||
|
||||
check(#mqtt_client{client_id = undefined}, _Password, []) ->
|
||||
{error, "ClientId undefined"};
|
||||
check(#mqtt_client{client_id = undefined}, _Password, _Opts) ->
|
||||
{error, clientid_undefined};
|
||||
check(#mqtt_client{client_id = ClientId, peername = {IpAddress, _}}, _Password, []) ->
|
||||
check_clientid_only(ClientId, IpAddress);
|
||||
check(#mqtt_client{client_id = ClientId, peername = {IpAddress, _}}, _Password, [{password, no}|_]) ->
|
||||
check_clientid_only(ClientId, IpAddress);
|
||||
check(_Client, undefined, [{password, yes}|_]) ->
|
||||
{error, "Password undefined"};
|
||||
{error, password_undefined};
|
||||
check(#mqtt_client{client_id = ClientId}, Password, [{password, yes}|_]) ->
|
||||
case mnesia:dirty_read(?AUTH_CLIENTID_TAB, ClientId) of
|
||||
[] -> {error, "ClientId Not Found"};
|
||||
[] -> {error, clientid_not_found};
|
||||
[#?AUTH_CLIENTID_TAB{password = Password}] -> ok; %% TODO: plaintext??
|
||||
_ -> {error, "Password Not Right"}
|
||||
_ -> {error, password_error}
|
||||
end.
|
||||
|
||||
description() -> "ClientId authentication module".
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
load(undefined) ->
|
||||
ok;
|
||||
|
||||
load(File) ->
|
||||
{ok, Fd} = file:open(File, [read]),
|
||||
|
|
@ -149,13 +123,13 @@ load(Fd, eof, Clients) ->
|
|||
|
||||
check_clientid_only(ClientId, IpAddr) ->
|
||||
case mnesia:dirty_read(?AUTH_CLIENTID_TAB, ClientId) of
|
||||
[] -> {error, "ClientId Not Found"};
|
||||
[] -> {error, clientid_not_found};
|
||||
[#?AUTH_CLIENTID_TAB{ipaddr = undefined}] -> ok;
|
||||
[#?AUTH_CLIENTID_TAB{ipaddr = {_, {Start, End}}}] ->
|
||||
I = esockd_access:atoi(IpAddr),
|
||||
case I >= Start andalso I =< End of
|
||||
true -> ok;
|
||||
false -> {error, "ClientId with wrong IP address"}
|
||||
true -> ok;
|
||||
false -> {error, wrong_ipaddr}
|
||||
end
|
||||
end.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc LDAP Authentication Module
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 LDAP Authentication Module
|
||||
-module(emqttd_auth_ldap).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -51,11 +43,11 @@ init(Opts) ->
|
|||
{ok, #state{servers = Servers, user_dn = UserDn, options = LdapOpts}}.
|
||||
|
||||
check(#mqtt_client{username = undefined}, _Password, _State) ->
|
||||
{error, "Username undefined"};
|
||||
{error, username_undefined};
|
||||
check(_Client, undefined, _State) ->
|
||||
{error, "Password undefined"};
|
||||
{error, password_undefined};
|
||||
check(_Client, <<>>, _State) ->
|
||||
{error, "Password undefined"};
|
||||
{error, password_undefined};
|
||||
check(#mqtt_client{username = Username}, Password,
|
||||
#state{servers = Servers, user_dn = UserDn, options = Options}) ->
|
||||
case eldap:open(Servers, Options) of
|
||||
|
|
@ -71,7 +63,7 @@ ldap_bind(LDAP, UserDn, Password) ->
|
|||
ok ->
|
||||
ok;
|
||||
{error, invalidCredentials} ->
|
||||
{error, "LDAP Invalid Credentials"};
|
||||
{error, invalid_credentials};
|
||||
{error, Error} ->
|
||||
{error, Error};
|
||||
{'EXIT', Reason} ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd Authentication Behaviour
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Authentication Behaviour.
|
||||
-module(emqttd_auth_mod).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -31,9 +23,9 @@
|
|||
|
||||
-type hash_type() :: plain | md5 | sha | sha256.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Auth behavihour
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Authentication behavihour
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-ifdef(use_specs).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Authentication with username and password
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Authentication with username and password
|
||||
-module(emqttd_auth_username).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -44,63 +36,54 @@
|
|||
|
||||
-record(?AUTH_USERNAME_TAB, {username, password}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% CLI
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% CLI
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
cli(["add", Username, Password]) ->
|
||||
?PRINT("~p~n", [add_user(list_to_binary(Username), list_to_binary(Password))]);
|
||||
?PRINT("~p~n", [add_user(iolist_to_binary(Username), iolist_to_binary(Password))]);
|
||||
|
||||
cli(["del", Username]) ->
|
||||
?PRINT("~p~n", [remove_user(list_to_binary(Username))]);
|
||||
?PRINT("~p~n", [remove_user(iolist_to_binary(Username))]);
|
||||
|
||||
cli(_) ->
|
||||
?USAGE([{"users add <Username> <Password>", "add user"},
|
||||
{"users del <Username>", "delete user"}]).
|
||||
?USAGE([{"users add <Username> <Password>", "Add User"},
|
||||
{"users del <Username>", "Delete User"}]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Add user
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec add_user(binary(), binary()) -> {atomic, ok} | {aborted, any()}.
|
||||
%% @doc Add User
|
||||
-spec add_user(binary(), binary()) -> ok | {error, any()}.
|
||||
add_user(Username, Password) ->
|
||||
User = #?AUTH_USERNAME_TAB{username = Username, password = hash(Password)},
|
||||
mnesia:transaction(fun mnesia:write/1, [User]).
|
||||
ret(mnesia:transaction(fun mnesia:write/1, [User])).
|
||||
|
||||
add_default_user(Username, Password) ->
|
||||
add_user(bin(Username), bin(Password)).
|
||||
add_user(iolist_to_binary(Username), iolist_to_binary(Password)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup user by username
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup_user(binary()) -> list().
|
||||
lookup_user(Username) ->
|
||||
mnesia:dirty_read(?AUTH_USERNAME_TAB, Username).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Remove user
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec remove_user(binary()) -> {atomic, ok} | {aborted, any()}.
|
||||
-spec remove_user(binary()) -> ok | {error, any()}.
|
||||
remove_user(Username) ->
|
||||
mnesia:transaction(fun mnesia:delete/1, [{?AUTH_USERNAME_TAB, Username}]).
|
||||
ret(mnesia:transaction(fun mnesia:delete/1, [{?AUTH_USERNAME_TAB, Username}])).
|
||||
|
||||
ret({atomic, ok}) -> ok;
|
||||
ret({aborted, Error}) -> {error, Error}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc All usernames
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec all_users() -> list().
|
||||
all_users() ->
|
||||
mnesia:dirty_all_keys(?AUTH_USERNAME_TAB).
|
||||
all_users() -> mnesia:dirty_all_keys(?AUTH_USERNAME_TAB).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% emqttd_auth_mod callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%%=============================================================================
|
||||
%%% emqttd_auth callbacks
|
||||
%%%=============================================================================
|
||||
init(DefautUsers) ->
|
||||
mnesia:create_table(?AUTH_USERNAME_TAB, [
|
||||
{disc_copies, [node()]},
|
||||
|
|
@ -113,40 +96,33 @@ init(DefautUsers) ->
|
|||
{ok, []}.
|
||||
|
||||
check(#mqtt_client{username = undefined}, _Password, _Opts) ->
|
||||
{error, "Username undefined"};
|
||||
{error, username_undefined};
|
||||
check(_User, undefined, _Opts) ->
|
||||
{error, "Password undefined"};
|
||||
{error, password_undefined};
|
||||
check(#mqtt_client{username = Username}, Password, _Opts) ->
|
||||
case mnesia:dirty_read(?AUTH_USERNAME_TAB, Username) of
|
||||
[] ->
|
||||
{error, "Username Not Found"};
|
||||
{error, username_not_found};
|
||||
[#?AUTH_USERNAME_TAB{password = <<Salt:4/binary, Hash/binary>>}] ->
|
||||
case Hash =:= md5_hash(Salt, Password) of
|
||||
true -> ok;
|
||||
false -> {error, "Password Not Right"}
|
||||
false -> {error, password_error}
|
||||
end
|
||||
end.
|
||||
|
||||
description() ->
|
||||
"Username password authentication module".
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
hash(Password) ->
|
||||
SaltBin = salt(),
|
||||
<<SaltBin/binary, (md5_hash(SaltBin, Password))/binary>>.
|
||||
SaltBin = salt(), <<SaltBin/binary, (md5_hash(SaltBin, Password))/binary>>.
|
||||
|
||||
md5_hash(SaltBin, Password) ->
|
||||
erlang:md5(<<SaltBin/binary, Password/binary>>).
|
||||
|
||||
salt() ->
|
||||
emqttd:seed_now(),
|
||||
Salt = random:uniform(16#ffffffff),
|
||||
<<Salt:32>>.
|
||||
|
||||
bin(A) when is_atom(A) -> bin(atom_to_list(A));
|
||||
bin(L) when is_list(L) -> list_to_binary(L);
|
||||
bin(B) when is_binary(B) -> B.
|
||||
emqttd_time:seed(), Salt = random:uniform(16#ffffffff), <<Salt:32>>.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_boot).
|
||||
|
||||
-export([apply_module_attributes/1, all_module_attributes/1]).
|
||||
|
||||
%% only {F, Args}...
|
||||
apply_module_attributes(Name) ->
|
||||
[{Module, [apply(Module, F, Args) || {F, Args} <- Attrs]} ||
|
||||
{_App, Module, Attrs} <- all_module_attributes(Name)].
|
||||
|
||||
%% Copy from rabbit_misc.erl
|
||||
all_module_attributes(Name) ->
|
||||
Targets =
|
||||
lists:usort(
|
||||
lists:append(
|
||||
[[{App, Module} || Module <- Modules] ||
|
||||
{App, _, _} <- ignore_lib_apps(application:loaded_applications()),
|
||||
{ok, Modules} <- [application:get_key(App, modules)]])),
|
||||
lists:foldl(
|
||||
fun ({App, Module}, Acc) ->
|
||||
case lists:append([Atts || {N, Atts} <- module_attributes(Module),
|
||||
N =:= Name]) of
|
||||
[] -> Acc;
|
||||
Atts -> [{App, Module, Atts} | Acc]
|
||||
end
|
||||
end, [], Targets).
|
||||
|
||||
%% Copy from rabbit_misc.erl
|
||||
module_attributes(Module) ->
|
||||
case catch Module:module_info(attributes) of
|
||||
{'EXIT', {undef, [{Module, module_info, [attributes], []} | _]}} ->
|
||||
[];
|
||||
{'EXIT', Reason} ->
|
||||
exit(Reason);
|
||||
V ->
|
||||
V
|
||||
end.
|
||||
|
||||
ignore_lib_apps(Apps) ->
|
||||
LibApps = [kernel, stdlib, sasl, appmon, eldap, erts,
|
||||
syntax_tools, ssl, crypto, mnesia, os_mon,
|
||||
inets, goldrush, lager, gproc, runtime_tools,
|
||||
snmp, otp_mibs, public_key, asn1, ssh, hipe,
|
||||
common_test, observer, webtool, xmerl, tools,
|
||||
test_server, compiler, debugger, eunit, et,
|
||||
gen_logger, wx],
|
||||
[App || App = {Name, _, _} <- Apps, not lists:member(Name, LibApps)].
|
||||
|
||||
|
|
@ -1,30 +1,23 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd bridge
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_bridge).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_protocol.hrl").
|
||||
|
|
@ -34,8 +27,6 @@
|
|||
%% API Function Exports
|
||||
-export([start_link/3]).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
|
@ -59,32 +50,29 @@
|
|||
|
||||
-export_type([option/0]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a bridge
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(atom(), binary(), [option()]) -> {ok, pid()} | ignore | {error, term()}.
|
||||
start_link(Node, SubTopic, Options) ->
|
||||
gen_server:start_link(?MODULE, [Node, SubTopic, Options], []).
|
||||
start_link(Node, Topic, Options) ->
|
||||
gen_server2:start_link(?MODULE, [Node, Topic, Options], []).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Node, SubTopic, Options]) ->
|
||||
init([Node, Topic, Options]) ->
|
||||
process_flag(trap_exit, true),
|
||||
case net_kernel:connect_node(Node) of
|
||||
true ->
|
||||
true = erlang:monitor_node(Node, true),
|
||||
State = parse_opts(Options, #state{node = Node, subtopic = SubTopic}),
|
||||
MQueue = emqttd_mqueue:new(qname(Node, SubTopic),
|
||||
State = parse_opts(Options, #state{node = Node, subtopic = Topic}),
|
||||
MQueue = emqttd_mqueue:new(qname(Node, Topic),
|
||||
[{max_len, State#state.max_queue_len}],
|
||||
emqttd_alarm:alarm_fun()),
|
||||
emqttd_pubsub:subscribe({SubTopic, State#state.qos}),
|
||||
emqttd_pubsub:subscribe({Topic, State#state.qos}),
|
||||
{ok, State#state{mqueue = MQueue}};
|
||||
false ->
|
||||
{stop, {cannot_connect, Node}}
|
||||
|
|
@ -105,10 +93,10 @@ parse_opts([{ping_down_interval, Interval} | Opts], State) ->
|
|||
parse_opts([_Opt | Opts], State) ->
|
||||
parse_opts(Opts, State).
|
||||
|
||||
qname(Node, SubTopic) when is_atom(Node) ->
|
||||
qname(atom_to_list(Node), SubTopic);
|
||||
qname(Node, SubTopic) ->
|
||||
list_to_binary(["Bridge:", Node, ":", SubTopic]).
|
||||
qname(Node, Topic) when is_atom(Node) ->
|
||||
qname(atom_to_list(Node), Topic);
|
||||
qname(Node, Topic) ->
|
||||
iolist_to_binary(["Bridge:", Node, ":", Topic]).
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
?UNEXPECTED_REQ(Req, State).
|
||||
|
|
@ -163,9 +151,9 @@ terminate(_Reason, _State) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
dequeue(State = #state{mqueue = MQ}) ->
|
||||
case emqttd_mqueue:out(MQ) of
|
||||
|
|
|
|||
|
|
@ -1,103 +1,73 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Bridge Supervisor
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_bridge_sup).
|
||||
|
||||
-behavior(supervisor).
|
||||
|
||||
-export([start_link/0,
|
||||
bridges/0,
|
||||
start_bridge/2, start_bridge/3,
|
||||
stop_bridge/2]).
|
||||
-export([start_link/0, bridges/0, start_bridge/2, start_bridge/3, stop_bridge/2]).
|
||||
|
||||
-export([init/1]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
-define(BRIDGE_ID(Node, Topic), {bridge, Node, Topic}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start bridge supervisor
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc List all bridges
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec bridges() -> [{tuple(), pid()}].
|
||||
bridges() ->
|
||||
[{{Node, SubTopic}, Pid} || {{bridge, Node, SubTopic}, Pid, worker, _}
|
||||
<- supervisor:which_children(?MODULE)].
|
||||
[{{Node, Topic}, Pid} || {?BRIDGE_ID(Node, Topic), Pid, worker, _}
|
||||
<- supervisor:which_children(?MODULE)].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a bridge
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_bridge(atom(), binary()) -> {ok, pid()} | {error, any()}.
|
||||
start_bridge(Node, SubTopic) when is_atom(Node) and is_binary(SubTopic) ->
|
||||
start_bridge(Node, SubTopic, []).
|
||||
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()}.
|
||||
start_bridge(Node, SubTopic, Options) when is_atom(Node) and is_binary(SubTopic) ->
|
||||
case Node =:= node() of
|
||||
true ->
|
||||
{error, bridge_to_self};
|
||||
false ->
|
||||
Options1 = emqttd_opts:merge(emqttd_broker:env(bridge), Options),
|
||||
supervisor:start_child(?MODULE, bridge_spec(Node, SubTopic, Options1))
|
||||
end.
|
||||
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) ->
|
||||
Options1 = emqttd_opts:merge(emqttd_broker:env(bridge), Options),
|
||||
supervisor:start_child(?MODULE, bridge_spec(Node, Topic, Options1)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Stop a bridge
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec stop_bridge(atom(), binary()) -> {ok, pid()} | ok.
|
||||
stop_bridge(Node, SubTopic) ->
|
||||
ChildId = bridge_id(Node, SubTopic),
|
||||
stop_bridge(Node, Topic) when is_atom(Node) andalso is_binary(Topic) ->
|
||||
ChildId = ?BRIDGE_ID(Node, Topic),
|
||||
case supervisor:terminate_child(?MODULE, ChildId) of
|
||||
ok ->
|
||||
supervisor:delete_child(?MODULE, ChildId);
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
ok -> supervisor:delete_child(?MODULE, ChildId);
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Supervisor callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_one, 10, 100}, []}}.
|
||||
|
||||
bridge_id(Node, SubTopic) ->
|
||||
{bridge, Node, SubTopic}.
|
||||
|
||||
bridge_spec(Node, SubTopic, Options) ->
|
||||
ChildId = bridge_id(Node, SubTopic),
|
||||
{ChildId, {emqttd_bridge, start_link, [Node, SubTopic, Options]},
|
||||
bridge_spec(Node, Topic, Options) ->
|
||||
ChildId = ?BRIDGE_ID(Node, Topic),
|
||||
{ChildId, {emqttd_bridge, start_link, [Node, Topic, Options]},
|
||||
transient, 10000, worker, [emqttd_bridge]}.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd broker
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_broker).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -34,9 +25,6 @@
|
|||
%% API Function Exports
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Running nodes
|
||||
-export([running_nodes/0]).
|
||||
|
||||
%% Event API
|
||||
-export([subscribe/1, notify/2]).
|
||||
|
||||
|
|
@ -67,78 +55,44 @@
|
|||
sysdescr % Broker description
|
||||
]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start emqttd broker
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link() -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get running nodes
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec running_nodes() -> list(node()).
|
||||
running_nodes() ->
|
||||
mnesia:system_info(running_db_nodes).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Subscribe broker event
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec subscribe(EventType :: any()) -> ok.
|
||||
subscribe(EventType) ->
|
||||
gproc:reg({p, l, {broker, EventType}}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Notify broker event
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec notify(EventType :: any(), Event :: any()) -> ok.
|
||||
notify(EventType, Event) ->
|
||||
Key = {broker, EventType},
|
||||
gproc:send({p, l, Key}, {self(), Key, Event}).
|
||||
gproc:send({p, l, {broker, EventType}}, {notify, EventType, self(), Event}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get broker env
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
env(Name) ->
|
||||
proplists:get_value(Name, emqttd:env(broker)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get broker version
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec version() -> string().
|
||||
version() ->
|
||||
{ok, Version} = application:get_key(emqttd, vsn), Version.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get broker description
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec sysdescr() -> string().
|
||||
sysdescr() ->
|
||||
{ok, Descr} = application:get_key(emqttd, description), Descr.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get broker uptime
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec uptime() -> string().
|
||||
uptime() ->
|
||||
gen_server:call(?SERVER, uptime).
|
||||
uptime() -> gen_server:call(?SERVER, uptime).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get broker datetime
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec datetime() -> string().
|
||||
datetime() ->
|
||||
{{Y, M, D}, {H, MM, S}} = calendar:local_time(),
|
||||
|
|
@ -146,26 +100,17 @@ datetime() ->
|
|||
io_lib:format(
|
||||
"~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", [Y, M, D, H, MM, S])).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Hook
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec hook(Hook :: atom(), Name :: any(), MFA :: mfa()) -> ok | {error, any()}.
|
||||
hook(Hook, Name, MFA) ->
|
||||
gen_server:call(?SERVER, {hook, Hook, Name, MFA}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unhook
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unhook(Hook :: atom(), Name :: any()) -> ok | {error, any()}.
|
||||
unhook(Hook, Name) ->
|
||||
gen_server:call(?SERVER, {unhook, Hook, Name}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Foreach hooks
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec foreach_hooks(Hook :: atom(), Args :: list()) -> any().
|
||||
foreach_hooks(Hook, Args) ->
|
||||
case ets:lookup(?BROKER_TAB, {hook, Hook}) of
|
||||
|
|
@ -177,10 +122,7 @@ foreach_hooks(Hook, Args) ->
|
|||
ok
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Foldl hooks
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec foldl_hooks(Hook :: atom(), Args :: list(), Acc0 :: any()) -> any().
|
||||
foldl_hooks(Hook, Args, Acc0) ->
|
||||
case ets:lookup(?BROKER_TAB, {hook, Hook}) of
|
||||
|
|
@ -192,10 +134,7 @@ foldl_hooks(Hook, Args, Acc0) ->
|
|||
Acc0
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a tick timer
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
start_tick(Msg) ->
|
||||
start_tick(timer:seconds(env(sys_interval)), Msg).
|
||||
|
||||
|
|
@ -204,21 +143,18 @@ start_tick(0, _Msg) ->
|
|||
start_tick(Interval, Msg) when Interval > 0 ->
|
||||
{ok, TRef} = timer:send_interval(Interval, Msg), TRef.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start tick timer
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
stop_tick(undefined) ->
|
||||
ok;
|
||||
stop_tick(TRef) ->
|
||||
timer:cancel(TRef).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
emqttd:seed_now(),
|
||||
emqttd_time:seed(),
|
||||
ets:new(?BROKER_TAB, [set, public, named_table]),
|
||||
% Create $SYS Topics
|
||||
emqttd_pubsub:create(topic, <<"$SYS/brokers">>),
|
||||
|
|
@ -234,24 +170,24 @@ handle_call(uptime, _From, State) ->
|
|||
handle_call({hook, Hook, Name, MFArgs}, _From, State) ->
|
||||
Key = {hook, Hook}, Reply =
|
||||
case ets:lookup(?BROKER_TAB, Key) of
|
||||
[{Key, Hooks}] ->
|
||||
[{Key, Hooks}] ->
|
||||
case lists:keyfind(Name, 1, Hooks) of
|
||||
{Name, _MFArgs} ->
|
||||
{error, existed};
|
||||
false ->
|
||||
ets:insert(?BROKER_TAB, {Key, Hooks ++ [{Name, MFArgs}]})
|
||||
insert_hooks(Key, Hooks ++ [{Name, MFArgs}])
|
||||
end;
|
||||
[] ->
|
||||
ets:insert(?BROKER_TAB, {Key, [{Name, MFArgs}]})
|
||||
[] ->
|
||||
insert_hooks(Key, [{Name, MFArgs}])
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
|
||||
handle_call({unhook, Hook, Name}, _From, State) ->
|
||||
Key = {hook, Hook}, Reply =
|
||||
case ets:lookup(?BROKER_TAB, Key) of
|
||||
[{Key, Hooks}] ->
|
||||
ets:insert(?BROKER_TAB, {Key, lists:keydelete(Name, 1, Hooks)});
|
||||
[] ->
|
||||
[{Key, Hooks}] ->
|
||||
insert_hooks(Key, lists:keydelete(Name, 1, Hooks));
|
||||
[] ->
|
||||
{error, not_found}
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
|
|
@ -284,15 +220,19 @@ terminate(_Reason, #state{heartbeat = Hb, tick_tref = TRef}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
insert_hooks(Key, Hooks) ->
|
||||
ets:insert(?BROKER_TAB, {Key, Hooks}), ok.
|
||||
|
||||
create_topic(Topic) ->
|
||||
emqttd_pubsub:create(topic, emqttd_topic:systop(Topic)).
|
||||
|
||||
retain(brokers) ->
|
||||
Payload = list_to_binary(string:join([atom_to_list(N) || N <- running_nodes()], ",")),
|
||||
Payload = list_to_binary(string:join([atom_to_list(N) ||
|
||||
N <- emqttd_mnesia:running_nodes()], ",")),
|
||||
Msg = emqttd_message:make(broker, <<"$SYS/brokers">>, Payload),
|
||||
emqttd_pubsub:publish(emqttd_message:set_flag(sys, Msg)).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd cli
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_cli).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -60,14 +51,12 @@ load() ->
|
|||
is_cmd(Fun) ->
|
||||
not lists:member(Fun, [init, load, module_info]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Commands
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Commands
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Node status
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
status([]) ->
|
||||
{InternalStatus, _ProvidedStatus} = init:get_status(),
|
||||
?PRINT("Node ~p is ~p~n", [node(), InternalStatus]),
|
||||
|
|
@ -80,10 +69,8 @@ status([]) ->
|
|||
status(_) ->
|
||||
?PRINT_CMD("status", "query broker status").
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Query broker
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
broker([]) ->
|
||||
Funs = [sysdescr, version, uptime, datetime],
|
||||
foreach(fun(Fun) ->
|
||||
|
|
@ -116,61 +103,48 @@ broker(_) ->
|
|||
{"broker stats", "query broker statistics of clients, topics, subscribers"},
|
||||
{"broker metrics", "query broker metrics"}]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Cluster with other node
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
cluster([]) ->
|
||||
Nodes = emqttd_broker:running_nodes(),
|
||||
?PRINT("cluster nodes: ~p~n", [Nodes]);
|
||||
|
||||
cluster(usage) ->
|
||||
?PRINT_CMD("cluster [<Node>]", "cluster with node, query cluster info");
|
||||
|
||||
cluster([SNode]) ->
|
||||
Node = emqttd_dist:parse_node(SNode),
|
||||
case lists:member(Node, emqttd_broker:running_nodes()) of
|
||||
true ->
|
||||
?PRINT("~s is already clustered~n", [Node]);
|
||||
false ->
|
||||
cluster(Node, fun() ->
|
||||
emqttd_plugins:unload(),
|
||||
stop_apps(),
|
||||
emqttd_mnesia:cluster(Node),
|
||||
start_apps()
|
||||
end)
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Cluster with other nodes
|
||||
cluster(["join", SNode]) ->
|
||||
case emqttd_cluster:join(emqttd_node:parse_name(SNode)) of
|
||||
ok ->
|
||||
?PRINT_MSG("Join the cluster successfully.~n"),
|
||||
cluster(["status"]);
|
||||
{error, Error} ->
|
||||
?PRINT("Failed to join the cluster: ~p~n", [Error])
|
||||
end;
|
||||
|
||||
cluster(["leave"]) ->
|
||||
case emqttd_cluster:leave() of
|
||||
ok ->
|
||||
?PRINT_MSG("Leave the cluster successfully.~n"),
|
||||
cluster(["status"]);
|
||||
{error, Error} ->
|
||||
?PRINT("Failed to leave the cluster: ~p~n", [Error])
|
||||
end;
|
||||
|
||||
cluster(["remove", SNode]) ->
|
||||
case emqttd_cluster:remove(emqttd_node:parse_name(SNode)) of
|
||||
ok ->
|
||||
?PRINT_MSG("Remove the node from cluster successfully.~n"),
|
||||
cluster(["status"]);
|
||||
{error, Error} ->
|
||||
?PRINT("Failed to remove the node from cluster: ~p~n", [Error])
|
||||
end;
|
||||
|
||||
cluster(["status"]) ->
|
||||
?PRINT("Cluster status: ~p~n", [emqttd_cluster:status()]);
|
||||
|
||||
cluster(_) ->
|
||||
cluster(usage).
|
||||
?USAGE([{"cluster join <Node>", "Join the cluster"},
|
||||
{"cluster leave", "Leave the cluster"},
|
||||
{"cluster remove <Node>","Remove the node from cluster"},
|
||||
{"cluster status", "Cluster status"}]).
|
||||
|
||||
cluster(Node, DoCluster) ->
|
||||
cluster(net_adm:ping(Node), Node, DoCluster).
|
||||
|
||||
cluster(pong, Node, DoCluster) ->
|
||||
case emqttd:is_running(Node) of
|
||||
true ->
|
||||
DoCluster(),
|
||||
?PRINT("cluster with ~s successfully.~n", [Node]);
|
||||
false ->
|
||||
?PRINT("emqttd is not running on ~s~n", [Node])
|
||||
end;
|
||||
|
||||
cluster(pang, Node, _DoCluster) ->
|
||||
?PRINT("Cannot connect to ~s~n", [Node]).
|
||||
|
||||
stop_apps() ->
|
||||
[application:stop(App) || App <- [emqttd, esockd, gproc]].
|
||||
|
||||
start_apps() ->
|
||||
[application:start(App) || App <- [gproc, esockd, emqttd]].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Query clients
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
clients(["list"]) ->
|
||||
emqttd_mnesia:dump(ets, mqtt_client, fun print/1);
|
||||
dump(ets, mqtt_client, fun print/1);
|
||||
|
||||
clients(["show", ClientId]) ->
|
||||
if_client(ClientId, fun print/1);
|
||||
|
|
@ -189,18 +163,16 @@ if_client(ClientId, Fun) ->
|
|||
Client -> Fun(Client)
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Sessions Command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
sessions(["list"]) ->
|
||||
[sessions(["list", Type]) || Type <- ["persistent", "transient"]];
|
||||
|
||||
sessions(["list", "persistent"]) ->
|
||||
emqttd_mnesia:dump(ets, mqtt_persistent_session, fun print/1);
|
||||
dump(ets, mqtt_persistent_session, fun print/1);
|
||||
|
||||
sessions(["list", "transient"]) ->
|
||||
emqttd_mnesia:dump(ets, mqtt_transient_session, fun print/1);
|
||||
dump(ets, mqtt_transient_session, fun print/1);
|
||||
|
||||
sessions(["show", ClientId]) ->
|
||||
MP = {{bin(ClientId), '_'}, '_'},
|
||||
|
|
@ -220,10 +192,8 @@ sessions(_) ->
|
|||
{"sessions list transient", "list all transient sessions"},
|
||||
{"sessions show <ClientId>", "show a session"}]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Topics Command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
topics(["list"]) ->
|
||||
Print = fun(Topic, Records) -> print(topic, Topic, Records) end,
|
||||
if_could_print(topic, Print);
|
||||
|
|
@ -316,11 +286,8 @@ plugins(_) ->
|
|||
{"plugins load <Plugin>", "load plugin"},
|
||||
{"plugins unload <Plugin>", "unload plugin"}]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Bridges command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
bridges(["list"]) ->
|
||||
foreach(fun({{Node, Topic}, _Pid}) ->
|
||||
?PRINT("bridge: ~s--~s-->~s~n", [node(), Topic, Node])
|
||||
|
|
@ -376,10 +343,8 @@ parse_opt(bridge, queue, Len) ->
|
|||
parse_opt(_Cmd, Opt, _Val) ->
|
||||
?PRINT("Bad Option: ~s~n", [Opt]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc vm command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
vm([]) ->
|
||||
vm(["all"]);
|
||||
|
||||
|
|
@ -410,20 +375,16 @@ vm(_) ->
|
|||
{"vm process", "query process of erlang vm"},
|
||||
{"vm io", "queue io of erlang vm"}]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc mnesia Command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
mnesia([]) ->
|
||||
mnesia:system_info();
|
||||
|
||||
mnesia(_) ->
|
||||
?PRINT_CMD("mnesia", "mnesia system info").
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Trace Command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
trace(["list"]) ->
|
||||
foreach(fun({{Who, Name}, LogFile}) ->
|
||||
?PRINT("trace ~s ~s -> ~s~n", [Who, Name, LogFile])
|
||||
|
|
@ -464,10 +425,8 @@ trace_off(Who, Name) ->
|
|||
?PRINT("stop to trace ~s ~s error: ~p.~n", [Who, Name, Error])
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc Listeners Command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
listeners([]) ->
|
||||
foreach(fun({{Protocol, Port}, Pid}) ->
|
||||
Info = [{acceptors, esockd:get_acceptors(Pid)},
|
||||
|
|
@ -493,7 +452,7 @@ print(#mqtt_client{client_id = ClientId, clean_sess = CleanSess,
|
|||
?PRINT("Client(~s, clean_sess=~s, username=~s, peername=~s, connected_at=~p)~n",
|
||||
[ClientId, CleanSess, Username,
|
||||
emqttd_net:format(Peername),
|
||||
emqttd_util:now_to_secs(ConnectedAt)]);
|
||||
emqttd_time:now_to_secs(ConnectedAt)]);
|
||||
|
||||
print(#mqtt_topic{topic = Topic, node = Node}) ->
|
||||
?PRINT("~s on ~s~n", [Topic, Node]);
|
||||
|
|
@ -523,7 +482,7 @@ print(subscription, ClientId, Subscriptions) ->
|
|||
?PRINT("~s: ~p~n", [ClientId, TopicTable]).
|
||||
|
||||
format(created_at, Val) ->
|
||||
emqttd_util:now_to_secs(Val);
|
||||
emqttd_time:now_to_secs(Val);
|
||||
|
||||
format(subscriptions, List) ->
|
||||
string:join([io_lib:format("~s:~w", [Topic, Qos]) || {Topic, Qos} <- List], ",");
|
||||
|
|
@ -531,6 +490,19 @@ format(subscriptions, List) ->
|
|||
format(_, Val) ->
|
||||
Val.
|
||||
|
||||
bin(S) when is_list(S) -> list_to_binary(S);
|
||||
bin(B) when is_binary(B) -> B.
|
||||
bin(S) -> iolist_to_binary(S).
|
||||
|
||||
%%TODO: ...
|
||||
dump(ets, Table, Fun) ->
|
||||
dump(ets, Table, ets:first(Table), Fun).
|
||||
|
||||
dump(ets, _Table, '$end_of_table', _Fun) ->
|
||||
ok;
|
||||
|
||||
dump(ets, Table, Key, Fun) ->
|
||||
case ets:lookup(Table, Key) of
|
||||
[Record] -> Fun(Record);
|
||||
[] -> ignore
|
||||
end,
|
||||
dump(ets, Table, ets:next(Table, Key), Fun).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Client Connection
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Client Connection
|
||||
-module(emqttd_client).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -228,9 +220,9 @@ terminate(Reason, #client_state{connection = Connection,
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
with_proto_state(Fun, State = #client_state{proto_state = ProtoState}) ->
|
||||
{ok, ProtoState1} = Fun(ProtoState),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_cluster).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
%% Cluster API
|
||||
-export([join/1, leave/0, status/0, remove/1]).
|
||||
|
||||
%% RPC Call
|
||||
-export([prepare/0, reboot/0]).
|
||||
|
||||
%% @doc Join cluster
|
||||
-spec join(node()) -> ok | {error, any()}.
|
||||
join(Node) when Node =:= node() ->
|
||||
{error, {cannot_join_with_self, Node}};
|
||||
|
||||
join(Node) when is_atom(Node) ->
|
||||
case {is_clustered(Node), emqttd:is_running(Node)} of
|
||||
{false, true} ->
|
||||
prepare(), ok = emqttd_mnesia:join_cluster(Node), reboot();
|
||||
{false, false} ->
|
||||
{error, {node_not_running, Node}};
|
||||
{true, _} ->
|
||||
{error, {already_clustered, Node}}
|
||||
end.
|
||||
|
||||
%% @doc Prepare to join or leave cluster.
|
||||
-spec prepare() -> ok.
|
||||
prepare() ->
|
||||
emqttd_plugins:unload(),
|
||||
lists:foreach(fun application:stop/1, [emqttd, mochiweb, esockd, gproc]).
|
||||
|
||||
%% @doc Is node in cluster?
|
||||
-spec is_clustered(node()) -> boolean().
|
||||
is_clustered(Node) ->
|
||||
lists:member(Node, emqttd_mnesia:running_nodes()).
|
||||
|
||||
%% @doc Reboot after join or leave cluster.
|
||||
-spec reboot() -> ok.
|
||||
reboot() ->
|
||||
lists:foreach(fun application:start/1, [gproc, esockd, mochiweb, emqttd]).
|
||||
|
||||
%% @doc Leave from Cluster.
|
||||
-spec leave() -> ok | {error, any()}.
|
||||
leave() ->
|
||||
case emqttd_mnesia:running_nodes() -- [node()] of
|
||||
[_|_] ->
|
||||
prepare(), ok = emqttd_mnesia:leave_cluster(), reboot();
|
||||
[] ->
|
||||
{error, node_not_in_cluster}
|
||||
end.
|
||||
|
||||
%% @doc Remove a node from cluster.
|
||||
-spec remove(node()) -> ok | {error, any()}.
|
||||
remove(Node) when Node =:= node() ->
|
||||
{error, {cannot_remove_self, Node}};
|
||||
|
||||
remove(Node) ->
|
||||
case rpc:call(Node, ?MODULE, prepare, []) of
|
||||
ok ->
|
||||
case emqttd_mnesia:remove_from_cluster(Node) of
|
||||
ok -> rpc:call(Node, ?MODULE, reboot, []);
|
||||
Error -> Error
|
||||
end;
|
||||
Error ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
%% @doc Cluster status
|
||||
status() ->
|
||||
emqttd_mnesia:cluster_status().
|
||||
|
||||
|
|
@ -1,30 +1,24 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Client Manager
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Client Manager
|
||||
-module(emqttd_cm).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_internal.hrl").
|
||||
|
|
@ -34,8 +28,6 @@
|
|||
|
||||
-export([lookup/1, lookup_proc/1, register/1, unregister/1]).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
|
@ -47,14 +39,11 @@
|
|||
|
||||
-define(POOL, ?MODULE).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start Client Manager
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(Pool, Id, StatsFun) -> {ok, pid()} | ignore | {error, any()} when
|
||||
Pool :: atom(),
|
||||
Id :: pos_integer(),
|
||||
|
|
@ -62,10 +51,7 @@
|
|||
start_link(Pool, Id, StatsFun) ->
|
||||
gen_server2:start_link(?MODULE, [Pool, Id, StatsFun], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup Client by ClientId
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup(ClientId :: binary()) -> mqtt_client() | undefined.
|
||||
lookup(ClientId) when is_binary(ClientId) ->
|
||||
case ets:lookup(mqtt_client, ClientId) of
|
||||
|
|
@ -73,10 +59,7 @@ lookup(ClientId) when is_binary(ClientId) ->
|
|||
[] -> undefined
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup client pid by clientId
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup_proc(ClientId :: binary()) -> pid() | undefined.
|
||||
lookup_proc(ClientId) when is_binary(ClientId) ->
|
||||
try ets:lookup_element(mqtt_client, ClientId, #mqtt_client.client_pid)
|
||||
|
|
@ -84,27 +67,21 @@ lookup_proc(ClientId) when is_binary(ClientId) ->
|
|||
error:badarg -> undefined
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Register ClientId with Pid.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec register(Client :: mqtt_client()) -> ok.
|
||||
register(Client = #mqtt_client{client_id = ClientId}) ->
|
||||
CmPid = gproc_pool:pick_worker(?POOL, ClientId),
|
||||
gen_server2:cast(CmPid, {register, Client}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unregister clientId with pid.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unregister(ClientId :: binary()) -> ok.
|
||||
unregister(ClientId) when is_binary(ClientId) ->
|
||||
CmPid = gproc_pool:pick_worker(?POOL, ClientId),
|
||||
gen_server2:cast(CmPid, {unregister, ClientId, self()}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id, StatsFun]) ->
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
|
|
@ -174,9 +151,9 @@ terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
monitor_client(ClientId, Pid, State = #state{monitors = Monitors}) ->
|
||||
MRef = erlang:monitor(process, Pid),
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Client Manager Supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Client Manager Supervisor.
|
||||
-module(emqttd_cm_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd control
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_ctl).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -34,10 +25,7 @@
|
|||
-define(SERVER, ?MODULE).
|
||||
|
||||
%% API Function Exports
|
||||
-export([start_link/0,
|
||||
register_cmd/3,
|
||||
unregister_cmd/1,
|
||||
run/1]).
|
||||
-export([start_link/0, register_cmd/3, unregister_cmd/1, run/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
|
|
@ -47,36 +35,26 @@
|
|||
|
||||
-define(CMD_TAB, mqttd_ctl_cmd).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Register a command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec register_cmd(atom(), {module(), atom()}, list()) -> ok.
|
||||
register_cmd(Cmd, MF, Opts) ->
|
||||
cast({register_cmd, Cmd, MF, Opts}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unregister a command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unregister_cmd(atom()) -> ok.
|
||||
unregister_cmd(Cmd) ->
|
||||
cast({unregister_cmd, Cmd}).
|
||||
|
||||
cast(Msg) ->
|
||||
gen_server:cast(?SERVER, Msg).
|
||||
cast(Msg) -> gen_server:cast(?SERVER, Msg).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Run a command
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
run([]) -> usage();
|
||||
|
||||
run(["help"]) -> usage();
|
||||
|
|
@ -88,18 +66,15 @@ run([CmdS|Args]) ->
|
|||
[] -> usage()
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Usage
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
usage() ->
|
||||
?PRINT("Usage: ~s~n", [?MODULE]),
|
||||
[begin ?PRINT("~80..-s~n", [""]), Mod:Cmd(usage) end
|
||||
|| {_, {Mod, Cmd}, _} <- ets:tab2list(?CMD_TAB)].
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
ets:new(?CMD_TAB, [ordered_set, named_table, protected]),
|
||||
|
|
@ -134,9 +109,9 @@ terminate(_Reason, _State) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal Function Definitions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal Function Definitions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
noreply(State) ->
|
||||
{noreply, State, hibernate}.
|
||||
|
|
@ -144,4 +119,3 @@ noreply(State) ->
|
|||
next_seq(State = #state{seq = Seq}) ->
|
||||
State#state{seq = Seq + 1}.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd distribution functions
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_dist).
|
||||
|
||||
-import(lists, [concat/1]).
|
||||
|
||||
-export([parse_node/1]).
|
||||
|
||||
parse_node(Name) when is_list(Name) ->
|
||||
case string:tokens(Name, "@") of
|
||||
[_Node, _Server] ->
|
||||
list_to_atom(Name);
|
||||
_ ->
|
||||
list_to_atom(with_domain(Name))
|
||||
end.
|
||||
|
||||
with_domain(Name) ->
|
||||
case net_kernel:longnames() of
|
||||
true ->
|
||||
concat([Name, "@", inet_db:gethostname(),
|
||||
".", inet_db:res_option(domain)]);
|
||||
false ->
|
||||
concat([Name, "@", inet_db:gethostname()]);
|
||||
_ ->
|
||||
Name
|
||||
end.
|
||||
|
||||
|
|
@ -1,35 +1,27 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd gen_mod behaviour
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd gen_mod behaviour
|
||||
-module(emqttd_gen_mod).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-ifdef(use_specs).
|
||||
|
||||
-callback load(Opts :: any()) -> {ok, State :: any()}.
|
||||
-callback load(Opts :: any()) -> ok | {error, any()}.
|
||||
|
||||
-callback unload(State :: any()) -> any().
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,32 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% Generate global unique id for mqtt message.
|
||||
%%%
|
||||
%%% --------------------------------------------------------
|
||||
%%% | Timestamp | NodeID + PID | Sequence |
|
||||
%%% |<------- 64bits ------->|<--- 48bits --->|<- 16bits ->|
|
||||
%%% --------------------------------------------------------
|
||||
%%%
|
||||
%%% 1. Timestamp: erlang:system_time if Erlang >= R18, otherwise os:timestamp
|
||||
%%% 2. NodeId: encode node() to 2 bytes integer
|
||||
%%% 3. Pid: encode pid to 4 bytes integer
|
||||
%%% 4. Sequence: 2 bytes sequence in one process
|
||||
%%%
|
||||
%%% @end
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Generate global unique id for mqtt message.
|
||||
%%
|
||||
%% --------------------------------------------------------
|
||||
%% | Timestamp | NodeID + PID | Sequence |
|
||||
%% |<------- 64bits ------->|<--- 48bits --->|<- 16bits ->|
|
||||
%% --------------------------------------------------------
|
||||
%%
|
||||
%% 1. Timestamp: erlang:system_time if Erlang >= R18, otherwise os:timestamp
|
||||
%% 2. NodeId: encode node() to 2 bytes integer
|
||||
%% 3. Pid: encode pid to 4 bytes integer
|
||||
%% 4. Sequence: 2 bytes sequence in one process
|
||||
%%
|
||||
%% @end
|
||||
-module(emqttd_guid).
|
||||
|
||||
-export([gen/0, new/0, timestamp/1]).
|
||||
|
|
@ -45,10 +35,7 @@
|
|||
|
||||
-type guid() :: <<_:128>>.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Generate a global unique id.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec gen() -> guid().
|
||||
gen() ->
|
||||
Guid = case get(guid) of
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd http publish API and websocket client.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd http publish API and websocket client.
|
||||
-module(emqttd_http).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -47,9 +39,10 @@ handle_request('GET', "/status", Req) ->
|
|||
[node(), InternalStatus, AppStatus]),
|
||||
Req:ok({"text/plain", iolist_to_binary(Status)});
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% HTTP Publish API
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
handle_request('POST', "/mqtt/publish", Req) ->
|
||||
Params = mochiweb_request:parse_post(Req),
|
||||
lager:info("HTTP Publish: ~p", [Params]),
|
||||
|
|
@ -74,9 +67,9 @@ handle_request('POST', "/mqtt/publish", Req) ->
|
|||
Req:respond({401, [], <<"Fobbiden">>})
|
||||
end;
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% MQTT Over WebSocket
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
handle_request('GET', "/mqtt", Req) ->
|
||||
lager:info("WebSocket Connection from: ~s", [Req:get(peer)]),
|
||||
Upgrade = Req:get_header_value("Upgrade"),
|
||||
|
|
@ -92,9 +85,10 @@ handle_request('GET', "/mqtt", Req) ->
|
|||
Req:respond({400, [], <<"Bad WebSocket Protocol">>})
|
||||
end;
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Get static files
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
handle_request('GET', "/" ++ File, Req) ->
|
||||
lager:info("HTTP GET File: ~s", [File]),
|
||||
mochiweb_request:serve_file(File, docroot(), Req);
|
||||
|
|
@ -103,9 +97,9 @@ handle_request(Method, Path, Req) ->
|
|||
lager:error("Unexpected HTTP Request: ~s ~s", [Method, Path]),
|
||||
Req:not_found().
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% basic authorization
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
authorized(Req) ->
|
||||
case Req:get_header_value("Authorization") of
|
||||
undefined ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc client keepalive
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Client Keepalive
|
||||
-module(emqttd_keepalive).
|
||||
|
||||
-export([start/3, check/1, cancel/1]).
|
||||
|
|
@ -33,10 +25,7 @@
|
|||
|
||||
-type keepalive() :: #keepalive{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a keepalive
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start(fun(), integer(), any()) -> undefined | keepalive().
|
||||
start(_, 0, _) ->
|
||||
undefined;
|
||||
|
|
@ -46,10 +35,7 @@ start(StatFun, TimeoutSec, TimeoutMsg) ->
|
|||
tsec = TimeoutSec, tmsg = TimeoutMsg,
|
||||
tref = timer(TimeoutSec, TimeoutMsg)}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Check keepalive, called when timeout.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec check(keepalive()) -> {ok, keepalive()} | {error, any()}.
|
||||
check(KeepAlive = #keepalive{statfun = StatFun, statval = LastVal, repeat = Repeat}) ->
|
||||
case StatFun() of
|
||||
|
|
@ -68,10 +54,7 @@ check(KeepAlive = #keepalive{statfun = StatFun, statval = LastVal, repeat = Repe
|
|||
resume(KeepAlive = #keepalive{tsec = TimeoutSec, tmsg = TimeoutMsg}) ->
|
||||
KeepAlive#keepalive{tref = timer(TimeoutSec, TimeoutMsg)}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Cancel Keepalive
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec cancel(keepalive()) -> ok.
|
||||
cancel(#keepalive{tref = TRef}) ->
|
||||
cancel(TRef);
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% emqttd log trace.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
%% TODO: issue #103
|
||||
%% 0.12.0 ???
|
||||
|
||||
-module(emqttd_log).
|
||||
|
||||
%%TODO: Hooks to log???
|
||||
|
|
@ -1,44 +1,34 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Message Functions
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Message Functions
|
||||
-module(emqttd_message).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_protocol.hrl").
|
||||
|
||||
-export([make/3, make/4, from_packet/1, from_packet/2, to_packet/1]).
|
||||
-export([make/3, make/4, from_packet/1, from_packet/2, from_packet/3,
|
||||
to_packet/1]).
|
||||
|
||||
-export([set_flag/1, set_flag/2, unset_flag/1, unset_flag/2]).
|
||||
|
||||
-export([format/1]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Make a message
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec make(From, Topic, Payload) -> mqtt_message() when
|
||||
From :: atom() | binary(),
|
||||
Topic :: binary(),
|
||||
|
|
@ -62,10 +52,7 @@ make(From, Qos, Topic, Payload) ->
|
|||
payload = Payload,
|
||||
timestamp = os:timestamp()}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Message from Packet
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec from_packet(mqtt_packet()) -> mqtt_message().
|
||||
from_packet(#mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
|
||||
retain = Retain,
|
||||
|
|
@ -86,12 +73,16 @@ from_packet(#mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
|
|||
from_packet(#mqtt_packet_connect{will_flag = false}) ->
|
||||
undefined;
|
||||
|
||||
from_packet(#mqtt_packet_connect{will_retain = Retain,
|
||||
from_packet(#mqtt_packet_connect{client_id = ClientId,
|
||||
username = Username,
|
||||
will_retain = Retain,
|
||||
will_qos = Qos,
|
||||
will_topic = Topic,
|
||||
will_msg = Msg}) ->
|
||||
#mqtt_message{msgid = msgid(Qos),
|
||||
topic = Topic,
|
||||
from = ClientId,
|
||||
sender = Username,
|
||||
retain = Retain,
|
||||
qos = Qos,
|
||||
dup = false,
|
||||
|
|
@ -99,17 +90,19 @@ from_packet(#mqtt_packet_connect{will_retain = Retain,
|
|||
timestamp = os:timestamp()}.
|
||||
|
||||
from_packet(ClientId, Packet) ->
|
||||
Msg = from_packet(Packet), Msg#mqtt_message{from = ClientId}.
|
||||
Msg = from_packet(Packet),
|
||||
Msg#mqtt_message{from = ClientId}.
|
||||
|
||||
from_packet(Username, ClientId, Packet) ->
|
||||
Msg = from_packet(Packet),
|
||||
Msg#mqtt_message{from = ClientId, sender = Username}.
|
||||
|
||||
msgid(?QOS_0) ->
|
||||
undefined;
|
||||
msgid(Qos) when Qos =:= ?QOS_1 orelse Qos =:= ?QOS_2 ->
|
||||
emqttd_guid:gen().
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Message to packet
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec to_packet(mqtt_message()) -> mqtt_packet().
|
||||
to_packet(#mqtt_message{pktid = PkgId,
|
||||
qos = Qos,
|
||||
|
|
@ -130,10 +123,7 @@ to_packet(#mqtt_message{pktid = PkgId,
|
|||
},
|
||||
payload = Payload}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc set dup, retain flag
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec set_flag(mqtt_message()) -> mqtt_message().
|
||||
set_flag(Msg) ->
|
||||
Msg#mqtt_message{dup = true, retain = true}.
|
||||
|
|
@ -147,10 +137,7 @@ set_flag(retain, Msg = #mqtt_message{retain = false}) ->
|
|||
Msg#mqtt_message{retain = true};
|
||||
set_flag(Flag, Msg) when Flag =:= dup orelse Flag =:= retain -> Msg.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unset dup, retain flag
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unset_flag(mqtt_message()) -> mqtt_message().
|
||||
unset_flag(Msg) ->
|
||||
Msg#mqtt_message{dup = false, retain = false}.
|
||||
|
|
@ -162,14 +149,11 @@ unset_flag(retain, Msg = #mqtt_message{retain = true}) ->
|
|||
Msg#mqtt_message{retain = false};
|
||||
unset_flag(Flag, Msg) when Flag =:= dup orelse Flag =:= retain -> Msg.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Format MQTT Message
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
format(#mqtt_message{msgid = MsgId, pktid = PktId, from = From,
|
||||
format(#mqtt_message{msgid = MsgId, pktid = PktId, from = From, sender = Sender,
|
||||
qos = Qos, retain = Retain, dup = Dup, topic =Topic}) ->
|
||||
io_lib:format("Message(Q~p, R~p, D~p, MsgId=~p, PktId=~p, From=~s, Topic=~s)",
|
||||
[i(Qos), i(Retain), i(Dup), MsgId, PktId, From, Topic]).
|
||||
io_lib:format("Message(Q~p, R~p, D~p, MsgId=~p, PktId=~p, From=~s, Sender=~s, Topic=~s)",
|
||||
[i(Qos), i(Retain), i(Dup), MsgId, PktId, From, Sender, Topic]).
|
||||
|
||||
i(true) -> 1;
|
||||
i(false) -> 0;
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd metrics. responsible for collecting broker metrics
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd metrics. responsible for collecting broker metrics.
|
||||
-module(emqttd_metrics).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -39,10 +31,7 @@
|
|||
%% Received/Sent Metrics
|
||||
-export([received/1, sent/1]).
|
||||
|
||||
-export([all/0, value/1,
|
||||
inc/1, inc/2, inc/3,
|
||||
dec/2, dec/3,
|
||||
set/2]).
|
||||
-export([all/0, value/1, inc/1, inc/2, inc/3, dec/2, dec/3, set/2]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
|
|
@ -97,22 +86,16 @@
|
|||
{counter, 'messages/dropped'} % Messages dropped
|
||||
]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start metrics server
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link() -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Count packets received.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec received(mqtt_packet()) -> ok.
|
||||
received(Packet) ->
|
||||
inc('packets/received'),
|
||||
|
|
@ -150,10 +133,7 @@ qos_received(?QOS_1) ->
|
|||
qos_received(?QOS_2) ->
|
||||
inc('messages/qos2/received').
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Count packets received. Will not count $SYS PUBLISH.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec sent(mqtt_packet()) -> ok.
|
||||
sent(?PUBLISH_PACKET(_Qos, <<"$SYS/", _/binary>>, _, _)) ->
|
||||
ignore;
|
||||
|
|
@ -191,10 +171,7 @@ qos_sent(?QOS_1) ->
|
|||
qos_sent(?QOS_2) ->
|
||||
inc('messages/qos2/sent').
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get all metrics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec all() -> [{atom(), non_neg_integer()}].
|
||||
all() ->
|
||||
maps:to_list(
|
||||
|
|
@ -206,26 +183,17 @@ all() ->
|
|||
end
|
||||
end, #{}, ?METRIC_TAB)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get metric value
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec value(atom()) -> non_neg_integer().
|
||||
value(Metric) ->
|
||||
lists:sum(ets:select(?METRIC_TAB, [{{{Metric, '_'}, '$1'}, [], ['$1']}])).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Increase counter
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec inc(atom()) -> non_neg_integer().
|
||||
inc(Metric) ->
|
||||
inc(counter, Metric, 1).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Increase metric value
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec inc({counter | gauge, atom()} | atom(), pos_integer()) -> non_neg_integer().
|
||||
inc({gauge, Metric}, Val) ->
|
||||
inc(gauge, Metric, Val);
|
||||
|
|
@ -234,56 +202,41 @@ inc({counter, Metric}, Val) ->
|
|||
inc(Metric, Val) when is_atom(Metric) ->
|
||||
inc(counter, Metric, Val).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Increase metric value
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec inc(counter | gauge, atom(), pos_integer()) -> pos_integer().
|
||||
inc(gauge, Metric, Val) ->
|
||||
ets:update_counter(?METRIC_TAB, key(gauge, Metric), {2, Val});
|
||||
inc(counter, Metric, Val) ->
|
||||
ets:update_counter(?METRIC_TAB, key(counter, Metric), {2, Val}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Decrease metric value
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec dec(gauge, atom()) -> integer().
|
||||
dec(gauge, Metric) ->
|
||||
dec(gauge, Metric, 1).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Decrease metric value
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec dec(gauge, atom(), pos_integer()) -> integer().
|
||||
dec(gauge, Metric, Val) ->
|
||||
ets:update_counter(?METRIC_TAB, key(gauge, Metric), {2, -Val}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Set metric value
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
set(Metric, Val) when is_atom(Metric) ->
|
||||
set(gauge, Metric, Val).
|
||||
set(gauge, Metric, Val) ->
|
||||
ets:insert(?METRIC_TAB, {key(gauge, Metric), Val}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Metric Key
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
key(gauge, Metric) ->
|
||||
{Metric, 0};
|
||||
key(counter, Metric) ->
|
||||
{Metric, erlang:system_info(scheduler_id)}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
emqttd:seed_now(),
|
||||
emqttd_time:seed(),
|
||||
Metrics = ?SYSTOP_BYTES ++ ?SYSTOP_PACKETS ++ ?SYSTOP_MESSAGES,
|
||||
% Create metrics table
|
||||
ets:new(?METRIC_TAB, [set, public, named_table, {write_concurrency, true}]),
|
||||
|
|
@ -314,13 +267,12 @@ terminate(_Reason, #state{tick_tref = TRef}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
publish(Metric, Val) ->
|
||||
Payload = emqttd_util:integer_to_binary(Val),
|
||||
Msg = emqttd_message:make(metrics, metric_topic(Metric), Payload),
|
||||
Msg = emqttd_message:make(metrics, metric_topic(Metric), bin(Val)),
|
||||
emqttd_pubsub:publish(emqttd_message:set_flag(sys, Msg)).
|
||||
|
||||
create_metric({gauge, Name}) ->
|
||||
|
|
@ -333,3 +285,5 @@ create_metric({counter, Name}) ->
|
|||
metric_topic(Metric) ->
|
||||
emqttd_topic:systop(list_to_binary(lists:concat(['metrics/', Metric]))).
|
||||
|
||||
bin(I) when is_integer(I) -> list_to_binary(integer_to_list(I)).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,182 +1,256 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd mnesia
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_mnesia).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-export([start/0, cluster/1]).
|
||||
-include("emqttd_internal.hrl").
|
||||
|
||||
-export([create_table/2, copy_table/1]).
|
||||
%% Start and stop mnesia
|
||||
-export([start/0, ensure_started/0, ensure_stopped/0, connect/1]).
|
||||
|
||||
-export([dump/3]).
|
||||
%% Cluster mnesia
|
||||
-export([join_cluster/1, cluster_status/0, leave_cluster/0,
|
||||
remove_from_cluster/1, running_nodes/0]).
|
||||
|
||||
%% Schema and tables
|
||||
-export([copy_schema/1, delete_schema/0, del_schema_copy/1,
|
||||
create_table/2, copy_table/1, copy_table/2]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Start and init mnesia
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Start mnesia database.
|
||||
-spec start() -> ok.
|
||||
start() ->
|
||||
case init_schema() of
|
||||
ok ->
|
||||
ok;
|
||||
{error, {_Node, {already_exists, _Node}}} ->
|
||||
ok;
|
||||
{error, Reason} ->
|
||||
lager:error("mnesia init_schema error: ~p", [Reason])
|
||||
end,
|
||||
ensure_ok(ensure_data_dir()),
|
||||
ensure_ok(init_schema()),
|
||||
ok = mnesia:start(),
|
||||
init_tables(),
|
||||
wait_for_tables().
|
||||
wait_for(tables).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% init mnesia schema.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
ensure_data_dir() ->
|
||||
Dir = mnesia:system_info(directory) ++ "/",
|
||||
case filelib:ensure_dir(Dir) of
|
||||
ok -> ok;
|
||||
{error, Reason} -> {error, {mnesia_dir_error, Dir, Reason}}
|
||||
end.
|
||||
|
||||
%% @doc ensure mnesia started.
|
||||
-spec ensure_started() -> ok | {error, any()}.
|
||||
ensure_started() ->
|
||||
ok = mnesia:start(), wait_for(start).
|
||||
|
||||
%% @doc ensure mnesia stopped.
|
||||
-spec ensure_stopped() -> ok | {error, any()}.
|
||||
ensure_stopped() ->
|
||||
stopped = mnesia:stop(), wait_for(stop).
|
||||
|
||||
%% @private
|
||||
%% @doc Init mnesia schema or tables.
|
||||
init_schema() ->
|
||||
case mnesia:system_info(extra_db_nodes) of
|
||||
[] ->
|
||||
%% create schema
|
||||
mnesia:create_schema([node()]);
|
||||
__ ->
|
||||
ok
|
||||
[] -> mnesia:create_schema([node()]);
|
||||
[_|_] -> ok
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% init mnesia tables.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Init mnesia tables.
|
||||
init_tables() ->
|
||||
case mnesia:system_info(extra_db_nodes) of
|
||||
[] ->
|
||||
create_tables();
|
||||
_ ->
|
||||
copy_tables()
|
||||
[] -> create_tables();
|
||||
[_|_] -> copy_tables()
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% create tables.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Create mnesia tables.
|
||||
create_tables() ->
|
||||
emqttd_util:apply_module_attributes(boot_mnesia).
|
||||
emqttd_boot:apply_module_attributes(boot_mnesia).
|
||||
|
||||
create_table(Table, Attrs) ->
|
||||
case mnesia:create_table(Table, Attrs) of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, {already_exists, Table}} -> ok;
|
||||
{aborted, {already_exists, Table, _}} -> ok;
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% copy tables.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Copy mnesia tables.
|
||||
copy_tables() ->
|
||||
emqttd_util:apply_module_attributes(copy_mnesia).
|
||||
emqttd_boot:apply_module_attributes(copy_mnesia).
|
||||
|
||||
copy_table(Table) ->
|
||||
case mnesia:add_table_copy(Table, node(), ram_copies) of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, {already_exists, Table}} -> ok;
|
||||
{aborted, {already_exists, Table, _Node}} -> ok;
|
||||
{aborted, Error} -> Error
|
||||
end.
|
||||
%% @doc Create mnesia table.
|
||||
-spec create_table(Name:: atom(), TabDef :: list()) -> ok | {error, any()}.
|
||||
create_table(Name, TabDef) ->
|
||||
ensure_tab(mnesia:create_table(Name, TabDef)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% wait for tables.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
wait_for_tables() ->
|
||||
%% io:format("mnesia wait_for_tables: ~p~n", [mnesia:system_info(local_tables)]),
|
||||
mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity).
|
||||
%% @doc Copy mnesia table.
|
||||
-spec copy_table(Name :: atom()) -> ok.
|
||||
copy_table(Name) ->
|
||||
copy_table(Name, ram_copies).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% Simple cluster with another nodes.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
cluster(Node) ->
|
||||
%% stop mnesia
|
||||
mnesia:stop(),
|
||||
ok = wait_for_mnesia(stop),
|
||||
%% delete mnesia
|
||||
ok = mnesia:delete_schema([node()]),
|
||||
%% start mnesia
|
||||
ok = mnesia:start(),
|
||||
%% connect with extra_db_nodes
|
||||
case mnesia:change_config(extra_db_nodes, [Node]) of
|
||||
{ok, []} ->
|
||||
throw({error, failed_to_connect_extra_db_nodes});
|
||||
{ok, Nodes} ->
|
||||
case lists:member(Node, Nodes) of
|
||||
true -> lager:info("mnesia connected to extra_db_node '~s' successfully!", [Node]);
|
||||
false -> lager:error("mnesia failed to connect extra_db_node '~s'!", [Node])
|
||||
end,
|
||||
mnesia:change_table_copy_type(schema, node(), disc_copies)
|
||||
end,
|
||||
copy_tables(),
|
||||
wait_for_tables().
|
||||
|
||||
wait_for_mnesia(stop) ->
|
||||
case mnesia:system_info(is_running) of
|
||||
no ->
|
||||
-spec copy_table(Name:: atom(), ram_copies | disc_copies) -> ok.
|
||||
copy_table(Name, RamOrDisc) ->
|
||||
ensure_tab(mnesia:add_table_copy(Name, node(), RamOrDisc)).
|
||||
|
||||
%% @doc Copy schema.
|
||||
copy_schema(Node) ->
|
||||
case mnesia:change_table_copy_type(schema, Node, disc_copies) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
stopping ->
|
||||
lager:info("Waiting for mnesia to stop..."),
|
||||
timer:sleep(1000),
|
||||
wait_for_mnesia(stop);
|
||||
yes ->
|
||||
{error, mnesia_unexpectedly_running};
|
||||
starting ->
|
||||
{error, mnesia_unexpectedly_starting}
|
||||
{aborted, {already_exists, schema, Node, disc_copies}} ->
|
||||
ok;
|
||||
{aborted, Error} ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
dump(ets, Table, Fun) ->
|
||||
dump(ets, Table, ets:first(Table), Fun).
|
||||
%% @doc Force to delete schema.
|
||||
delete_schema() ->
|
||||
mnesia:delete_schema([node()]).
|
||||
|
||||
dump(ets, _Table, '$end_of_table', _Fun) ->
|
||||
ok;
|
||||
%% @doc Delete schema copy
|
||||
del_schema_copy(Node) ->
|
||||
case mnesia:del_table_copy(schema, Node) of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
dump(ets, Table, Key, Fun) ->
|
||||
case ets:lookup(Table, Key) of
|
||||
[Record] -> Fun(Record);
|
||||
[] -> ignore
|
||||
end,
|
||||
dump(ets, Table, ets:next(Table, Key), Fun).
|
||||
%%--------------------------------------------------------------------
|
||||
%% Cluster mnesia
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Join the mnesia cluster
|
||||
-spec join_cluster(node()) -> ok.
|
||||
join_cluster(Node) when Node =/= node() ->
|
||||
%% Stop mnesia and delete schema first
|
||||
ensure_ok(ensure_stopped()),
|
||||
ensure_ok(delete_schema()),
|
||||
%% Start mnesia and cluster to node
|
||||
ensure_ok(ensure_started()),
|
||||
ensure_ok(connect(Node)),
|
||||
ensure_ok(copy_schema(node())),
|
||||
%% Copy tables
|
||||
copy_tables(),
|
||||
ensure_ok(wait_for(tables)).
|
||||
|
||||
%% @doc Cluster status
|
||||
-spec cluster_status() -> list().
|
||||
cluster_status() ->
|
||||
Running = mnesia:system_info(running_db_nodes),
|
||||
Stopped = mnesia:system_info(db_nodes) -- Running,
|
||||
?IF(Stopped =:= [], [{running_nodes, Running}],
|
||||
[{running_nodes, Running}, {stopped_nodes, Stopped}]).
|
||||
|
||||
%% @doc This node try leave the cluster
|
||||
-spec leave_cluster() -> ok | {error, any()}.
|
||||
leave_cluster() ->
|
||||
case running_nodes() -- [node()] of
|
||||
[] ->
|
||||
{error, node_not_in_cluster};
|
||||
Nodes ->
|
||||
case lists:any(fun(Node) ->
|
||||
case leave_cluster(Node) of
|
||||
ok -> true;
|
||||
{error, _Reason} -> false
|
||||
end
|
||||
end, Nodes) of
|
||||
true -> ok;
|
||||
false -> {error, {failed_to_leave, Nodes}}
|
||||
end
|
||||
end.
|
||||
|
||||
-spec leave_cluster(node()) -> ok | {error, any()}.
|
||||
leave_cluster(Node) when Node =/= node() ->
|
||||
case is_running_db_node(Node) of
|
||||
true ->
|
||||
ensure_ok(ensure_stopped()),
|
||||
ensure_ok(rpc:call(Node, ?MODULE, del_schema_copy, [node()])),
|
||||
ensure_ok(delete_schema());
|
||||
%%ensure_ok(start()); %% restart?
|
||||
false ->
|
||||
{error, {node_not_running, Node}}
|
||||
end.
|
||||
|
||||
%% @doc Remove node from mnesia cluster.
|
||||
-spec remove_from_cluster(node()) -> ok | {error, any()}.
|
||||
remove_from_cluster(Node) when Node =/= node() ->
|
||||
case {is_node_in_cluster(Node), is_running_db_node(Node)} of
|
||||
{true, true} ->
|
||||
ensure_ok(rpc:call(Node, ?MODULE, ensure_stopped, [])),
|
||||
ensure_ok(del_schema_copy(Node)),
|
||||
ensure_ok(rpc:call(Node, ?MODULE, delete_schema, []));
|
||||
{true, false} ->
|
||||
ensure_ok(del_schema_copy(Node)),
|
||||
ensure_ok(rpc:call(Node, ?MODULE, delete_schema, []));
|
||||
{false, _} ->
|
||||
{error, node_not_in_cluster}
|
||||
end.
|
||||
|
||||
%% @doc Is node in mnesia cluster.
|
||||
is_node_in_cluster(Node) ->
|
||||
lists:member(Node, mnesia:system_info(db_nodes)).
|
||||
|
||||
%% @private
|
||||
%% @doc Is running db node.
|
||||
is_running_db_node(Node) ->
|
||||
lists:member(Node, running_nodes()).
|
||||
|
||||
%% @doc Cluster with node.
|
||||
-spec connect(node()) -> ok | {error, any()}.
|
||||
connect(Node) ->
|
||||
case mnesia:change_config(extra_db_nodes, [Node]) of
|
||||
{ok, [Node]} -> ok;
|
||||
{ok, []} -> {error, {failed_to_connect_node, Node}};
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
%% @doc Running nodes
|
||||
-spec running_nodes() -> list(node()).
|
||||
running_nodes() ->
|
||||
mnesia:system_info(running_db_nodes).
|
||||
|
||||
%% @private
|
||||
ensure_ok(ok) -> ok;
|
||||
ensure_ok({error, {_Node, {already_exists, _Node}}}) -> ok;
|
||||
ensure_ok({badrpc, Reason}) -> throw({error, {badrpc, Reason}});
|
||||
ensure_ok({error, Reason}) -> throw({error, Reason}).
|
||||
|
||||
%% @private
|
||||
ensure_tab({atomic, ok}) -> ok;
|
||||
ensure_tab({aborted, {already_exists, _Name}}) -> ok;
|
||||
ensure_tab({aborted, {already_exists, _Name, _Node}})-> ok;
|
||||
ensure_tab({aborted, Error}) -> Error.
|
||||
|
||||
%% @doc Wait for mnesia to start, stop or tables ready.
|
||||
-spec wait_for(start | stop | tables) -> ok | {error, Reason :: atom()}.
|
||||
wait_for(start) ->
|
||||
case mnesia:system_info(is_running) of
|
||||
yes -> ok;
|
||||
no -> {error, mnesia_unexpectedly_stopped};
|
||||
stopping -> {error, mnesia_unexpectedly_stopping};
|
||||
starting -> timer:sleep(1000), wait_for(start)
|
||||
end;
|
||||
|
||||
wait_for(stop) ->
|
||||
case mnesia:system_info(is_running) of
|
||||
no -> ok;
|
||||
yes -> {error, mnesia_unexpectedly_running};
|
||||
starting -> {error, mnesia_unexpectedly_starting};
|
||||
stopping -> timer:sleep(1000), wait_for(stop)
|
||||
end;
|
||||
|
||||
wait_for(tables) ->
|
||||
Tables = mnesia:system_info(local_tables),
|
||||
case mnesia:wait_for_tables(Tables, 600000) of
|
||||
ok -> ok;
|
||||
{error, Reason} -> {error, Reason};
|
||||
{timeout, BadTables} -> {error, {timetout, BadTables}}
|
||||
end.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd presence management module
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd presence management module
|
||||
-module(emqttd_mod_presence).
|
||||
|
||||
-behaviour(emqttd_gen_mod).
|
||||
|
|
@ -38,7 +30,7 @@ load(Opts) ->
|
|||
{?MODULE, client_connected, [Opts]}),
|
||||
emqttd_broker:hook('client.disconnected', {?MODULE, client_disconnected},
|
||||
{?MODULE, client_disconnected, [Opts]}),
|
||||
{ok, Opts}.
|
||||
ok.
|
||||
|
||||
client_connected(ConnAck, #mqtt_client{client_id = ClientId,
|
||||
username = Username,
|
||||
|
|
@ -55,7 +47,7 @@ client_connected(ConnAck, #mqtt_client{client_id = ClientId,
|
|||
{session, Sess},
|
||||
{protocol, ProtoVer},
|
||||
{connack, ConnAck},
|
||||
{ts, emqttd_util:now_to_secs()}]),
|
||||
{ts, emqttd_time:now_to_secs()}]),
|
||||
Msg = emqttd_message:make(presence,
|
||||
proplists:get_value(qos, Opts, 0),
|
||||
topic(connected, ClientId),
|
||||
|
|
@ -65,7 +57,7 @@ client_connected(ConnAck, #mqtt_client{client_id = ClientId,
|
|||
client_disconnected(Reason, ClientId, Opts) ->
|
||||
Json = mochijson2:encode([{clientid, ClientId},
|
||||
{reason, reason(Reason)},
|
||||
{ts, emqttd_util:now_to_secs()}]),
|
||||
{ts, emqttd_time:now_to_secs()}]),
|
||||
Msg = emqttd_message:make(presence,
|
||||
proplists:get_value(qos, Opts, 0),
|
||||
topic(disconnected, ClientId),
|
||||
|
|
@ -85,4 +77,3 @@ reason(Reason) when is_atom(Reason) -> Reason;
|
|||
reason({Error, _}) when is_atom(Error) -> Error;
|
||||
reason(_) -> internal_error.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd rewrite module
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd rewrite module
|
||||
-module(emqttd_mod_rewrite).
|
||||
|
||||
-behaviour(emqttd_gen_mod).
|
||||
|
|
@ -33,9 +25,9 @@
|
|||
|
||||
-export([rewrite/3, rewrite/4]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
load(Opts) ->
|
||||
File = proplists:get_value(file, Opts),
|
||||
|
|
@ -47,7 +39,7 @@ load(Opts) ->
|
|||
{?MODULE, rewrite, [unsubscribe, Sections]}),
|
||||
emqttd_broker:hook('message.publish', {?MODULE, rewrite_publish},
|
||||
{?MODULE, rewrite, [publish, Sections]}),
|
||||
{ok, Sections}.
|
||||
ok.
|
||||
|
||||
rewrite(_ClientId, TopicTable, subscribe, Sections) ->
|
||||
lager:info("rewrite subscribe: ~p", [TopicTable]),
|
||||
|
|
@ -84,9 +76,9 @@ unload(_) ->
|
|||
emqttd_broker:unhook('client.unsubscribe',{?MODULE, rewrite_unsubscribe}),
|
||||
emqttd_broker:unhook('message.publish', {?MODULE, rewrite_publish}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
compile(Sections) ->
|
||||
C = fun({rewrite, Re, Dest}) ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Subscription from Broker Side
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Subscription from Broker Side
|
||||
-module(emqttd_mod_subscription).
|
||||
|
||||
-behaviour(emqttd_gen_mod).
|
||||
|
|
@ -35,16 +27,12 @@
|
|||
|
||||
-record(state, {topics, stored = false}).
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile(export_all).
|
||||
-endif.
|
||||
|
||||
load(Opts) ->
|
||||
Topics = [{iolist_to_binary(Topic), QoS} || {Topic, QoS} <- Opts, ?IS_QOS(QoS)],
|
||||
State = #state{topics = Topics, stored = lists:member(stored, Opts)},
|
||||
emqttd_broker:hook('client.connected', {?MODULE, client_connected},
|
||||
{?MODULE, client_connected, [State]}),
|
||||
{ok, State}.
|
||||
ok.
|
||||
|
||||
client_connected(?CONNACK_ACCEPT, #mqtt_client{client_id = ClientId,
|
||||
client_pid = ClientPid,
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd module supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_mod_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
@ -38,9 +29,9 @@
|
|||
%% Helper macro for declaring children of supervisor
|
||||
-define(CHILD(Mod, Type), {Mod, {Mod, start_link, []}, permanent, 5000, Type, [Mod]}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
|
@ -55,10 +46,10 @@ start_child(ChildSpec) when is_tuple(ChildSpec) ->
|
|||
start_child(Mod, Type) when is_atom(Mod) and is_atom(Type) ->
|
||||
supervisor:start_child(?MODULE, ?CHILD(Mod, Type)).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Supervisor callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_one, 10, 3600}, []}}.
|
||||
{ok, {{one_for_one, 10, 100}, []}}.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +1,54 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% A Simple in-memory message queue.
|
||||
%%%
|
||||
%%% Notice that MQTT is not an enterprise messaging queue. MQTT assume that client
|
||||
%%% should be online in most of the time.
|
||||
%%%
|
||||
%%% This module implements a simple in-memory queue for MQTT persistent session.
|
||||
%%%
|
||||
%%% If the broker restarted or crashed, all the messages queued will be gone.
|
||||
%%%
|
||||
%%% Concept of Message Queue and Inflight Window:
|
||||
%%%
|
||||
%%% |<----------------- Max Len ----------------->|
|
||||
%%% -----------------------------------------------
|
||||
%%% IN -> | Messages Queue | Inflight Window | -> Out
|
||||
%%% -----------------------------------------------
|
||||
%%% |<--- Win Size --->|
|
||||
%%%
|
||||
%%%
|
||||
%%% 1. Inflight Window to store the messages delivered and awaiting for puback.
|
||||
%%%
|
||||
%%% 2. Enqueue messages when the inflight window is full.
|
||||
%%%
|
||||
%%% 3. If the queue is full, dropped qos0 messages if store_qos0 is true,
|
||||
%%% otherwise dropped the oldest one.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 A Simple in-memory message queue.
|
||||
%%
|
||||
%% Notice that MQTT is not an enterprise messaging queue. MQTT assume that client
|
||||
%% should be online in most of the time.
|
||||
%%
|
||||
%% This module implements a simple in-memory queue for MQTT persistent session.
|
||||
%%
|
||||
%% If the broker restarted or crashed, all the messages queued will be gone.
|
||||
%%
|
||||
%% Concept of Message Queue and Inflight Window:
|
||||
%%
|
||||
%% |<----------------- Max Len ----------------->|
|
||||
%% -----------------------------------------------
|
||||
%% IN -> | Messages Queue | Inflight Window | -> Out
|
||||
%% -----------------------------------------------
|
||||
%% |<--- Win Size --->|
|
||||
%%
|
||||
%%
|
||||
%% 1. Inflight Window to store the messages delivered and awaiting for puback.
|
||||
%%
|
||||
%% 2. Enqueue messages when the inflight window is full.
|
||||
%%
|
||||
%% 3. If the queue is full, dropped qos0 messages if store_qos0 is true,
|
||||
%% otherwise dropped the oldest one.
|
||||
%%
|
||||
%% @end
|
||||
|
||||
-module(emqttd_mqueue).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_protocol.hrl").
|
||||
|
||||
-import(proplists, [get_value/3]).
|
||||
|
||||
-export([new/3, type/1, name/1, is_empty/1, len/1, max_len/1, in/2, out/1, stats/1]).
|
||||
|
||||
-define(LOW_WM, 0.2).
|
||||
|
|
@ -97,19 +90,19 @@
|
|||
%% @doc New Queue.
|
||||
-spec new(iolist(), list(mqueue_option()), fun()) -> mqueue().
|
||||
new(Name, Opts, AlarmFun) ->
|
||||
Type = emqttd_opts:g(type, Opts, simple),
|
||||
MaxLen = emqttd_opts:g(max_length, Opts, infinity),
|
||||
Type = get_value(type, Opts, simple),
|
||||
MaxLen = get_value(max_length, Opts, infinity),
|
||||
init_q(#mqueue{type = Type, name = iolist_to_binary(Name),
|
||||
len = 0, max_len = MaxLen,
|
||||
low_wm = low_wm(MaxLen, Opts),
|
||||
high_wm = high_wm(MaxLen, Opts),
|
||||
qos0 = emqttd_opts:g(queue_qos0, Opts, false),
|
||||
qos0 = get_value(queue_qos0, Opts, false),
|
||||
alarm_fun = AlarmFun}, Opts).
|
||||
|
||||
init_q(MQ = #mqueue{type = simple}, _Opts) ->
|
||||
MQ#mqueue{q = queue:new()};
|
||||
init_q(MQ = #mqueue{type = priority}, Opts) ->
|
||||
Priorities = emqttd_opts:g(priority, Opts, []),
|
||||
Priorities = get_value(priority, Opts, []),
|
||||
init_p(Priorities, MQ#mqueue{q = priority_queue:new()}).
|
||||
|
||||
init_p([], MQ) ->
|
||||
|
|
@ -125,12 +118,12 @@ insert_p(Topic, P, MQ = #mqueue{priorities = Tab, pseq = Seq}) ->
|
|||
low_wm(infinity, _Opts) ->
|
||||
infinity;
|
||||
low_wm(MaxLen, Opts) ->
|
||||
round(MaxLen * emqttd_opts:g(low_watermark, Opts, ?LOW_WM)).
|
||||
round(MaxLen * get_value(low_watermark, Opts, ?LOW_WM)).
|
||||
|
||||
high_wm(infinity, _Opts) ->
|
||||
infinity;
|
||||
high_wm(MaxLen, Opts) ->
|
||||
round(MaxLen * emqttd_opts:g(high_watermark, Opts, ?HIGH_WM)).
|
||||
round(MaxLen * get_value(high_watermark, Opts, ?HIGH_WM)).
|
||||
|
||||
-spec name(mqueue()) -> iolist().
|
||||
name(#mqueue{name = Name}) ->
|
||||
|
|
|
|||
|
|
@ -1,37 +1,29 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd net utility functions. some functions copied from rabbitmq.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd net utilities.
|
||||
-module(emqttd_net).
|
||||
|
||||
-include_lib("kernel/include/inet.hrl").
|
||||
|
||||
-export([tcp_name/3, tcp_host/1, getopts/2, setopts/2,
|
||||
getaddr/2, port_to_listeners/1]).
|
||||
-export([tcp_name/3, tcp_host/1, getopts/2, setopts/2, getaddr/2,
|
||||
port_to_listeners/1]).
|
||||
|
||||
-export([peername/1, sockname/1, format/2, format/1,
|
||||
connection_string/2, ntoa/1]).
|
||||
-export([peername/1, sockname/1, format/2, format/1, ntoa/1,
|
||||
connection_string/2]).
|
||||
|
||||
-define(FIRST_TEST_BIND_PORT, 10000).
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_node).
|
||||
|
||||
-import(lists, [concat/1]).
|
||||
|
||||
-export([is_aliving/1, parse_name/1]).
|
||||
|
||||
%% @doc Is node aliving
|
||||
-spec is_aliving(node()) -> boolean().
|
||||
is_aliving(Node) ->
|
||||
case net_adm:ping(Node) of
|
||||
pong -> true;
|
||||
pang -> false
|
||||
end.
|
||||
|
||||
%% @doc Parse node name
|
||||
-spec parse_name(string()) -> atom().
|
||||
parse_name(Name) when is_list(Name) ->
|
||||
case string:tokens(Name, "@") of
|
||||
[_Node, _Host] -> list_to_atom(Name);
|
||||
_ -> with_host(Name)
|
||||
end.
|
||||
|
||||
with_host(Name) ->
|
||||
[_, Host] = string:tokens(atom_to_list(node()), "@"),
|
||||
list_to_atom(concat([Name, "@", Host])).
|
||||
|
||||
|
|
@ -1,36 +1,24 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd options handler.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_opts).
|
||||
|
||||
-export([merge/2, g/2, g/3]).
|
||||
-export([merge/2]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Merge Options
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
merge(Defaults, Options) ->
|
||||
lists:foldl(
|
||||
fun({Opt, Val}, Acc) ->
|
||||
|
|
@ -45,13 +33,3 @@ merge(Defaults, Options) ->
|
|||
end
|
||||
end, Defaults, Options).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get option
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
g(Key, Options) ->
|
||||
proplists:get_value(Key, Options).
|
||||
|
||||
g(Key, Options, Default) ->
|
||||
proplists:get_value(Key, Options, Default).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Packet Functions
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Packet Functions
|
||||
-module(emqttd_packet).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -34,38 +26,26 @@
|
|||
|
||||
-export([format/1]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Protocol name of version
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec protocol_name(mqtt_vsn()) -> binary().
|
||||
protocol_name(Ver) when Ver =:= ?MQTT_PROTO_V31; Ver =:= ?MQTT_PROTO_V311->
|
||||
-spec protocol_name(mqtt_vsn()) -> binary().
|
||||
protocol_name(Ver) when Ver =:= ?MQTT_PROTO_V31; Ver =:= ?MQTT_PROTO_V311 ->
|
||||
proplists:get_value(Ver, ?PROTOCOL_NAMES).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Name of MQTT packet type
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec type_name(mqtt_packet_type()) -> atom().
|
||||
type_name(Type) when Type > ?RESERVED andalso Type =< ?DISCONNECT ->
|
||||
lists:nth(Type, ?TYPE_NAMES).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Connack Name
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec connack_name(mqtt_connack()) -> atom().
|
||||
connack_name(?CONNACK_ACCEPT) -> 'CONNACK_ACCEPT';
|
||||
connack_name(?CONNACK_PROTO_VER) -> 'CONNACK_PROTO_VER';
|
||||
connack_name(?CONNACK_INVALID_ID ) -> 'CONNACK_INVALID_ID';
|
||||
connack_name(?CONNACK_SERVER) -> 'CONNACK_SERVER';
|
||||
connack_name(?CONNACK_CREDENTIALS) -> 'CONNACK_CREDENTIALS';
|
||||
connack_name(?CONNACK_AUTH) -> 'CONNACK_AUTH'.
|
||||
connack_name(?CONNACK_ACCEPT) -> 'CONNACK_ACCEPT';
|
||||
connack_name(?CONNACK_PROTO_VER) -> 'CONNACK_PROTO_VER';
|
||||
connack_name(?CONNACK_INVALID_ID) -> 'CONNACK_INVALID_ID';
|
||||
connack_name(?CONNACK_SERVER) -> 'CONNACK_SERVER';
|
||||
connack_name(?CONNACK_CREDENTIALS) -> 'CONNACK_CREDENTIALS';
|
||||
connack_name(?CONNACK_AUTH) -> 'CONNACK_AUTH'.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Format packet
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec format(mqtt_packet()) -> iolist().
|
||||
format(#mqtt_packet{header = Header, variable = Variable, payload = Payload}) ->
|
||||
format_header(Header, format_variable(Variable, Payload)).
|
||||
|
|
@ -115,7 +95,7 @@ format_variable(#mqtt_packet_connack{ack_flags = AckFlags,
|
|||
|
||||
format_variable(#mqtt_packet_publish{topic_name = TopicName,
|
||||
packet_id = PacketId}) ->
|
||||
io_lib:format("TopicName=~s, PacketId=~p", [TopicName, PacketId]);
|
||||
io_lib:format("Topic=~s, PacketId=~p", [TopicName, PacketId]);
|
||||
|
||||
format_variable(#mqtt_packet_puback{packet_id = PacketId}) ->
|
||||
io_lib:format("PacketId=~p", [PacketId]);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Packet Parser
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Packet Parser
|
||||
-module(emqttd_parser).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -38,10 +30,7 @@
|
|||
|
||||
-type parser() :: fun( (binary()) -> any() ).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Initialize a parser
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec new(Opts :: [option()]) -> parser().
|
||||
new(Opts) ->
|
||||
fun(Bin) -> parse(Bin, {none, limit(Opts)}) end.
|
||||
|
|
@ -50,11 +39,9 @@ limit(Opts) ->
|
|||
#mqtt_packet_limit{max_packet_size =
|
||||
proplists:get_value(max_packet_size, Opts, ?MAX_LEN)}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Parse MQTT Packet
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec parse(binary(), {none, [option()]} | fun()) -> {ok, mqtt_packet()} | {error, any()} | {more, fun()}.
|
||||
-spec parse(binary(), {none, [option()]} | fun()) ->
|
||||
{ok, mqtt_packet()} | {error, any()} | {more, fun()}.
|
||||
parse(<<>>, {none, Limit}) ->
|
||||
{more, fun(Bin) -> parse(Bin, {none, Limit}) end};
|
||||
parse(<<PacketType:4, Dup:1, QoS:2, Retain:1, Rest/binary>>, {none, Limit}) ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd plugins.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_plugins).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -33,10 +24,7 @@
|
|||
|
||||
-export([list/0]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Load all plugins when the broker started.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec load() -> list() | {error, any()}.
|
||||
load() ->
|
||||
case env(loaded_file) of
|
||||
|
|
@ -65,10 +53,7 @@ load_plugins(Names, Persistent) ->
|
|||
NeedToLoad = Names -- NotFound -- names(started_app),
|
||||
[load_plugin(find_plugin(Name, Plugins), Persistent) || Name <- NeedToLoad].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unload all plugins before broker stopped.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unload() -> list() | {error, any()}.
|
||||
unload() ->
|
||||
case env(loaded_file) of
|
||||
|
|
@ -82,10 +67,7 @@ unload() ->
|
|||
stop_plugins(Names) ->
|
||||
[stop_app(App) || App <- Names].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc List all available plugins
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec list() -> [mqtt_plugin()].
|
||||
list() ->
|
||||
case env(plugins_dir) of
|
||||
|
|
@ -119,10 +101,7 @@ plugin(PluginsDir, AppFile0) ->
|
|||
Descr = proplists:get_value(description, Attrs, ""),
|
||||
#mqtt_plugin{name = Name, version = Ver, config = AppsEnv1, descr = Descr}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Load One Plugin
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec load(atom()) -> ok | {error, any()}.
|
||||
load(PluginName) when is_atom(PluginName) ->
|
||||
case lists:member(PluginName, names(started_app)) of
|
||||
|
|
@ -182,10 +161,7 @@ find_plugin(Name) ->
|
|||
find_plugin(Name, Plugins) ->
|
||||
lists:keyfind(Name, 2, Plugins).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc UnLoad One Plugin
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unload(atom()) -> ok | {error, any()}.
|
||||
unload(PluginName) when is_atom(PluginName) ->
|
||||
case {lists:member(PluginName, names(started_app)), lists:member(PluginName, names(plugin))} of
|
||||
|
|
@ -217,9 +193,9 @@ stop_app(App) ->
|
|||
lager:error("stop plugin ~p error: ~p", [App]), {error, Reason}
|
||||
end.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
names(plugin) ->
|
||||
names(list());
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Common Pool Supervisor
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Common Pool Supervisor
|
||||
-module(emqttd_pool_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd pooler.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_pooler).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -41,40 +32,30 @@
|
|||
|
||||
-record(state, {pool, id}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start Pooler Supervisor.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
start_link() ->
|
||||
emqttd_pool_sup:start_link(pooler, random, {?MODULE, start_link, []}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(Pool, Id) ->
|
||||
gen_server:start_link({local, emqttd:reg_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
gen_server:start_link({local, ?PROC_NAME(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Submit work to pooler
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
submit(Fun) ->
|
||||
gen_server:call(worker(), {submit, Fun}, infinity).
|
||||
submit(Fun) -> gen_server:call(worker(), {submit, Fun}, infinity).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Submit work to pooler asynchronously
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
async_submit(Fun) ->
|
||||
gen_server:cast(worker(), {async_submit, Fun}).
|
||||
|
||||
worker() ->
|
||||
gproc_pool:pick_worker(pooler).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id]) ->
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
|
|
@ -105,9 +86,9 @@ terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
run({M, F, A}) ->
|
||||
erlang:apply(M, F, A);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd protocol.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Protocol Processor.
|
||||
-module(emqttd_protocol).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -31,6 +23,8 @@
|
|||
|
||||
-include("emqttd_internal.hrl").
|
||||
|
||||
-import(proplists, [get_value/2, get_value/3]).
|
||||
|
||||
%% API
|
||||
-export([init/3, info/1, clientid/1, client/1, session/1]).
|
||||
|
||||
|
|
@ -55,13 +49,10 @@
|
|||
lager:Level([{client, State#proto_state.client_id}], "Client(~s@~s): " ++ Format,
|
||||
[State#proto_state.client_id, esockd_net:format(State#proto_state.peername) | Args])).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Init protocol
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
init(Peername, SendFun, Opts) ->
|
||||
MaxLen = emqttd_opts:g(max_clientid_len, Opts, ?MAX_CLIENTID_LEN),
|
||||
WsInitialHeaders = emqttd_opts:g(ws_initial_headers, Opts),
|
||||
MaxLen = get_value(max_clientid_len, Opts, ?MAX_CLIENTID_LEN),
|
||||
WsInitialHeaders = get_value(ws_initial_headers, Opts),
|
||||
#proto_state{peername = Peername,
|
||||
sendfun = SendFun,
|
||||
max_clientid_len = MaxLen,
|
||||
|
|
@ -233,8 +224,9 @@ process(?PACKET(?DISCONNECT), State) ->
|
|||
{stop, normal, State#proto_state{will_msg = undefined}}.
|
||||
|
||||
publish(Packet = ?PUBLISH_PACKET(?QOS_0, _PacketId),
|
||||
#proto_state{client_id = ClientId, session = Session}) ->
|
||||
emqttd_session:publish(Session, emqttd_message:from_packet(ClientId, Packet));
|
||||
#proto_state{client_id = ClientId, username = Username, session = Session}) ->
|
||||
Msg = emqttd_message:from_packet(Username, ClientId, Packet),
|
||||
emqttd_session:publish(Session, Msg);
|
||||
|
||||
publish(Packet = ?PUBLISH_PACKET(?QOS_1, _PacketId), State) ->
|
||||
with_puback(?PUBACK, Packet, State);
|
||||
|
|
@ -243,8 +235,10 @@ publish(Packet = ?PUBLISH_PACKET(?QOS_2, _PacketId), State) ->
|
|||
with_puback(?PUBREC, Packet, State).
|
||||
|
||||
with_puback(Type, Packet = ?PUBLISH_PACKET(_Qos, PacketId),
|
||||
State = #proto_state{client_id = ClientId, session = Session}) ->
|
||||
Msg = emqttd_message:from_packet(ClientId, Packet),
|
||||
State = #proto_state{client_id = ClientId,
|
||||
username = Username,
|
||||
session = Session}) ->
|
||||
Msg = emqttd_message:from_packet(Username, ClientId, Packet),
|
||||
case emqttd_session:publish(Session, Msg) of
|
||||
ok ->
|
||||
send(?PUBACK_PACKET(Type, PacketId), State);
|
||||
|
|
@ -315,9 +309,10 @@ start_keepalive(0) -> ignore;
|
|||
start_keepalive(Sec) when Sec > 0 ->
|
||||
self() ! {keepalive, start, round(Sec * 1.2)}.
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Validate Packets
|
||||
%%----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
validate_connect(Connect = #mqtt_packet_connect{}, ProtoState) ->
|
||||
case validate_protocol(Connect) of
|
||||
true ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc PubSub
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_pubsub).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
|
@ -52,17 +43,13 @@
|
|||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile(export_all).
|
||||
-endif.
|
||||
|
||||
-record(state, {pool, id, statsfun}).
|
||||
|
||||
-define(ROUTER, emqttd_router).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Mnesia callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Mnesia callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
mnesia(boot) ->
|
||||
ok = create_table(topic, ram_copies),
|
||||
if_subscription(fun(RamOrDisc) ->
|
||||
|
|
@ -111,13 +98,13 @@ env(Key) ->
|
|||
end.
|
||||
|
||||
cache_env(Key) ->
|
||||
Val = emqttd_opts:g(Key, emqttd_broker:env(pubsub)),
|
||||
Val = proplists:get_value(Key, emqttd_broker:env(pubsub)),
|
||||
put({pubsub, Key}, Val),
|
||||
Val.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Start one pubsub server
|
||||
-spec start_link(Pool, Id, StatsFun, Opts) -> {ok, pid()} | ignore | {error, any()} when
|
||||
|
|
@ -126,7 +113,7 @@ cache_env(Key) ->
|
|||
StatsFun :: fun((atom()) -> any()),
|
||||
Opts :: list(tuple()).
|
||||
start_link(Pool, Id, StatsFun, Opts) ->
|
||||
gen_server2:start_link({local, emqttd:reg_name(?MODULE, Id)},
|
||||
gen_server2:start_link({local, ?PROC_NAME(?MODULE, Id)},
|
||||
?MODULE, [Pool, Id, StatsFun, Opts], []).
|
||||
|
||||
%% @doc Create Topic or Subscription.
|
||||
|
|
@ -237,13 +224,13 @@ publish(To, Msg) ->
|
|||
%% @doc Match Topic Name with Topic Filters
|
||||
-spec match(emqttd_topic:topic()) -> [mqtt_topic()].
|
||||
match(To) ->
|
||||
MatchedTopics = mnesia:async_dirty(fun emqttd_trie:match/1, [To]),
|
||||
Matched = mnesia:async_dirty(fun emqttd_trie:match/1, [To]),
|
||||
%% ets:lookup for topic table will be replicated to all nodes.
|
||||
lists:append([ets:lookup(topic, Topic) || Topic <- MatchedTopics]).
|
||||
lists:append([ets:lookup(topic, Topic) || Topic <- [To | Matched]]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id, StatsFun, _Opts]) ->
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
|
|
@ -332,9 +319,9 @@ terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
add_topics(Records) ->
|
||||
lists:foreach(fun add_topic/1, Records).
|
||||
|
|
@ -342,7 +329,10 @@ add_topics(Records) ->
|
|||
add_topic(TopicR = #mqtt_topic{topic = Topic}) ->
|
||||
case mnesia:wread({topic, Topic}) of
|
||||
[] ->
|
||||
ok = emqttd_trie:insert(Topic),
|
||||
case emqttd_topic:wildcard(Topic) of
|
||||
true -> emqttd_trie:insert(Topic);
|
||||
false -> ok
|
||||
end,
|
||||
mnesia:write(topic, TopicR, write);
|
||||
Records ->
|
||||
case lists:member(TopicR, Records) of
|
||||
|
|
@ -363,7 +353,7 @@ add_subscription(SubId, {Topic, Qos}) ->
|
|||
Pattern = #mqtt_subscription{subid = SubId, topic = Topic, qos = '_'},
|
||||
Records = mnesia:match_object(subscription, Pattern, write),
|
||||
case lists:member(Subscription, Records) of
|
||||
true ->
|
||||
true ->
|
||||
ok;
|
||||
false ->
|
||||
[delete_subscription(Record) || Record <- Records],
|
||||
|
|
@ -410,9 +400,9 @@ try_monitor(SubPid) ->
|
|||
false -> erlang:monitor(process, SubPid)
|
||||
end.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Trace Functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Trace Functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
trace(publish, From, _Msg) when is_atom(From) ->
|
||||
%% Dont' trace '$SYS' publish
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 PubSub Helper.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_pubsub_helper).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -47,9 +39,9 @@
|
|||
start_link(StatsFun) ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [StatsFun], []).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([StatsFun]) ->
|
||||
mnesia:subscribe(system),
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc PubSub Supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 PubSub Supervisor.
|
||||
-module(emqttd_pubsub_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
@ -55,8 +47,9 @@ init([Env]) ->
|
|||
|
||||
%% Router Pool Sup
|
||||
RouterMFA = {emqttd_router, start_link, [fun setstats/1, Env]},
|
||||
|
||||
%% Pool_size / 2
|
||||
RouterSup = emqttd_pool_sup:spec(router_pool, [router, hash, 1 + (pool_size(Env) div 2), RouterMFA]),
|
||||
RouterSup = emqttd_pool_sup:spec(router_pool, [router, hash, router_pool(Env), RouterMFA]),
|
||||
|
||||
%% PubSub Pool Sup
|
||||
PubSubMFA = {emqttd_pubsub, start_link, [fun setstats/1, Env]},
|
||||
|
|
@ -79,6 +72,12 @@ ensure_tab(Tab, Opts) ->
|
|||
_ -> ok
|
||||
end.
|
||||
|
||||
router_pool(Env) ->
|
||||
case pool_size(Env) div 2 of
|
||||
0 -> 1;
|
||||
I -> I
|
||||
end.
|
||||
|
||||
pool_size(Env) ->
|
||||
Schedulers = erlang:system_info(schedulers),
|
||||
proplists:get_value(pool_size, Env, Schedulers).
|
||||
|
|
|
|||
|
|
@ -1,32 +1,21 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT retained message storage.
|
||||
%%%
|
||||
%%% TODO: should match topic tree
|
||||
%%%
|
||||
%%% @end
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% TODO: should match topic tree
|
||||
%% @doc MQTT retained message storage.
|
||||
-module(emqttd_retainer).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -57,9 +46,9 @@
|
|||
|
||||
-record(state, {stats_fun, expired_after, stats_timer, expire_timer}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Mnesia callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Mnesia callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
mnesia(boot) ->
|
||||
ok = emqttd_mnesia:create_table(retained, [
|
||||
|
|
@ -70,22 +59,16 @@ mnesia(boot) ->
|
|||
mnesia(copy) ->
|
||||
ok = emqttd_mnesia:copy_table(retained).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a retained server
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link() -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%% @doc Retain message
|
||||
%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-spec retain(mqtt_message()) -> ok | ignore.
|
||||
retain(#mqtt_message{retain = false}) -> ignore;
|
||||
|
||||
|
|
@ -121,10 +104,7 @@ env(Key) ->
|
|||
Val
|
||||
end.
|
||||
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%% @doc Deliver retained messages to subscribed client
|
||||
%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-spec dispatch(Topic, CPid) -> any() when
|
||||
Topic :: binary(),
|
||||
CPid :: pid().
|
||||
|
|
@ -144,9 +124,9 @@ dispatch(Topic, CPid) when is_binary(Topic) ->
|
|||
end,
|
||||
lists:foreach(fun(Msg) -> CPid ! {dispatch, Topic, Msg} end, lists:reverse(Msgs)).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
StatsFun = emqttd_stats:statsfun('retained/count', 'retained/max'),
|
||||
|
|
@ -174,7 +154,7 @@ handle_info(expire, State = #state{expired_after = Never})
|
|||
{noreply, State, hibernate};
|
||||
|
||||
handle_info(expire, State = #state{expired_after = ExpiredAfter}) ->
|
||||
expire(emqttd_util:now_to_secs(os:timestamp()) - ExpiredAfter),
|
||||
expire(emqttd_time:now_to_secs() - ExpiredAfter),
|
||||
{noreply, State, hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
|
|
@ -187,9 +167,9 @@ terminate(_Reason, _State = #state{stats_timer = TRef1, expire_timer = TRef2}) -
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
expire(Time) ->
|
||||
mnesia:async_dirty(
|
||||
|
|
|
|||
|
|
@ -1,29 +1,22 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Message Router on local node.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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
|
||||
%% The Message Router on Local Node.
|
||||
%% @end
|
||||
-module(emqttd_router).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
|
@ -54,20 +47,20 @@
|
|||
|
||||
-record(aging, {topics, time, tref}).
|
||||
|
||||
-record(state, {pool, id, statsfun, aging :: #aging{}}).
|
||||
-record(state, {pool, id, aging :: #aging{}, statsfun}).
|
||||
|
||||
%% @doc Start a local router.
|
||||
%% @doc Start a router.
|
||||
-spec start_link(atom(), pos_integer(), fun((atom()) -> ok), list()) -> {ok, pid()} | {error, any()}.
|
||||
start_link(Pool, Id, StatsFun, Env) ->
|
||||
gen_server2:start_link({local, emqttd:reg_name(?MODULE,Id)},
|
||||
gen_server2:start_link({local, ?PROC_NAME(?MODULE, Id)},
|
||||
?MODULE, [Pool, Id, StatsFun, Env], []).
|
||||
|
||||
%% @doc Route Message on the local node.
|
||||
%% @doc Route Message on this node.
|
||||
-spec route(emqttd_topic:topic(), mqtt_message()) -> any().
|
||||
route(Queue = <<"$Q/", _Q>>, Msg) ->
|
||||
case lookup_routes(Queue) of
|
||||
[] ->
|
||||
emqttd_metrics:inc('messages/dropped');
|
||||
dropped(Queue);
|
||||
[SubPid] ->
|
||||
SubPid ! {dispatch, Queue, Msg};
|
||||
Routes ->
|
||||
|
|
@ -79,8 +72,8 @@ route(Queue = <<"$Q/", _Q>>, Msg) ->
|
|||
route(Topic, Msg) ->
|
||||
case lookup_routes(Topic) of
|
||||
[] ->
|
||||
emqttd_metrics:inc('messages/dropped');
|
||||
[SubPid] -> %% optimize
|
||||
dropped(Topic);
|
||||
[SubPid] ->
|
||||
SubPid ! {dispatch, Topic, Msg};
|
||||
Routes ->
|
||||
lists:foreach(fun(SubPid) ->
|
||||
|
|
@ -88,9 +81,16 @@ route(Topic, Msg) ->
|
|||
end, Routes)
|
||||
end.
|
||||
|
||||
%% @private
|
||||
%% @doc Ingore $SYS Messages.
|
||||
dropped(<<"$SYS/", _/binary>>) ->
|
||||
ok;
|
||||
dropped(_Topic) ->
|
||||
emqttd_metrics:inc('messages/dropped').
|
||||
|
||||
%% @doc Has Route?
|
||||
-spec has_route(emqttd_topic:topic()) -> boolean().
|
||||
has_route(Topic) ->
|
||||
has_route(Topic) when is_binary(Topic) ->
|
||||
ets:member(route, Topic).
|
||||
|
||||
%% @doc Lookup Routes
|
||||
|
|
@ -103,12 +103,12 @@ lookup_routes(Topic) when is_binary(Topic) ->
|
|||
[]
|
||||
end.
|
||||
|
||||
%% @doc Add Route.
|
||||
%% @doc Add Route
|
||||
-spec add_route(emqttd_topic:topic(), pid()) -> ok.
|
||||
add_route(Topic, Pid) when is_pid(Pid) ->
|
||||
call(pick(Topic), {add_route, Topic, Pid}).
|
||||
|
||||
%% @doc Add Routes.
|
||||
%% @doc Add Routes
|
||||
-spec add_routes(list(emqttd_topic:topic()), pid()) -> ok.
|
||||
add_routes([], _Pid) ->
|
||||
ok;
|
||||
|
|
@ -120,12 +120,12 @@ add_routes(Topics, Pid) ->
|
|||
call(Router, {add_routes, Slice, Pid})
|
||||
end, slice(Topics)).
|
||||
|
||||
%% @doc Delete Route.
|
||||
%% @doc Delete Route
|
||||
-spec delete_route(emqttd_topic:topic(), pid()) -> ok.
|
||||
delete_route(Topic, Pid) ->
|
||||
cast(pick(Topic), {delete_route, Topic, Pid}).
|
||||
|
||||
%% @doc Delete Routes.
|
||||
%% @doc Delete Routes
|
||||
-spec delete_routes(list(emqttd_topic:topic()), pid()) -> ok.
|
||||
delete_routes([Topic], Pid) ->
|
||||
delete_route(Topic, Pid);
|
||||
|
|
@ -145,8 +145,11 @@ slice(Topics) ->
|
|||
pick(Topic) ->
|
||||
gproc_pool:pick_worker(router, Topic).
|
||||
|
||||
%% @doc For unit test.
|
||||
stop(Id) when is_integer(Id) ->
|
||||
gen_server2:call(emqttd:reg_name(?MODULE, Id), stop).
|
||||
gen_server2:call(?PROC_NAME(?MODULE, Id), stop);
|
||||
stop(Pid) when is_pid(Pid) ->
|
||||
gen_server2:call(Pid, stop).
|
||||
|
||||
call(Router, Request) ->
|
||||
gen_server2:call(Router, Request, infinity).
|
||||
|
|
@ -156,21 +159,19 @@ cast(Router, Msg) ->
|
|||
|
||||
init([Pool, Id, StatsFun, Opts]) ->
|
||||
|
||||
%% Calls from pubsub should be scheduled first?
|
||||
process_flag(priority, high),
|
||||
emqttd_time:seed(),
|
||||
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
|
||||
emqttd:seed_now(),
|
||||
Aging = init_aging(Opts),
|
||||
|
||||
{ok, #state{pool = Pool, id = Id, aging = Aging, statsfun = StatsFun}}.
|
||||
|
||||
%% Init Aging
|
||||
init_aging(Opts) ->
|
||||
AgingSecs = proplists:get_value(route_aging, Opts, 5),
|
||||
|
||||
%% Aging Timer
|
||||
{ok, AgingTref} = start_tick(AgingSecs + random:uniform(AgingSecs)),
|
||||
|
||||
Aging = #aging{topics = dict:new(), time = AgingSecs, tref = AgingTref},
|
||||
|
||||
{ok, #state{pool = Pool, id = Id, statsfun = StatsFun, aging = Aging}}.
|
||||
#aging{topics = dict:new(), time = AgingSecs, tref = AgingTref}.
|
||||
|
||||
start_tick(Secs) ->
|
||||
timer:send_interval(timer:seconds(Secs), {clean, aged}).
|
||||
|
|
@ -190,24 +191,15 @@ handle_call(Req, _From, State) ->
|
|||
?UNEXPECTED_REQ(Req, State).
|
||||
|
||||
handle_cast({delete_route, Topic, Pid}, State = #state{aging = Aging}) ->
|
||||
ets:delete_object(route, {Topic, Pid}),
|
||||
NewState =
|
||||
case has_route(Topic) of
|
||||
false -> State#state{aging = store_aged(Topic, Aging)};
|
||||
true -> State
|
||||
end,
|
||||
{noreply, setstats(NewState)};
|
||||
Aging1 = delete_route_(Topic, Pid, Aging),
|
||||
{noreply, setstats(State#state{aging = Aging1})};
|
||||
|
||||
handle_cast({delete_routes, Topics, Pid}, State) ->
|
||||
NewAging =
|
||||
Aging1 =
|
||||
lists:foldl(fun(Topic, Aging) ->
|
||||
ets:delete_object(route, {Topic, Pid}),
|
||||
case has_route(Topic) of
|
||||
false -> store_aged(Topic, Aging);
|
||||
true -> Aging
|
||||
end
|
||||
delete_route_(Topic, Pid, Aging)
|
||||
end, State#state.aging, Topics),
|
||||
{noreply, setstats(State#state{aging = NewAging})};
|
||||
{noreply, setstats(State#state{aging = Aging1})};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
?UNEXPECTED_MSG(Msg, State).
|
||||
|
|
@ -216,13 +208,13 @@ handle_info({clean, aged}, State = #state{aging = Aging}) ->
|
|||
|
||||
#aging{topics = Dict, time = Time} = Aging,
|
||||
|
||||
ByTime = emqttd_util:now_to_secs() - Time,
|
||||
ByTime = emqttd_time:now_to_secs() - Time,
|
||||
|
||||
Dict1 = try_clean(ByTime, dict:to_list(Dict)),
|
||||
|
||||
NewAging = Aging#aging{topics = dict:from_list(Dict1)},
|
||||
Aging1 = Aging#aging{topics = dict:from_list(Dict1)},
|
||||
|
||||
{noreply, State#state{aging = NewAging}, hibernate};
|
||||
{noreply, State#state{aging = Aging1}, hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
?UNEXPECTED_INFO(Info, State).
|
||||
|
|
@ -234,6 +226,13 @@ terminate(_Reason, #state{pool = Pool, id = Id, aging = #aging{tref = TRef}}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
delete_route_(Topic, Pid, Aging) ->
|
||||
ets:delete_object(route, {Topic, Pid}),
|
||||
case has_route(Topic) of
|
||||
false -> store_aged(Topic, Aging);
|
||||
true -> Aging
|
||||
end.
|
||||
|
||||
try_clean(ByTime, List) ->
|
||||
try_clean(ByTime, List, []).
|
||||
|
||||
|
|
@ -262,22 +261,19 @@ try_clean2(ByTime, {Topic, _TS}, Left, Acc) ->
|
|||
try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
|
||||
%% Lock topic first
|
||||
case mnesia:wread({topic, Topic}) of
|
||||
[] ->
|
||||
ok; %% mnesia:abort(not_found);
|
||||
[TopicR] ->
|
||||
%% Remove topic and trie
|
||||
delete_topic(TopicR),
|
||||
emqttd_trie:delete(Topic);
|
||||
_More ->
|
||||
%% Remove topic only
|
||||
delete_topic(TopicR)
|
||||
[] -> ok;
|
||||
[TopicR] -> %% Remove topic and trie
|
||||
delete_topic(TopicR),
|
||||
emqttd_trie:delete(Topic);
|
||||
_More -> %% Remove topic only
|
||||
delete_topic(TopicR)
|
||||
end.
|
||||
|
||||
delete_topic(TopicR) ->
|
||||
mnesia:delete_object(topic, TopicR, write).
|
||||
|
||||
store_aged(Topic, Aging = #aging{topics = Dict}) ->
|
||||
Now = emqttd_util:now_to_secs(),
|
||||
Now = emqttd_time:now_to_secs(),
|
||||
Aging#aging{topics = dict:store(Topic, Now, Dict)}.
|
||||
|
||||
setstats(State = #state{statsfun = StatsFun}) ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Packet Serializer
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Packet Serializer
|
||||
-module(emqttd_serializer).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -32,10 +24,7 @@
|
|||
%% API
|
||||
-export([serialize/1]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Serialise MQTT Packet
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec serialize(mqtt_packet()) -> binary().
|
||||
serialize(#mqtt_packet{header = Header = #mqtt_packet_header{type = Type},
|
||||
variable = Variable,
|
||||
|
|
|
|||
|
|
@ -1,49 +1,42 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Session for persistent MQTT client.
|
||||
%%%
|
||||
%%% Session State in the broker consists of:
|
||||
%%%
|
||||
%%% 1. The Client’s subscriptions.
|
||||
%%%
|
||||
%%% 2. inflight qos1/2 messages sent to the client but unacked, QoS 1 and QoS 2
|
||||
%%% messages which have been sent to the Client, but have not been completely
|
||||
%%% acknowledged.
|
||||
%%%
|
||||
%%% 3. inflight qos2 messages received from client and waiting for pubrel. QoS 2
|
||||
%%% messages which have been received from the Client, but have not been
|
||||
%%% completely acknowledged.
|
||||
%%%
|
||||
%%% 4. all qos1, qos2 messages published to when client is disconnected.
|
||||
%%% QoS 1 and QoS 2 messages pending transmission to the Client.
|
||||
%%%
|
||||
%%% 5. Optionally, QoS 0 messages pending transmission to the Client.
|
||||
%%%
|
||||
%%% State of Message: newcome, inflight, pending
|
||||
%%%
|
||||
%%% @end
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Session for persistent MQTT client.
|
||||
%%
|
||||
%% Session State in the broker consists of:
|
||||
%%
|
||||
%% 1. The Client’s subscriptions.
|
||||
%%
|
||||
%% 2. inflight qos1/2 messages sent to the client but unacked, QoS 1 and QoS 2
|
||||
%% messages which have been sent to the Client, but have not been completely
|
||||
%% acknowledged.
|
||||
%%
|
||||
%% 3. inflight qos2 messages received from client and waiting for pubrel. QoS 2
|
||||
%% messages which have been received from the Client, but have not been
|
||||
%% completely acknowledged.
|
||||
%%
|
||||
%% 4. all qos1, qos2 messages published to when client is disconnected.
|
||||
%% QoS 1 and QoS 2 messages pending transmission to the Client.
|
||||
%%
|
||||
%% 5. Optionally, QoS 0 messages pending transmission to the Client.
|
||||
%%
|
||||
%% State of Message: newcome, inflight, pending
|
||||
%%
|
||||
%% @end
|
||||
|
||||
-module(emqttd_session).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -54,6 +47,8 @@
|
|||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-import(proplists, [get_value/2, get_value/3]).
|
||||
|
||||
%% Session API
|
||||
-export([start_link/3, resume/3, info/1, destroy/2]).
|
||||
|
||||
|
|
@ -140,41 +135,26 @@
|
|||
lager:Level([{client, State#session.client_id}],
|
||||
"Session(~s): " ++ Format, [State#session.client_id | Args])).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a session.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(boolean(), mqtt_client_id(), pid()) -> {ok, pid()} | {error, any()}.
|
||||
start_link(CleanSess, ClientId, ClientPid) ->
|
||||
gen_server2:start_link(?MODULE, [CleanSess, ClientId, ClientPid], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Resume a session.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec resume(pid(), mqtt_client_id(), pid()) -> ok.
|
||||
resume(SessPid, ClientId, ClientPid) ->
|
||||
gen_server2:cast(SessPid, {resume, ClientId, ClientPid}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Session Info.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
info(SessPid) ->
|
||||
gen_server2:call(SessPid, info).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Destroy a session.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec destroy(pid(), mqtt_client_id()) -> ok.
|
||||
destroy(SessPid, ClientId) ->
|
||||
gen_server2:cast(SessPid, {destroy, ClientId}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Subscribe Topics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec subscribe(pid(), [{binary(), mqtt_qos()}]) -> ok.
|
||||
subscribe(SessPid, TopicTable) ->
|
||||
gen_server2:cast(SessPid, {subscribe, TopicTable, fun(_) -> ok end}).
|
||||
|
|
@ -187,10 +167,7 @@ subscribe(SessPid, PacketId, TopicTable) ->
|
|||
end,
|
||||
gen_server2:cast(SessPid, {subscribe, TopicTable, AckFun}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Publish message
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec publish(pid(), mqtt_message()) -> ok | {error, any()}.
|
||||
publish(_SessPid, Msg = #mqtt_message{qos = ?QOS_0}) ->
|
||||
%% publish qos0 directly
|
||||
|
|
@ -204,10 +181,7 @@ publish(SessPid, Msg = #mqtt_message{qos = ?QOS_2}) ->
|
|||
%% publish qos2 by session
|
||||
gen_server2:call(SessPid, {publish, Msg}, ?PUBSUB_TIMEOUT).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc PubAck message
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec puback(pid(), mqtt_packet_id()) -> ok.
|
||||
puback(SessPid, PktId) ->
|
||||
gen_server2:cast(SessPid, {puback, PktId}).
|
||||
|
|
@ -224,17 +198,14 @@ pubrel(SessPid, PktId) ->
|
|||
pubcomp(SessPid, PktId) ->
|
||||
gen_server2:cast(SessPid, {pubcomp, PktId}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unsubscribe Topics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unsubscribe(pid(), [binary()]) -> ok.
|
||||
unsubscribe(SessPid, Topics) ->
|
||||
gen_server2:cast(SessPid, {unsubscribe, Topics}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([CleanSess, ClientId, ClientPid]) ->
|
||||
process_flag(trap_exit, true),
|
||||
|
|
@ -247,16 +218,16 @@ init([CleanSess, ClientId, ClientPid]) ->
|
|||
client_pid = ClientPid,
|
||||
subscriptions = dict:new(),
|
||||
inflight_queue = [],
|
||||
max_inflight = emqttd_opts:g(max_inflight, SessEnv, 0),
|
||||
max_inflight = get_value(max_inflight, SessEnv, 0),
|
||||
message_queue = emqttd_mqueue:new(ClientId, QEnv, emqttd_alarm:alarm_fun()),
|
||||
awaiting_rel = #{},
|
||||
awaiting_ack = #{},
|
||||
awaiting_comp = #{},
|
||||
retry_interval = emqttd_opts:g(unack_retry_interval, SessEnv),
|
||||
await_rel_timeout = emqttd_opts:g(await_rel_timeout, SessEnv),
|
||||
max_awaiting_rel = emqttd_opts:g(max_awaiting_rel, SessEnv),
|
||||
expired_after = emqttd_opts:g(expired_after, SessEnv) * 3600,
|
||||
collect_interval = emqttd_opts:g(collect_interval, SessEnv, 0),
|
||||
retry_interval = get_value(unack_retry_interval, SessEnv),
|
||||
await_rel_timeout = get_value(await_rel_timeout, SessEnv),
|
||||
max_awaiting_rel = get_value(max_awaiting_rel, SessEnv),
|
||||
expired_after = get_value(expired_after, SessEnv) * 3600,
|
||||
collect_interval = get_value(collect_interval, SessEnv, 0),
|
||||
timestamp = os:timestamp()},
|
||||
emqttd_sm:register_session(CleanSess, ClientId, sess_info(Session)),
|
||||
%% start statistics
|
||||
|
|
@ -564,13 +535,9 @@ terminate(_Reason, #session{clean_sess = CleanSess, client_id = ClientId}) ->
|
|||
code_change(_OldVsn, Session, _Extra) ->
|
||||
{ok, Session}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Kick old client out
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
kick(_ClientId, undefined, _Pid) ->
|
||||
ignore;
|
||||
kick(_ClientId, Pid, Pid) ->
|
||||
|
|
@ -581,9 +548,9 @@ kick(ClientId, OldPid, Pid) ->
|
|||
%% Clean noproc
|
||||
receive {'EXIT', OldPid, _} -> ok after 0 -> ok end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Dispatch Messages
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% Queue message if client disconnected
|
||||
dispatch(Msg, Session = #session{client_pid = undefined, message_queue = Q}) ->
|
||||
|
|
@ -613,9 +580,9 @@ tune_qos(Topic, Msg = #mqtt_message{qos = PubQos}, Subscriptions) ->
|
|||
Msg
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Check inflight and awaiting_rel
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
check_inflight(#session{max_inflight = 0}) ->
|
||||
true;
|
||||
|
|
@ -628,9 +595,9 @@ check_awaiting_rel(#session{awaiting_rel = AwaitingRel,
|
|||
max_awaiting_rel = MaxLen}) ->
|
||||
maps:size(AwaitingRel) < MaxLen.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Dequeue and Deliver
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
dequeue(Session = #session{client_pid = undefined}) ->
|
||||
%% do nothing if client is disconnected
|
||||
|
|
@ -670,7 +637,7 @@ redeliver(Msg = #mqtt_message{qos = QoS}, Session = #session{client_pid = Client
|
|||
ClientPid ! {deliver, Msg#mqtt_message{dup = true}},
|
||||
await(Msg, Session).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Awaiting ack for qos1, qos2 message
|
||||
%%------------------------------------------------------------------------------
|
||||
await(#mqtt_message{pktid = PktId}, Session = #session{awaiting_ack = Awaiting,
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd session supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd session supervisor.
|
||||
-module(emqttd_session_sup).
|
||||
|
||||
-behavior(supervisor).
|
||||
|
|
@ -31,29 +23,22 @@
|
|||
|
||||
-export([init/1]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start session supervisor
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link() -> {ok, pid()}.
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a session
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_session(boolean(), binary(), pid()) -> {ok, pid()}.
|
||||
start_session(CleanSess, ClientId, ClientPid) ->
|
||||
supervisor:start_child(?MODULE, [CleanSess, ClientId, ClientPid]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Supervisor callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, {{simple_one_for_one, 10, 10},
|
||||
[{session, {emqttd_session, start_link, []},
|
||||
temporary, 10000, worker, [emqttd_session]}]}}.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,24 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Session Manager
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Session Manager
|
||||
-module(emqttd_sm).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_internal.hrl").
|
||||
|
|
@ -42,8 +36,6 @@
|
|||
|
||||
-export([register_session/3, unregister_session/2]).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
|
@ -60,9 +52,9 @@
|
|||
-define(LOG(Level, Format, Args, Session),
|
||||
lager:Level("SM(~s): " ++ Format, [Session#mqtt_session.client_id | Args])).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Mnesia callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Mnesia callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
mnesia(boot) ->
|
||||
%% Global Session Table
|
||||
|
|
@ -75,31 +67,22 @@ mnesia(boot) ->
|
|||
mnesia(copy) ->
|
||||
ok = emqttd_mnesia:copy_table(session).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a session manager
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(Pool, Id) ->
|
||||
gen_server2:start_link({local, emqttd:reg_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
gen_server2:start_link({local, ?PROC_NAME(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a session
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_session(CleanSess :: boolean(), binary()) -> {ok, pid(), boolean()} | {error, any()}.
|
||||
start_session(CleanSess, ClientId) ->
|
||||
SM = gproc_pool:pick_worker(?POOL, ClientId),
|
||||
call(SM, {start_session, {CleanSess, ClientId, self()}}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup a Session
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup_session(binary()) -> mqtt_session() | undefined.
|
||||
lookup_session(ClientId) ->
|
||||
case mnesia:dirty_read(session, ClientId) of
|
||||
|
|
@ -107,10 +90,7 @@ lookup_session(ClientId) ->
|
|||
[] -> undefined
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Register a session with info.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec register_session(CleanSess, ClientId, Info) -> ok when
|
||||
CleanSess :: boolean(),
|
||||
ClientId :: binary(),
|
||||
|
|
@ -118,10 +98,7 @@ lookup_session(ClientId) ->
|
|||
register_session(CleanSess, ClientId, Info) ->
|
||||
ets:insert(sesstab(CleanSess), {{ClientId, self()}, Info}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unregister a session.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unregister_session(CleanSess, ClientId) -> ok when
|
||||
CleanSess :: boolean(),
|
||||
ClientId :: binary().
|
||||
|
|
@ -134,9 +111,9 @@ sesstab(false) -> mqtt_persistent_session.
|
|||
call(SM, Req) ->
|
||||
gen_server2:call(SM, Req, ?TIMEOUT). %%infinity).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id]) ->
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
|
|
@ -213,9 +190,9 @@ terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% Create Session Locally
|
||||
create_session({CleanSess, ClientId, ClientPid}, State) ->
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Session Helper.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Session Helper.
|
||||
-module(emqttd_sm_helper).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -42,10 +34,7 @@
|
|||
|
||||
-record(state, {stats_fun, tick_tref}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a session helper
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(fun()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(StatsFun) ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [StatsFun], []).
|
||||
|
|
@ -89,9 +78,9 @@ terminate(_Reason, _State = #state{tick_tref = TRef}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
setstats(State = #state{stats_fun = StatsFun}) ->
|
||||
StatsFun(ets:info(mqtt_persistent_session, size)), State.
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Session Manager Supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 Session Manager Supervisor.
|
||||
-module(emqttd_sm_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
@ -33,8 +25,7 @@
|
|||
|
||||
-define(HELPER, emqttd_sm_helper).
|
||||
|
||||
-define(TABS, [mqtt_transient_session,
|
||||
mqtt_persistent_session]).
|
||||
-define(TABS, [mqtt_transient_session, mqtt_persistent_session]).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd statistics
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd statistics
|
||||
-module(emqttd_stats).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -76,14 +68,11 @@
|
|||
'retained/max'
|
||||
]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start stats server
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
|
@ -91,10 +80,7 @@ start_link() ->
|
|||
stop() ->
|
||||
gen_server:call(?SERVER, stop).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Generate stats fun
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec statsfun(Stat :: atom()) -> fun().
|
||||
statsfun(Stat) ->
|
||||
fun(Val) -> setstat(Stat, Val) end.
|
||||
|
|
@ -103,18 +89,12 @@ statsfun(Stat) ->
|
|||
statsfun(Stat, MaxStat) ->
|
||||
fun(Val) -> setstats(Stat, MaxStat, Val) end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get broker statistics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec getstats() -> [{atom(), non_neg_integer()}].
|
||||
getstats() ->
|
||||
lists:sort(ets:tab2list(?STATS_TAB)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Get stats by name
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec getstat(atom()) -> non_neg_integer() | undefined.
|
||||
getstat(Name) ->
|
||||
case ets:lookup(?STATS_TAB, Name) of
|
||||
|
|
@ -122,28 +102,22 @@ getstat(Name) ->
|
|||
[] -> undefined
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Set broker stats
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec setstat(Stat :: atom(), Val :: pos_integer()) -> boolean().
|
||||
setstat(Stat, Val) ->
|
||||
ets:update_element(?STATS_TAB, Stat, {2, Val}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Set stats with max
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec setstats(Stat :: atom(), MaxStat :: atom(), Val :: pos_integer()) -> boolean().
|
||||
setstats(Stat, MaxStat, Val) ->
|
||||
gen_server:cast(?MODULE, {setstats, Stat, MaxStat, Val}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
emqttd:seed_now(),
|
||||
emqttd_time:seed(),
|
||||
ets:new(?STATS_TAB, [set, public, named_table, {write_concurrency, true}]),
|
||||
Topics = ?SYSTOP_CLIENTS ++ ?SYSTOP_SESSIONS ++ ?SYSTOP_PUBSUB ++ ?SYSTOP_RETAINED,
|
||||
ets:insert(?STATS_TAB, [{Topic, 0} || Topic <- Topics]),
|
||||
|
|
@ -186,14 +160,16 @@ terminate(_Reason, #state{tick_tref = TRef}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
publish(Stat, Val) ->
|
||||
Msg = emqttd_message:make(stats, stats_topic(Stat),
|
||||
emqttd_util:integer_to_binary(Val)),
|
||||
Msg = emqttd_message:make(stats, stats_topic(Stat), bin(Val)),
|
||||
emqttd_pubsub:publish(Msg).
|
||||
|
||||
stats_topic(Stat) ->
|
||||
emqttd_topic:systop(list_to_binary(lists:concat(['stats/', Stat]))).
|
||||
|
||||
bin(I) when is_integer(I) -> list_to_binary(integer_to_list(I)).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd top supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 emqttd top supervisor.
|
||||
-module(emqttd_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
@ -39,9 +31,9 @@
|
|||
-define(CHILD(Mod, Type), {Mod, {Mod, start_link, []},
|
||||
permanent, 5000, Type, [Mod]}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
|
@ -49,16 +41,13 @@ start_link() ->
|
|||
start_child(ChildSpec) when is_tuple(ChildSpec) ->
|
||||
supervisor:start_child(?MODULE, ChildSpec).
|
||||
|
||||
%%
|
||||
%% start_child(Mod::atom(), Type::type()) -> {ok, pid()}
|
||||
%% @type type() = worker | supervisor
|
||||
%%
|
||||
-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
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_all, 10, 3600}, []}}.
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc VM System Monitor
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 VM System Monitor
|
||||
-module(emqttd_sysmon).
|
||||
|
||||
-behavior(gen_server).
|
||||
|
|
@ -44,18 +36,15 @@
|
|||
-define(LOG(Msg, ProcInfo, PortInfo),
|
||||
lager:warning([{sysmon, true}], "~s~n~p~n~p", [WarnMsg, ProcInfo, PortInfo])).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start system monitor
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(Opts :: list(tuple())) ->
|
||||
{ok, pid()} | ignore | {error, term()}.
|
||||
start_link(Opts) ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Opts]) ->
|
||||
erlang:system_monitor(self(), parse_opt(Opts)),
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd sysmon supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_sysmon_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
@ -37,8 +28,7 @@ start_link() ->
|
|||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
Env = emqttd:env(sysmon),
|
||||
{ok, {{one_for_one, 10, 100},
|
||||
[{sysmon, {emqttd_sysmon, start_link, [Env]},
|
||||
permanent, 5000, worker, [emqttd_sysmon]}]}}.
|
||||
Sysmon = {sysmon, {emqttd_sysmon, start_link, [emqttd:env(sysmon)]},
|
||||
permanent, 5000, worker, [emqttd_sysmon]} ,
|
||||
{ok, {{one_for_one, 10, 100}, [Sysmon]}}.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_time).
|
||||
|
||||
-export([seed/0, now_to_secs/0, now_to_secs/1, now_to_ms/0, now_to_ms/1]).
|
||||
|
||||
seed() ->
|
||||
case erlang:function_exported(erlang, timestamp, 0) of
|
||||
true -> random:seed(erlang:timestamp()); %% R18
|
||||
false -> random:seed(os:timestamp()) %% Compress now() deprecated warning...
|
||||
end.
|
||||
|
||||
now_to_secs() -> now_to_secs(os:timestamp()).
|
||||
|
||||
now_to_secs({MegaSecs, Secs, _MicroSecs}) ->
|
||||
MegaSecs * 1000000 + Secs.
|
||||
|
||||
now_to_ms() -> now_to_ms(os:timestamp()).
|
||||
|
||||
now_to_ms({MegaSecs, Secs, MicroSecs}) ->
|
||||
(MegaSecs * 1000000 + Secs) * 1000 + round(MicroSecs/1000).
|
||||
|
||||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Topic Functions
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_topic).
|
||||
|
||||
-import(lists, [reverse/1]).
|
||||
|
|
@ -33,8 +24,6 @@
|
|||
|
||||
-type topic() :: binary().
|
||||
|
||||
%-type type() :: static | dynamic.
|
||||
|
||||
-type word() :: '' | '+' | '#' | binary().
|
||||
|
||||
-type words() :: list(word()).
|
||||
|
|
@ -45,11 +34,8 @@
|
|||
|
||||
-define(MAX_TOPIC_LEN, 4096).
|
||||
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%% @doc Is wildcard topic?
|
||||
%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-spec wildcard(topic()) -> true | false.
|
||||
-spec wildcard(topic() | words()) -> true | false.
|
||||
wildcard(Topic) when is_binary(Topic) ->
|
||||
wildcard(words(Topic));
|
||||
wildcard([]) ->
|
||||
|
|
@ -61,10 +47,7 @@ wildcard(['+'|_]) ->
|
|||
wildcard([_H|T]) ->
|
||||
wildcard(T).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Match Topic name with filter
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec match(Name, Filter) -> boolean() when
|
||||
Name :: topic() | words(),
|
||||
Filter :: topic() | words().
|
||||
|
|
@ -89,10 +72,7 @@ match([_H1|_], []) ->
|
|||
match([], [_H|_T2]) ->
|
||||
false.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Validate Topic
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec validate({name | filter, topic()}) -> boolean().
|
||||
validate({_, <<>>}) ->
|
||||
false;
|
||||
|
|
@ -127,10 +107,7 @@ validate3(<<C/utf8, _Rest/binary>>) when C == $#; C == $+; C == 0 ->
|
|||
validate3(<<_/utf8, Rest/binary>>) ->
|
||||
validate3(Rest).
|
||||
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%% @doc Topic to Triples
|
||||
%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-spec triples(topic()) -> list(triple()).
|
||||
triples(Topic) when is_binary(Topic) ->
|
||||
triples(words(Topic), root, []).
|
||||
|
|
@ -152,10 +129,7 @@ bin('+') -> <<"+">>;
|
|||
bin('#') -> <<"#">>;
|
||||
bin(B) when is_binary(B) -> B.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Split Topic Path to Words
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec words(topic()) -> words().
|
||||
words(Topic) when is_binary(Topic) ->
|
||||
[word(W) || W <- binary:split(Topic, <<"/">>, [global])].
|
||||
|
|
@ -165,21 +139,16 @@ word(<<"+">>) -> '+';
|
|||
word(<<"#">>) -> '#';
|
||||
word(Bin) -> Bin.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Queue is a special topic name that starts with "$Q/"
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec is_queue(topic()) -> boolean().
|
||||
is_queue(<<"$Q/", _Queue/binary>>) ->
|
||||
true;
|
||||
is_queue(<<"$q/", _Queue/binary>>) ->
|
||||
true;
|
||||
is_queue(_) ->
|
||||
false.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc '$SYS' Topic.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
systop(Name) when is_atom(Name) ->
|
||||
list_to_binary(lists:concat(["$SYS/brokers/", node(), "/", Name]));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,22 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc Trace MQTT packets/messages by ClientID or Topic.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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
|
||||
%% Trace MQTT packets/messages by ClientID or Topic.
|
||||
%% @end
|
||||
-module(emqttd_trace).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
|
@ -44,17 +38,15 @@
|
|||
|
||||
-define(TRACE_OPTIONS, [{formatter_config, [time, " [",severity,"] ", message, "\n"]}]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-spec start_link() -> {ok, pid()}.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start to trace client or topic.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_trace(trace_who(), string()) -> ok | {error, any()}.
|
||||
start_trace({client, ClientId}, LogFile) ->
|
||||
start_trace({start_trace, {client, ClientId}, LogFile});
|
||||
|
|
@ -62,26 +54,22 @@ start_trace({client, ClientId}, LogFile) ->
|
|||
start_trace({topic, Topic}, LogFile) ->
|
||||
start_trace({start_trace, {topic, Topic}, LogFile}).
|
||||
|
||||
start_trace(Req) ->
|
||||
gen_server:call(?MODULE, Req, infinity).
|
||||
start_trace(Req) -> gen_server:call(?MODULE, Req, infinity).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Stop tracing client or topic.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec stop_trace(trace_who()) -> ok | {error, any()}.
|
||||
stop_trace({client, ClientId}) ->
|
||||
gen_server:call(?MODULE, {stop_trace, {client, ClientId}});
|
||||
stop_trace({topic, Topic}) ->
|
||||
gen_server:call(?MODULE, {stop_trace, {topic, Topic}}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup all traces.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec all_traces() -> [{Who :: trace_who(), LogFile :: string()}].
|
||||
all_traces() ->
|
||||
gen_server:call(?MODULE, all_traces).
|
||||
all_traces() -> gen_server:call(?MODULE, all_traces).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, #state{level = info, traces = #{}}}.
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd trace supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_trace_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
|
@ -37,7 +28,7 @@ start_link() ->
|
|||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_one, 10, 100},
|
||||
[{trace, {emqttd_trace, start_link, []},
|
||||
permanent, 5000, worker, [emqttd_trace]}]}}.
|
||||
Trace = {trace, {emqttd_trace, start_link, []},
|
||||
permanent, 5000, worker, [emqttd_trace]},
|
||||
{ok, {{one_for_one, 10, 100}, [Trace]}}.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,26 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% MQTT Topic Trie.
|
||||
%%%
|
||||
%%% [Trie](http://en.wikipedia.org/wiki/Trie)
|
||||
%%%
|
||||
%%% @end
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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 MQTT Topic Trie:
|
||||
%% [Trie](http://en.wikipedia.org/wiki/Trie)
|
||||
%% @end
|
||||
-module(emqttd_trie).
|
||||
|
||||
-include("emqttd_trie.hrl").
|
||||
|
||||
%% Mnesia Callbacks
|
||||
-export([mnesia/1]).
|
||||
|
||||
|
|
@ -37,34 +28,13 @@
|
|||
-copy_mnesia({mnesia, [copy]}).
|
||||
|
||||
%% Trie API
|
||||
-export([insert/1, match/1, delete/1]).
|
||||
-export([insert/1, match/1, delete/1, lookup/1]).
|
||||
|
||||
-type node_id() :: binary() | atom().
|
||||
%%--------------------------------------------------------------------
|
||||
%% Mnesia Callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-record(trie_node, {
|
||||
node_id :: node_id(),
|
||||
edge_count = 0 :: non_neg_integer(),
|
||||
topic :: binary() | undefined
|
||||
}).
|
||||
|
||||
-record(trie_edge, {
|
||||
node_id :: node_id(),
|
||||
word :: binary() | atom()
|
||||
}).
|
||||
|
||||
-record(trie, {
|
||||
edge :: #trie_edge{},
|
||||
node_id :: node_id()
|
||||
}).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Mnesia Callbacks
|
||||
%%%=============================================================================
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Create Trie Tables
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Create or Replicate trie tables.
|
||||
-spec mnesia(boot | copy) -> ok.
|
||||
mnesia(boot) ->
|
||||
%% Trie Table
|
||||
|
|
@ -78,24 +48,17 @@ mnesia(boot) ->
|
|||
{record_name, trie_node},
|
||||
{attributes, record_info(fields, trie_node)}]);
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Replicate trie tables
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
mnesia(copy) ->
|
||||
%% Copy Trie Table
|
||||
ok = emqttd_mnesia:copy_table(trie),
|
||||
%% Copy Trie Node Table
|
||||
ok = emqttd_mnesia:copy_table(trie_node).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Trie API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Insert topic to trie tree
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Insert topic to trie
|
||||
-spec insert(Topic :: binary()) -> ok.
|
||||
insert(Topic) when is_binary(Topic) ->
|
||||
case mnesia:read(trie_node, Topic) of
|
||||
|
|
@ -105,24 +68,23 @@ insert(Topic) when is_binary(Topic) ->
|
|||
mnesia:write(TrieNode#trie_node{topic=Topic});
|
||||
[] ->
|
||||
%add trie path
|
||||
[add_path(Triple) || Triple <- emqttd_topic:triples(Topic)],
|
||||
lists:foreach(fun add_path/1, emqttd_topic:triples(Topic)),
|
||||
%add last node
|
||||
mnesia:write(#trie_node{node_id=Topic, topic=Topic})
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Find trie nodes that match topic
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec match(Topic :: binary()) -> list(MatchedTopic :: binary()).
|
||||
match(Topic) when is_binary(Topic) ->
|
||||
TrieNodes = match_node(root, emqttd_topic:words(Topic)),
|
||||
[Name || #trie_node{topic=Name} <- TrieNodes, Name =/= undefined].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup a Trie Node
|
||||
-spec lookup(NodeId :: binary()) -> [#trie_node{}].
|
||||
lookup(NodeId) ->
|
||||
mnesia:read(trie_node, NodeId).
|
||||
|
||||
%% @doc Delete topic from trie
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec delete(Topic :: binary()) -> ok.
|
||||
delete(Topic) when is_binary(Topic) ->
|
||||
case mnesia:read(trie_node, Topic) of
|
||||
|
|
@ -130,22 +92,17 @@ delete(Topic) when is_binary(Topic) ->
|
|||
mnesia:delete({trie_node, Topic}),
|
||||
delete_path(lists:reverse(emqttd_topic:triples(Topic)));
|
||||
[TrieNode] ->
|
||||
mnesia:write(TrieNode#trie_node{topic=Topic});
|
||||
mnesia:write(TrieNode#trie_node{topic = undefined});
|
||||
[] ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal Functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% Add path to trie tree.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Add path to trie tree.
|
||||
add_path({Node, Word, Child}) ->
|
||||
Edge = #trie_edge{node_id=Node, word=Word},
|
||||
case mnesia:read(trie_node, Node) of
|
||||
|
|
@ -162,14 +119,8 @@ add_path({Node, Word, Child}) ->
|
|||
mnesia:write(#trie{edge=Edge, node_id=Child})
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% Match node with word or '+'.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% @doc Match node with word or '+'.
|
||||
match_node(root, [<<"$SYS">>|Words]) ->
|
||||
match_node(<<"$SYS">>, Words, []);
|
||||
|
||||
|
|
@ -187,28 +138,18 @@ match_node(NodeId, [W|Words], ResAcc) ->
|
|||
end
|
||||
end, 'match_#'(NodeId, ResAcc), [W, '+']).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% Match node with '#'.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Match node with '#'.
|
||||
'match_#'(NodeId, ResAcc) ->
|
||||
case mnesia:read(trie, #trie_edge{node_id=NodeId, word = '#'}) of
|
||||
[#trie{node_id=ChildId}] ->
|
||||
mnesia:read(trie_node, ChildId) ++ ResAcc;
|
||||
mnesia:read(trie_node, ChildId) ++ ResAcc;
|
||||
[] ->
|
||||
ResAcc
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% @private
|
||||
%% Delete paths from trie tree.
|
||||
%%
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Delete paths from trie tree.
|
||||
delete_path([]) ->
|
||||
ok;
|
||||
delete_path([{NodeId, Word, _} | RestPath]) ->
|
||||
|
|
|
|||
|
|
@ -1,100 +0,0 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd utility functions
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_util).
|
||||
|
||||
-export([apply_module_attributes/1, all_module_attributes/1, cancel_timer/1,
|
||||
now_to_secs/0, now_to_secs/1, now_to_ms/0, now_to_ms/1]).
|
||||
|
||||
-export([integer_to_binary/1]).
|
||||
|
||||
%% only {F, Args}...
|
||||
apply_module_attributes(Name) ->
|
||||
[{Module, [apply(Module, F, Args) || {F, Args} <- Attrs]} ||
|
||||
{_App, Module, Attrs} <- all_module_attributes(Name)].
|
||||
|
||||
%% copy from rabbit_misc.erl
|
||||
all_module_attributes(Name) ->
|
||||
Targets =
|
||||
lists:usort(
|
||||
lists:append(
|
||||
[[{App, Module} || Module <- Modules] ||
|
||||
{App, _, _} <- ignore_lib_apps(application:loaded_applications()),
|
||||
{ok, Modules} <- [application:get_key(App, modules)]])),
|
||||
lists:foldl(
|
||||
fun ({App, Module}, Acc) ->
|
||||
case lists:append([Atts || {N, Atts} <- module_attributes(Module),
|
||||
N =:= Name]) of
|
||||
[] -> Acc;
|
||||
Atts -> [{App, Module, Atts} | Acc]
|
||||
end
|
||||
end, [], Targets).
|
||||
|
||||
%% copy from rabbit_misc.erl
|
||||
module_attributes(Module) ->
|
||||
case catch Module:module_info(attributes) of
|
||||
{'EXIT', {undef, [{Module, module_info, _} | _]}} ->
|
||||
[];
|
||||
{'EXIT', Reason} ->
|
||||
exit(Reason);
|
||||
V ->
|
||||
V
|
||||
end.
|
||||
|
||||
ignore_lib_apps(Apps) ->
|
||||
LibApps = [kernel, stdlib, sasl,
|
||||
syntax_tools, ssl, crypto,
|
||||
mnesia, os_mon, inets,
|
||||
goldrush, lager, gproc,
|
||||
runtime_tools, snmp, otp_mibs,
|
||||
public_key, asn1, ssh,
|
||||
common_test, observer, webtool,
|
||||
xmerl, tools, test_server,
|
||||
compiler, debugger, eunit,
|
||||
et, gen_logger, wx,
|
||||
hipe, esockd, mochiweb],
|
||||
[App || App = {Name, _, _} <- Apps, not lists:member(Name, LibApps)].
|
||||
|
||||
|
||||
cancel_timer(undefined) ->
|
||||
undefined;
|
||||
cancel_timer(Ref) ->
|
||||
catch erlang:cancel_timer(Ref).
|
||||
|
||||
integer_to_binary(I) when is_integer(I) ->
|
||||
list_to_binary(integer_to_list(I)).
|
||||
|
||||
now_to_secs() ->
|
||||
now_to_secs(os:timestamp()).
|
||||
|
||||
now_to_secs({MegaSecs, Secs, _MicroSecs}) ->
|
||||
MegaSecs * 1000000 + Secs.
|
||||
|
||||
now_to_ms() ->
|
||||
now_to_ms(os:timestamp()).
|
||||
|
||||
now_to_ms({MegaSecs, Secs, MicroSecs}) ->
|
||||
(MegaSecs * 1000000 + Secs) * 1000 + round(MicroSecs/1000).
|
||||
|
||||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd erlang vm.
|
||||
%%%
|
||||
%%% @author huangdan
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_vm).
|
||||
|
||||
-export([schedulers/0]).
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd websocket client
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_ws_client).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
|
@ -50,10 +41,7 @@
|
|||
-define(WSLOG(Level, Format, Args, Req),
|
||||
lager:Level("WsClient(~s): " ++ Format, [Req:get(peer) | Args])).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start WebSocket client.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
start_link(Req) ->
|
||||
PktOpts = emqttd:env(mqtt, packet),
|
||||
ParserFun = emqttd_parser:new(PktOpts),
|
||||
|
|
@ -80,18 +68,12 @@ subscribe(CPid, TopicTable) ->
|
|||
unsubscribe(CPid, Topics) ->
|
||||
gen_server:cast(CPid, {unsubscribe, Topics}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc Start WebSocket client.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Upgrade WebSocket.
|
||||
upgrade(Req) ->
|
||||
mochiweb_websocket:upgrade_connection(Req, fun ?MODULE:ws_loop/3).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc WebSocket frame receive loop.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
ws_loop(<<>>, State, _ReplyChannel) ->
|
||||
State;
|
||||
ws_loop([<<>>], State, _ReplyChannel) ->
|
||||
|
|
@ -118,9 +100,9 @@ ws_loop(Data, State = #wsocket_state{request = Req,
|
|||
reset_parser(State = #wsocket_state{packet_opts = PktOpts}) ->
|
||||
State#wsocket_state{parser_fun = emqttd_parser:new(PktOpts)}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([WsPid, Req, ReplyChannel, PktOpts]) ->
|
||||
%%issue#413: trap_exit is unnecessary
|
||||
|
|
@ -241,9 +223,9 @@ terminate(Reason, #wsclient_state{proto_state = ProtoState, keepalive = KeepAliv
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal functions
|
||||
%%%=============================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
with_proto_state(Fun, State = #wsclient_state{proto_state = ProtoState}) ->
|
||||
{ok, ProtoState1} = Fun(ProtoState),
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqtt lager backend
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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(lager_emqtt_backend).
|
||||
|
||||
-behaviour(gen_event).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,214 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_SUITE).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
all() ->
|
||||
[{group, pubsub},
|
||||
{group, router},
|
||||
{group, session},
|
||||
{group, retainer},
|
||||
{group, broker},
|
||||
{group, metrics},
|
||||
{group, stats}].
|
||||
|
||||
groups() ->
|
||||
[{pubsub, [sequence],
|
||||
[create_topic,
|
||||
create_subscription,
|
||||
subscribe_unsubscribe,
|
||||
publish_message]},
|
||||
{router, [sequence],
|
||||
[add_delete_routes,
|
||||
add_delete_route,
|
||||
route_message]},
|
||||
{session, [sequence],
|
||||
[start_session]},
|
||||
{retainer, [sequence],
|
||||
[retain_message]},
|
||||
{broker, [sequence],
|
||||
[hook_unhook]},
|
||||
{metrics, [sequence],
|
||||
[inc_dec_metric]},
|
||||
{stats, [sequence],
|
||||
[set_get_stat]}].
|
||||
|
||||
init_per_suite(Config) ->
|
||||
application:start(lager),
|
||||
application:ensure_all_started(emqttd),
|
||||
Config.
|
||||
|
||||
end_per_suite(_Config) ->
|
||||
application:stop(emqttd),
|
||||
application:stop(esockd),
|
||||
application:stop(gproc),
|
||||
emqttd_mnesia:ensure_stopped().
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% PubSub Group
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
create_topic(_) ->
|
||||
Node = node(),
|
||||
ok = emqttd_pubsub:create(topic, <<"topic/create">>),
|
||||
ok = emqttd_pubsub:create(topic, <<"topic/create2">>),
|
||||
[#mqtt_topic{topic = <<"topic/create">>, node = Node}]
|
||||
= emqttd_pubsub:lookup(topic, <<"topic/create">>).
|
||||
|
||||
create_subscription(_) ->
|
||||
ok = emqttd_pubsub:create(subscription, {<<"clientId">>, <<"topic/sub">>, qos2}),
|
||||
[#mqtt_subscription{subid = <<"clientId">>, topic = <<"topic/sub">>, qos = 2}]
|
||||
= emqttd_pubsub:lookup(subscription, <<"clientId">>),
|
||||
ok = emqttd_pubsub:delete(subscription, <<"clientId">>),
|
||||
[] = emqttd_pubsub:lookup(subscription, <<"clientId">>).
|
||||
|
||||
subscribe_unsubscribe(_) ->
|
||||
{ok, [1]} = emqttd_pubsub:subscribe({<<"topic/subunsub">>, 1}),
|
||||
{ok, [1, 2]} = emqttd_pubsub:subscribe([{<<"topic/subunsub1">>, 1}, {<<"topic/subunsub2">>, 2}]),
|
||||
ok = emqttd_pubsub:unsubscribe(<<"topic/subunsub">>),
|
||||
ok = emqttd_pubsub:unsubscribe([<<"topic/subunsub1">>, <<"topic/subunsub2">>]),
|
||||
|
||||
{ok, [1]} = emqttd_pubsub:subscribe(<<"client_subunsub">>, {<<"topic/subunsub">>, 1}),
|
||||
{ok, [1,2]} = emqttd_pubsub:subscribe(<<"client_subunsub">>, [{<<"topic/subunsub1">>, 1},
|
||||
{<<"topic/subunsub2">>, 2}]),
|
||||
ok = emqttd_pubsub:unsubscribe(<<"client_subunsub">>, <<"topic/subunsub">>),
|
||||
ok = emqttd_pubsub:unsubscribe(<<"client_subunsub">>, [<<"topic/subunsub1">>,
|
||||
<<"topic/subunsub2">>]).
|
||||
|
||||
publish_message(_) ->
|
||||
Msg = emqttd_message:make(ct, <<"test/pubsub">>, <<"hello">>),
|
||||
{ok, [1]} = emqttd_pubsub:subscribe({<<"test/+">>, qos1}),
|
||||
emqttd_pubsub:publish(Msg),
|
||||
true = receive {dispatch, <<"test/+">>, Msg} -> true after 5 -> false end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Route Group
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
add_delete_route(_) ->
|
||||
Self = self(),
|
||||
emqttd_router:add_route(<<"topic1">>, Self),
|
||||
true = emqttd_router:has_route(<<"topic1">>),
|
||||
emqttd_router:add_route(<<"topic2">>, Self),
|
||||
true = emqttd_router:has_route(<<"topic2">>),
|
||||
[Self] = emqttd_router:lookup_routes(<<"topic1">>),
|
||||
[Self] = emqttd_router:lookup_routes(<<"topic2">>),
|
||||
%% Del topic1
|
||||
emqttd_router:delete_route(<<"topic1">>, Self),
|
||||
erlang:yield(),
|
||||
timer:sleep(10),
|
||||
false = emqttd_router:has_route(<<"topic1">>),
|
||||
%% Del topic2
|
||||
emqttd_router:delete_route(<<"topic2">>, Self),
|
||||
erlang:yield(),
|
||||
timer:sleep(10),
|
||||
false = emqttd_router:has_route(<<"topic2">>).
|
||||
|
||||
add_delete_routes(_) ->
|
||||
Self = self(),
|
||||
emqttd_router:add_routes([], Self),
|
||||
emqttd_router:add_routes([<<"t0">>], Self),
|
||||
emqttd_router:add_routes([<<"t1">>,<<"t2">>,<<"t3">>], Self),
|
||||
true = emqttd_router:has_route(<<"t1">>),
|
||||
[Self] = emqttd_router:lookup_routes(<<"t1">>),
|
||||
[Self] = emqttd_router:lookup_routes(<<"t2">>),
|
||||
[Self] = emqttd_router:lookup_routes(<<"t3">>),
|
||||
|
||||
emqttd_router:delete_routes([<<"t3">>], Self),
|
||||
emqttd_router:delete_routes([<<"t0">>, <<"t1">>], Self),
|
||||
erlang:yield(),
|
||||
timer:sleep(10),
|
||||
false = emqttd_router:has_route(<<"t0">>),
|
||||
false = emqttd_router:has_route(<<"t1">>),
|
||||
true = emqttd_router:has_route(<<"t2">>),
|
||||
false = emqttd_router:has_route(<<"t3">>).
|
||||
|
||||
route_message(_) ->
|
||||
Self = self(),
|
||||
Pid = spawn_link(fun() -> timer:sleep(1000) end),
|
||||
emqttd_router:add_routes([<<"$Q/1">>,<<"t/2">>,<<"t/3">>], Self),
|
||||
emqttd_router:add_routes([<<"t/2">>], Pid),
|
||||
Msg1 = #mqtt_message{topic = <<"$Q/1">>, payload = <<"q">>},
|
||||
Msg2 = #mqtt_message{topic = <<"t/2">>, payload = <<"t2">>},
|
||||
Msg3 = #mqtt_message{topic = <<"t/3">>, payload = <<"t3">>},
|
||||
emqttd_router:route(<<"$Q/1">>, Msg1),
|
||||
emqttd_router:route(<<"t/2">>, Msg2),
|
||||
emqttd_router:route(<<"t/3">>, Msg3),
|
||||
[Msg1, Msg2, Msg3] = recv_loop([]),
|
||||
emqttd_router:add_route(<<"$Q/1">>, Self),
|
||||
emqttd_router:route(<<"$Q/1">>, Msg1).
|
||||
|
||||
recv_loop(Msgs) ->
|
||||
receive
|
||||
{dispatch, _Topic, Msg} ->
|
||||
recv_loop([Msg|Msgs])
|
||||
after
|
||||
100 -> lists:reverse(Msgs)
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Session Group
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
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">>),
|
||||
Message1 = Message#mqtt_message{pktid = 1},
|
||||
emqttd_session:publish(SessPid, Message1),
|
||||
emqttd_session:pubrel(SessPid, 1),
|
||||
emqttd_session:subscribe(SessPid, [{<<"topic/session">>, 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).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Retainer Group
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
retain_message(_) ->
|
||||
Msg = #mqtt_message{retain = true, topic = <<"a/b/c">>,
|
||||
payload = <<"payload">>},
|
||||
emqttd_retainer:retain(Msg),
|
||||
emqttd_retainer:dispatch(<<"a/b/+">>, self()),
|
||||
true = receive {dispatch, <<"a/b/+">>, Msg} -> true after 10 -> false end,
|
||||
emqttd_retainer:retain(#mqtt_message{retain = true, topic = <<"a/b/c">>, payload = <<>>}),
|
||||
[] = mnesia:dirty_read({retained, <<"a/b/c">>}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Broker Group
|
||||
%%--------------------------------------------------------------------
|
||||
hook_unhook(_) ->
|
||||
ok.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Metric Group
|
||||
%%--------------------------------------------------------------------
|
||||
inc_dec_metric(_) ->
|
||||
emqttd_metrics:inc(gauge, 'messages/retained', 10),
|
||||
emqttd_metrics:dec(gauge, 'messages/retained', 10).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Stats Group
|
||||
%%--------------------------------------------------------------------
|
||||
set_get_stat(_) ->
|
||||
emqttd_stats:setstat('retained/max', 99),
|
||||
99 = emqttd_stats:getstat('retained/max').
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_access_SUITE).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-define(AC, emqttd_access_control).
|
||||
|
||||
-import(emqttd_access_rule, [compile/1, match/3]).
|
||||
|
||||
all() ->
|
||||
[{group, access_control},
|
||||
{group, access_rule}].
|
||||
|
||||
groups() ->
|
||||
[{access_control, [sequence],
|
||||
[reload_acl,
|
||||
register_mod,
|
||||
unregister_mod,
|
||||
check_acl]},
|
||||
{access_rule, [],
|
||||
[compile_rule,
|
||||
match_rule]}].
|
||||
|
||||
init_per_group(_Group, Config) ->
|
||||
Config.
|
||||
|
||||
end_per_group(_Group, Config) ->
|
||||
Config.
|
||||
|
||||
init_per_testcase(TestCase, Config) when TestCase =:= reload_acl;
|
||||
TestCase =:= register_mod;
|
||||
TestCase =:= unregister_mod;
|
||||
TestCase =:= check_acl ->
|
||||
DataDir = proplists:get_value(data_dir, Config),
|
||||
AclOpts = [
|
||||
{auth, [{anonymous, []}]},
|
||||
{acl, [{internal, [{file, filename:join([DataDir, "test_acl.config"])},
|
||||
{nomatch, allow}]}]}
|
||||
],
|
||||
{ok, _Pid} = ?AC:start_link(AclOpts),
|
||||
Config;
|
||||
|
||||
init_per_testcase(_TestCase, Config) ->
|
||||
Config.
|
||||
|
||||
end_per_testcase(TestCase, _Config) when TestCase =:= reload_acl;
|
||||
TestCase =:= register_mod;
|
||||
TestCase =:= unregister_mod;
|
||||
TestCase =:= check_acl ->
|
||||
?AC:stop();
|
||||
|
||||
end_per_testcase(_TestCase, _Config) ->
|
||||
ok.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% emqttd_access_control
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
reload_acl(_) ->
|
||||
ct:print("~p~n", [whereis(?AC)]),
|
||||
[ok] = ?AC:reload_acl().
|
||||
|
||||
register_mod(_) ->
|
||||
ok = ?AC:register_mod(acl, emqttd_acl_test_mod, []),
|
||||
[{emqttd_acl_test_mod, _, 0},
|
||||
{emqttd_acl_internal, _, 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},
|
||||
{emqttd_auth_anonymous, _, 0}] = ?AC:lookup_mods(auth).
|
||||
|
||||
unregister_mod(_) ->
|
||||
ok = ?AC:register_mod(acl, emqttd_acl_test_mod, []),
|
||||
[{emqttd_acl_test_mod, _, 0},
|
||||
{emqttd_acl_internal, _, 0}] = ?AC:lookup_mods(acl),
|
||||
ok = ?AC:unregister_mod(acl, emqttd_acl_test_mod),
|
||||
timer:sleep(5),
|
||||
[{emqttd_acl_internal, _, 0}] = ?AC:lookup_mods(acl),
|
||||
ok = ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
|
||||
[{emqttd_auth_anonymous_test_mod, _, 0},
|
||||
{emqttd_auth_anonymous, _, 0}] = ?AC:lookup_mods(auth),
|
||||
|
||||
ok = ?AC:unregister_mod(auth, emqttd_auth_anonymous_test_mod),
|
||||
timer:sleep(5),
|
||||
[{emqttd_auth_anonymous, _, 0}] = ?AC:lookup_mods(auth).
|
||||
|
||||
check_acl(_) ->
|
||||
User1 = #mqtt_client{client_id = <<"client1">>, username = <<"testuser">>},
|
||||
User2 = #mqtt_client{client_id = <<"client2">>, username = <<"xyz">>},
|
||||
allow = ?AC:check_acl(User1, subscribe, <<"users/testuser/1">>),
|
||||
allow = ?AC:check_acl(User1, subscribe, <<"clients/client1">>),
|
||||
deny = ?AC:check_acl(User1, subscribe, <<"clients/client1/x/y">>),
|
||||
allow = ?AC:check_acl(User1, publish, <<"users/testuser/1">>),
|
||||
allow = ?AC:check_acl(User1, subscribe, <<"a/b/c">>),
|
||||
deny = ?AC:check_acl(User2, subscribe, <<"a/b/c">>).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% emqttd_access_rule
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
compile_rule(_) ->
|
||||
|
||||
{allow, {'and', [{ipaddr, {"127.0.0.1", _I, _I}},
|
||||
{user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
|
||||
compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]}),
|
||||
{allow, {'or', [{ipaddr, {"127.0.0.1", _I, _I}},
|
||||
{user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
|
||||
compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]}),
|
||||
|
||||
{allow, {ipaddr, {"127.0.0.1", _I, _I}}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
|
||||
compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}),
|
||||
{allow, {user, <<"testuser">>}, subscribe, [ [<<"a">>, <<"b">>, <<"c">>], [<<"d">>, <<"e">>, <<"f">>, '#'] ]} =
|
||||
compile({allow, {user, "testuser"}, subscribe, ["a/b/c", "d/e/f/#"]}),
|
||||
{allow, {user, <<"admin">>}, pubsub, [ [<<"d">>, <<"e">>, <<"f">>, '#'] ]} =
|
||||
compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]}),
|
||||
{allow, {client, <<"testClient">>}, publish, [ [<<"testTopics">>, <<"testClient">>] ]} =
|
||||
compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]}),
|
||||
{allow, all, pubsub, [{pattern, [<<"clients">>, <<"$c">>]}]} =
|
||||
compile({allow, all, pubsub, ["clients/$c"]}),
|
||||
{allow, all, subscribe, [{pattern, [<<"users">>, <<"$u">>, '#']}]} =
|
||||
compile({allow, all, subscribe, ["users/$u/#"]}),
|
||||
{deny, all, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
|
||||
compile({deny, all, subscribe, ["$SYS/#", "#"]}),
|
||||
{allow, all} = compile({allow, all}),
|
||||
{deny, all} = compile({deny, all}).
|
||||
|
||||
match_rule(_) ->
|
||||
User = #mqtt_client{peername = {{127,0,0,1}, 2948}, client_id = <<"testClient">>, username = <<"TestUser">>},
|
||||
User2 = #mqtt_client{peername = {{192,168,0,10}, 3028}, client_id = <<"testClient">>, username = <<"TestUser">>},
|
||||
|
||||
{matched, allow} = match(User, <<"Test/Topic">>, {allow, all}),
|
||||
{matched, deny} = match(User, <<"Test/Topic">>, {deny, all}),
|
||||
{matched, allow} = match(User, <<"Test/Topic">>, compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]})),
|
||||
{matched, allow} = match(User2, <<"Test/Topic">>, compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]})),
|
||||
{matched, allow} = match(User, <<"d/e/f/x">>, compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]})),
|
||||
nomatch = match(User, <<"d/e/f/x">>, compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]})),
|
||||
{matched, allow} = match(User, <<"testTopics/testClient">>, compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]})),
|
||||
{matched, allow} = match(User, <<"clients/testClient">>, compile({allow, all, pubsub, ["clients/$c"]})),
|
||||
{matched, allow} = match(#mqtt_client{username = <<"user2">>}, <<"users/user2/abc/def">>,
|
||||
compile({allow, all, subscribe, ["users/$u/#"]})),
|
||||
{matched, deny} = match(User, <<"d/e/f">>, compile({deny, all, subscribe, ["$SYS/#", "#"]})),
|
||||
Rule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}),
|
||||
nomatch = match(User, <<"Topic">>, Rule),
|
||||
AndRule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}),
|
||||
{matched, allow} = match(User, <<"Topic">>, AndRule),
|
||||
OrRule = compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}),
|
||||
{matched, allow} = match(User, <<"Topic">>, OrRule).
|
||||
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% emqttd_access_control tests.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_access_control_tests).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-ifdef(TEST).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
reload_acl_test() ->
|
||||
with_acl(
|
||||
fun() ->
|
||||
?assertEqual([ok], emqttd_access_control:reload_acl())
|
||||
end).
|
||||
|
||||
register_mod_test() ->
|
||||
with_acl(
|
||||
fun() ->
|
||||
emqttd_access_control:register_mod(acl, emqttd_acl_test_mod, []),
|
||||
?assertMatch([{emqttd_acl_test_mod, _, 0}, {emqttd_acl_internal, _, 0}],
|
||||
emqttd_access_control:lookup_mods(acl)),
|
||||
emqttd_access_control:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
|
||||
emqttd_access_control:register_mod(auth, emqttd_auth_dashboard, [], 99),
|
||||
?assertMatch([{emqttd_auth_dashboard, _, 99},
|
||||
{emqttd_auth_anonymous_test_mod, _, 0},
|
||||
{emqttd_auth_anonymous, _, 0}],
|
||||
emqttd_access_control:lookup_mods(auth))
|
||||
end).
|
||||
|
||||
unregister_mod_test() ->
|
||||
with_acl(
|
||||
fun() ->
|
||||
emqttd_access_control:register_mod(acl, emqttd_acl_test_mod, []),
|
||||
?assertMatch([{emqttd_acl_test_mod, _, 0}, {emqttd_acl_internal, _, 0}],
|
||||
emqttd_access_control:lookup_mods(acl)),
|
||||
emqttd_access_control:unregister_mod(acl, emqttd_acl_test_mod),
|
||||
timer:sleep(5),
|
||||
?assertMatch([{emqttd_acl_internal, _, 0}], emqttd_access_control:lookup_mods(acl)),
|
||||
|
||||
emqttd_access_control:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
|
||||
?assertMatch([{emqttd_auth_anonymous_test_mod, _, 0}, {emqttd_auth_anonymous, _, 0}],
|
||||
emqttd_access_control:lookup_mods(auth)),
|
||||
|
||||
emqttd_access_control:unregister_mod(auth, emqttd_auth_anonymous_test_mod),
|
||||
timer:sleep(5),
|
||||
?assertMatch([{emqttd_auth_anonymous, _, 0}], emqttd_access_control:lookup_mods(auth))
|
||||
end).
|
||||
|
||||
check_acl_test() ->
|
||||
with_acl(
|
||||
fun() ->
|
||||
User1 = #mqtt_client{client_id = <<"client1">>, username = <<"testuser">>},
|
||||
User2 = #mqtt_client{client_id = <<"client2">>, username = <<"xyz">>},
|
||||
?assertEqual(allow, emqttd_access_control:check_acl(User1, subscribe, <<"users/testuser/1">>)),
|
||||
?assertEqual(allow, emqttd_access_control:check_acl(User1, subscribe, <<"clients/client1">>)),
|
||||
?assertEqual(deny, emqttd_access_control:check_acl(User1, subscribe, <<"clients/client1/x/y">>)),
|
||||
?assertEqual(allow, emqttd_access_control:check_acl(User1, publish, <<"users/testuser/1">>)),
|
||||
?assertEqual(allow, emqttd_access_control:check_acl(User1, subscribe, <<"a/b/c">>)),
|
||||
?assertEqual(deny, emqttd_access_control:check_acl(User2, subscribe, <<"a/b/c">>))
|
||||
end).
|
||||
|
||||
with_acl(Fun) ->
|
||||
process_flag(trap_exit, true),
|
||||
AclOpts = [
|
||||
{auth, [
|
||||
%% Authentication with username, password
|
||||
%{username, []},
|
||||
%% Authentication with clientid
|
||||
%{clientid, [{password, no}, {file, "etc/clients.config"}]},
|
||||
%% Allow all
|
||||
{anonymous, []}
|
||||
]},
|
||||
%% ACL config
|
||||
{acl, [
|
||||
%% Internal ACL module
|
||||
{internal, [{file, "../test/test_acl.config"}, {nomatch, allow}]}
|
||||
]}
|
||||
],
|
||||
%application:set_env(emqttd, access, AclOpts),
|
||||
emqttd_access_control:start_link(AclOpts),
|
||||
Fun(),
|
||||
emqttd_access_control:stop().
|
||||
|
||||
-endif.
|
||||
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% emqttd_access_rule tests.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_access_rule_tests).
|
||||
|
||||
-import(emqttd_access_rule, [compile/1, match/3]).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-ifdef(TEST).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
compile_test() ->
|
||||
|
||||
?assertMatch({allow, {'and', [{ipaddr, {"127.0.0.1", _I, _I}},
|
||||
{user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]})),
|
||||
?assertMatch({allow, {'or', [{ipaddr, {"127.0.0.1", _I, _I}},
|
||||
{user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]})),
|
||||
|
||||
?assertMatch({allow, {ipaddr, {"127.0.0.1", _I, _I}}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]})),
|
||||
?assertMatch({allow, {user, <<"testuser">>}, subscribe, [ [<<"a">>, <<"b">>, <<"c">>], [<<"d">>, <<"e">>, <<"f">>, '#'] ]},
|
||||
compile({allow, {user, "testuser"}, subscribe, ["a/b/c", "d/e/f/#"]})),
|
||||
?assertEqual({allow, {user, <<"admin">>}, pubsub, [ [<<"d">>, <<"e">>, <<"f">>, '#'] ]},
|
||||
compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]})),
|
||||
?assertEqual({allow, {client, <<"testClient">>}, publish, [ [<<"testTopics">>, <<"testClient">>] ]},
|
||||
compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]})),
|
||||
?assertEqual({allow, all, pubsub, [{pattern, [<<"clients">>, <<"$c">>]}]},
|
||||
compile({allow, all, pubsub, ["clients/$c"]})),
|
||||
?assertEqual({allow, all, subscribe, [{pattern, [<<"users">>, <<"$u">>, '#']}]},
|
||||
compile({allow, all, subscribe, ["users/$u/#"]})),
|
||||
?assertEqual({deny, all, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({deny, all, subscribe, ["$SYS/#", "#"]})),
|
||||
?assertEqual({allow, all}, compile({allow, all})),
|
||||
?assertEqual({deny, all}, compile({deny, all})).
|
||||
|
||||
match_test() ->
|
||||
User = #mqtt_client{peername = {{127,0,0,1}, 2948}, client_id = <<"testClient">>, username = <<"TestUser">>},
|
||||
User2 = #mqtt_client{peername = {{192,168,0,10}, 3028}, client_id = <<"testClient">>, username = <<"TestUser">>},
|
||||
|
||||
?assertEqual({matched, allow}, match(User, <<"Test/Topic">>, {allow, all})),
|
||||
?assertEqual({matched, deny}, match(User, <<"Test/Topic">>, {deny, all})),
|
||||
?assertMatch({matched, allow}, match(User, <<"Test/Topic">>,
|
||||
compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}))),
|
||||
?assertMatch({matched, allow}, match(User2, <<"Test/Topic">>,
|
||||
compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]}))),
|
||||
?assertMatch({matched, allow}, match(User, <<"d/e/f/x">>, compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]}))),
|
||||
?assertEqual(nomatch, match(User, <<"d/e/f/x">>, compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]}))),
|
||||
?assertMatch({matched, allow}, match(User, <<"testTopics/testClient">>,
|
||||
compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]}))),
|
||||
?assertMatch({matched, allow}, match(User, <<"clients/testClient">>,
|
||||
compile({allow, all, pubsub, ["clients/$c"]}))),
|
||||
?assertMatch({matched, allow}, match(#mqtt_client{username = <<"user2">>}, <<"users/user2/abc/def">>,
|
||||
compile({allow, all, subscribe, ["users/$u/#"]}))),
|
||||
?assertMatch({matched, deny}, match(User, <<"d/e/f">>,
|
||||
compile({deny, all, subscribe, ["$SYS/#", "#"]}))),
|
||||
Rule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}),
|
||||
?assertMatch(nomatch, match(User, <<"Topic">>, Rule)),
|
||||
AndRule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}),
|
||||
?assertMatch({matched, allow}, match(User, <<"Topic">>, AndRule)),
|
||||
OrRule = compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}),
|
||||
?assertMatch({matched, allow}, match(User, <<"Topic">>, OrRule)).
|
||||
|
||||
-endif.
|
||||
|
||||
|
||||
|
|
@ -1,29 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% Test ACL Module.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_acl_test_mod).
|
||||
|
||||
%% ACL callbacks
|
||||
|
|
|
|||
|
|
@ -1,29 +1,19 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% Test ACL Module.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_auth_anonymous_test_mod).
|
||||
|
||||
%% ACL callbacks
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_auth_dashboard).
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2016 Feng Lee <feng@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_backend_SUITE).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
all() -> [{group, retainer}].
|
||||
|
||||
groups() -> [{retainer, [], [t_retain]}].
|
||||
|
||||
init_per_group(retainer, _Config) ->
|
||||
ok = emqttd_mnesia:ensure_started(),
|
||||
emqttd_retainer:mnesia(boot),
|
||||
emqttd_retainer:mnesia(copy).
|
||||
|
||||
end_per_group(retainer, _Config) ->
|
||||
ok;
|
||||
end_per_group(_Group, _Config) ->
|
||||
ok.
|
||||
|
||||
t_retain(_) -> ok.
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_guid_tests).
|
||||
|
||||
-ifdef(TEST).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
gen_test() ->
|
||||
Guid1 = emqttd_guid:gen(),
|
||||
Guid2 = emqttd_guid:gen(),
|
||||
?assertMatch(<<_:128>>, Guid1),
|
||||
?assertEqual(true, Guid2 >= Guid1).
|
||||
|
||||
-endif.
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue