Upgrade for MQTT Version 5.0 and Erlang/OTP R21
This commit is contained in:
parent
e57411c3e0
commit
62aa072f2f
|
@ -6,6 +6,6 @@
|
|||
{applications,[kernel,stdlib,gproc,lager,esockd,mochiweb,lager_syslog,pbkdf2,bcrypt,clique,jsx]},
|
||||
{env,[]},
|
||||
{mod,{emqx_app,[]}},
|
||||
{maintainers,["Feng Lee <feng@emqtt.io>"]},
|
||||
{maintainers,["Feng Lee <feng@emqx.io>"]},
|
||||
{licenses,["Apache-2.0"]},
|
||||
{links,[{"Github","https://github.com/emqx/emqx"}]}]}.
|
||||
|
|
56
src/emqx.erl
56
src/emqx.erl
|
@ -1,42 +1,36 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
%% Start/Stop Application
|
||||
%% Start/Stop the application
|
||||
-export([start/0, is_running/1, stop/0]).
|
||||
|
||||
%% PubSub API
|
||||
-export([subscribe/1, subscribe/2, subscribe/3, publish/1,
|
||||
unsubscribe/1, unsubscribe/2]).
|
||||
-export([subscribe/1, subscribe/2, subscribe/3]).
|
||||
-export([publish/1]).
|
||||
-export([unsubscribe/1, unsubscribe/2]).
|
||||
|
||||
%% PubSub management API
|
||||
-export([topics/0, subscriptions/1, subscribers/1, subscribed/2]).
|
||||
|
||||
%% Get/Set suboptions
|
||||
-export([get_subopts/2, set_subopts/3]).
|
||||
|
||||
%% Hooks API
|
||||
-export([hook/4, hook/3, unhook/2, run_hooks/2, run_hooks/3]).
|
||||
|
||||
%% Debug API
|
||||
-export([dump/0]).
|
||||
|
||||
%% Shutdown and reboot
|
||||
-export([shutdown/0, shutdown/1, reboot/0]).
|
||||
|
||||
|
@ -76,16 +70,16 @@ is_running(Node) ->
|
|||
subscribe(Topic) ->
|
||||
emqx_broker:subscribe(iolist_to_binary(Topic)).
|
||||
|
||||
-spec(subscribe(topic() | iodata(), subscriber() | string()) -> ok | {error, term()}).
|
||||
-spec(subscribe(topic() | string(), subscriber() | string()) -> ok | {error, term()}).
|
||||
subscribe(Topic, Subscriber) ->
|
||||
emqx_broker:subscribe(iolist_to_binary(Topic), list_to_subid(Subscriber)).
|
||||
|
||||
-spec(subscribe(topic() | iodata(), subscriber() | string(), [suboption()]) -> ok | {error, term()}).
|
||||
-spec(subscribe(topic() | string(), subscriber() | string(), [suboption()]) -> ok | {error, term()}).
|
||||
subscribe(Topic, Subscriber, Options) ->
|
||||
emqx_broker:subscribe(iolist_to_binary(Topic), list_to_subid(Subscriber), Options).
|
||||
|
||||
%% @doc Publish Message
|
||||
-spec(publish(message()) -> {ok, delivery()} | ignore).
|
||||
-spec(publish(message()) -> {ok, delivery()} | {error, term()}).
|
||||
publish(Msg) ->
|
||||
emqx_broker:publish(Msg).
|
||||
|
||||
|
@ -118,7 +112,7 @@ subscribers(Topic) ->
|
|||
|
||||
-spec(subscriptions(subscriber() | string()) -> [{topic(), list(suboption())}]).
|
||||
subscriptions(Subscriber) ->
|
||||
emqx_broker:subscriptions(Subscriber).
|
||||
emqx_broker:subscriptions(list_to_subid(Subscriber)).
|
||||
|
||||
-spec(subscribed(topic() | string(), subscriber()) -> boolean()).
|
||||
subscribed(Topic, Subscriber) ->
|
||||
|
@ -170,16 +164,10 @@ shutdown() ->
|
|||
shutdown(normal).
|
||||
|
||||
shutdown(Reason) ->
|
||||
emqx_logger:error("EMQ shutdown for ~s", [Reason]),
|
||||
emqx_logger:error("emqx shutdown for ~s", [Reason]),
|
||||
emqx_plugins:unload(),
|
||||
lists:foreach(fun application:stop/1, [emqx, ekka, mochiweb, esockd, gproc]).
|
||||
|
||||
reboot() ->
|
||||
lists:foreach(fun application:start/1, [gproc, esockd, mochiweb, ekka, emqx]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Debug
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
dump() -> lists:append([emqx_broker:dump(), emqx_router:dump()]).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_access_control).
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_access_rule).
|
||||
|
||||
|
@ -73,8 +71,7 @@ compile(topic, Topic) ->
|
|||
end.
|
||||
|
||||
'pattern?'(Words) ->
|
||||
lists:member(<<"%u">>, Words)
|
||||
orelse lists:member(<<"%c">>, Words).
|
||||
lists:member(<<"%u">>, Words) orelse lists:member(<<"%c">>, Words).
|
||||
|
||||
bin(L) when is_list(L) ->
|
||||
list_to_binary(L);
|
||||
|
@ -99,7 +96,7 @@ match_who(_Client, {user, all}) ->
|
|||
true;
|
||||
match_who(_Client, {client, all}) ->
|
||||
true;
|
||||
match_who(#client{client_id = ClientId}, {client, ClientId}) ->
|
||||
match_who(#client{id = ClientId}, {client, ClientId}) ->
|
||||
true;
|
||||
match_who(#client{username = Username}, {user, Username}) ->
|
||||
true;
|
||||
|
@ -137,9 +134,9 @@ feed_var(Client, Pattern) ->
|
|||
feed_var(Client, Pattern, []).
|
||||
feed_var(_Client, [], Acc) ->
|
||||
lists:reverse(Acc);
|
||||
feed_var(Client = #client{client_id = undefined}, [<<"%c">>|Words], Acc) ->
|
||||
feed_var(Client = #client{id = undefined}, [<<"%c">>|Words], Acc) ->
|
||||
feed_var(Client, Words, [<<"%c">>|Acc]);
|
||||
feed_var(Client = #client{client_id = ClientId}, [<<"%c">>|Words], Acc) ->
|
||||
feed_var(Client = #client{id = ClientId}, [<<"%c">>|Words], Acc) ->
|
||||
feed_var(Client, Words, [ClientId |Acc]);
|
||||
feed_var(Client = #client{username = undefined}, [<<"%u">>|Words], Acc) ->
|
||||
feed_var(Client, Words, [<<"%u">>|Acc]);
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_acl_internal).
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_acl_mod).
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,29 +11,24 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_alarm).
|
||||
-module(emqx_alarm_mgr).
|
||||
|
||||
-behaviour(gen_event).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
-define(ALARM_MGR, ?MODULE).
|
||||
|
||||
%% API Function Exports
|
||||
-export([start_link/0, alarm_fun/0, get_alarms/0,
|
||||
set_alarm/1, clear_alarm/1,
|
||||
add_alarm_handler/1, add_alarm_handler/2,
|
||||
delete_alarm_handler/1]).
|
||||
-export([start_link/0]).
|
||||
-export([alarm_fun/0, get_alarms/0, set_alarm/1, clear_alarm/1]).
|
||||
-export([add_alarm_handler/1, add_alarm_handler/2, delete_alarm_handler/1]).
|
||||
|
||||
%% gen_event callbacks
|
||||
-export([init/1, handle_event/2, handle_call/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
-define(ALARM_MGR, ?MODULE).
|
||||
|
||||
-record(state, {alarms}).
|
||||
|
||||
start_link() ->
|
||||
start_with(fun(Pid) -> gen_event:add_handler(Pid, ?MODULE, []) end).
|
||||
|
@ -75,70 +69,72 @@ 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
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init(_) -> {ok, []}.
|
||||
init(_) -> {ok, #state{alarms = []}}.
|
||||
|
||||
handle_event({set_alarm, Alarm = #alarm{id = AlarmId,
|
||||
severity = Severity,
|
||||
title = Title,
|
||||
summary = Summary}}, Alarms)->
|
||||
TS = os:timestamp(),
|
||||
case catch emqx_json:encode([{id, AlarmId},
|
||||
{severity, Severity},
|
||||
{title, iolist_to_binary(Title)},
|
||||
{summary, iolist_to_binary(Summary)},
|
||||
{ts, emqx_time:now_secs(TS)}]) of
|
||||
{'EXIT', Reason} ->
|
||||
emqx_logger:error("[Alarm] Failed to encode set_alarm: ~p", [Reason]);
|
||||
JSON ->
|
||||
emqx_broker:publish(alarm_msg(alert, AlarmId, JSON))
|
||||
handle_event({set_alarm, Alarm = #alarm{timestamp = undefined}}, State)->
|
||||
handle_event({set_alarm, Alarm#alarm{timestamp = os:timestamp()}}, State);
|
||||
|
||||
handle_event({set_alarm, Alarm = #alarm{id = AlarmId}}, State = #state{alarms = Alarms}) ->
|
||||
case encode_alarm(Alarm) of
|
||||
{ok, Json} ->
|
||||
emqx_broker:safe_publish(alarm_msg(alert, AlarmId, Json));
|
||||
{error, Reason} ->
|
||||
emqx_logger:error("[AlarmMgr] Failed to encode alarm: ~p", [Reason])
|
||||
end,
|
||||
{ok, [Alarm#alarm{timestamp = TS} | Alarms]};
|
||||
{ok, State#state{alarms = [Alarm|Alarms]}};
|
||||
|
||||
handle_event({clear_alarm, AlarmId}, Alarms) ->
|
||||
case catch emqx_json:encode([{id, AlarmId}, {ts, emqx_time:now_secs()}]) of
|
||||
{'EXIT', Reason} ->
|
||||
emqx_logger:error("[Alarm] Failed to encode clear_alarm: ~p", [Reason]);
|
||||
JSON ->
|
||||
emqx_broker:publish(alarm_msg(clear, AlarmId, JSON))
|
||||
handle_event({clear_alarm, AlarmId}, State = #state{alarms = Alarms}) ->
|
||||
case emqx_json:safe_encode([{id, AlarmId}, {ts, emqx_time:now_secs()}]) of
|
||||
{ok, Json} ->
|
||||
emqx_broker:safe_publish(alarm_msg(clear, AlarmId, Json));
|
||||
{error, Reason} ->
|
||||
emqx_logger:error("[AlarmMgr] Failed to encode clear: ~p", [Reason])
|
||||
end,
|
||||
{ok, lists:keydelete(AlarmId, 2, Alarms), hibernate};
|
||||
{ok, State#state{alarms = lists:keydelete(AlarmId, 2, Alarms)}, hibernate};
|
||||
|
||||
handle_event(_, Alarms)->
|
||||
{ok, Alarms}.
|
||||
handle_event(Event, State)->
|
||||
error_logger:error("[AlarmMgr] unexpected event: ~p", [Event]),
|
||||
{ok, State}.
|
||||
|
||||
handle_info(_, Alarms) ->
|
||||
{ok, Alarms}.
|
||||
handle_info(Info, State) ->
|
||||
error_logger:error("[AlarmMgr] unexpected info: ~p", [Info]),
|
||||
{ok, State}.
|
||||
|
||||
handle_call(get_alarms, Alarms) ->
|
||||
{ok, Alarms, Alarms};
|
||||
handle_call(get_alarms, State = #state{alarms = Alarms}) ->
|
||||
{ok, Alarms, State};
|
||||
|
||||
handle_call(_Query, Alarms) ->
|
||||
{ok, {error, bad_query}, Alarms}.
|
||||
|
||||
terminate(swap, Alarms) ->
|
||||
{?MODULE, Alarms};
|
||||
handle_call(Req, State) ->
|
||||
error_logger:error("[AlarmMgr] unexpected call: ~p", [Req]),
|
||||
{ok, ignored, State}.
|
||||
|
||||
terminate(swap, State) ->
|
||||
{?MODULE, State};
|
||||
terminate(_, _) ->
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
encode_alarm(#alarm{id = AlarmId, severity = Severity, title = Title,
|
||||
summary = Summary, timestamp = Ts}) ->
|
||||
emqx_json:safe_encode([{id, AlarmId}, {severity, Severity},
|
||||
{title, iolist_to_binary(Title)},
|
||||
{summary, iolist_to_binary(Summary)},
|
||||
{ts, emqx_time:now_secs(Ts)}]).
|
||||
|
||||
alarm_msg(Type, AlarmId, Json) ->
|
||||
Msg = emqx_message:make(alarm, topic(Type, AlarmId), iolist_to_binary(Json)),
|
||||
emqx_message:set_flag(sys, Msg).
|
||||
emqx_message:make(?ALARM_MGR, #{sys => true, qos => 0}, topic(Type, AlarmId), Json).
|
||||
|
||||
topic(alert, AlarmId) ->
|
||||
emqx_topic:systop(<<"alarms/", AlarmId/binary, "/alert">>);
|
||||
|
||||
topic(clear, AlarmId) ->
|
||||
emqx_topic:systop(<<"alarms/", AlarmId/binary, "/clear">>).
|
||||
|
|
@ -1,24 +1,21 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_app).
|
||||
|
||||
-behaviour(application).
|
||||
|
||||
%% Application callbacks
|
||||
-export([start/2, stop/1]).
|
||||
|
||||
-define(APP, emqx).
|
||||
|
@ -34,7 +31,7 @@ start(_Type, _Args) ->
|
|||
emqx_modules:load(),
|
||||
emqx_plugins:init(),
|
||||
emqx_plugins:load(),
|
||||
emqx_listeners:start(),
|
||||
emqx_listeners:start_all(),
|
||||
start_autocluster(),
|
||||
register(emqx, self()),
|
||||
print_vsn(),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_auth_mod).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_banned).
|
||||
|
||||
|
@ -70,9 +68,7 @@ start_link() ->
|
|||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
-spec(check(client()) -> boolean()).
|
||||
check(#client{client_id = ClientId,
|
||||
username = Username,
|
||||
peername = {IPAddr, _}}) ->
|
||||
check(#client{id = ClientId, username = Username, peername = {IPAddr, _}}) ->
|
||||
ets:member(?TAB, {client_id, ClientId})
|
||||
orelse ets:member(?TAB, {username, Username})
|
||||
orelse ets:member(?TAB, {ipaddr, IPAddr}).
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All Rights Reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_base62).
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_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,
|
||||
wx],
|
||||
[App || App = {Name, _, _} <- Apps, not lists:member(Name, LibApps)].
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,22 +11,18 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_bridge).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
%% API Function Exports
|
||||
-export([start_link/5]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-define(PING_DOWN_INTERVAL, 1000).
|
||||
|
||||
|
@ -49,35 +44,30 @@
|
|||
|
||||
-export_type([option/0]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Start a bridge
|
||||
-spec(start_link(any(), pos_integer(), atom(), binary(), [option()]) ->
|
||||
{ok, pid()} | ignore | {error, term()}).
|
||||
-spec(start_link(term(), pos_integer(), atom(), binary(), [option()])
|
||||
-> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link(Pool, Id, Node, Topic, Options) ->
|
||||
gen_server:start_link(?MODULE, [Pool, Id, Node, Topic, Options], []).
|
||||
gen_server:start_link(?MODULE, [Pool, Id, Node, Topic, Options], [{hibernate_after, 5000}]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id, Node, Topic, Options]) ->
|
||||
process_flag(trap_exit, true),
|
||||
gproc_pool:connect_worker(Pool, {Pool, Id}),
|
||||
true = gproc_pool:connect_worker(Pool, {Pool, Id}),
|
||||
case net_kernel:connect_node(Node) of
|
||||
true ->
|
||||
true = erlang:monitor_node(Node, true),
|
||||
Share = iolist_to_binary(["$bridge:", atom_to_list(Node), ":", Topic]),
|
||||
%% TODO:: local???
|
||||
emqx_broker:subscribe(Topic, self(), [local, {share, Share}, {qos, ?QOS_0}]),
|
||||
emqx_broker:subscribe(Topic, self(), [{share, Share}, {qos, ?QOS_0}]),
|
||||
State = parse_opts(Options, #state{node = Node, subtopic = Topic}),
|
||||
%%TODO: queue....
|
||||
MQueue = emqx_mqueue:new(qname(Node, Topic),
|
||||
[{max_len, State#state.max_queue_len}],
|
||||
emqx_alarm:alarm_fun()),
|
||||
{ok, State#state{pool = Pool, id = Id, mqueue = MQueue},
|
||||
hibernate, {backoff, 1000, 1000, 10000}};
|
||||
{ok, State#state{pool = Pool, id = Id, mqueue = MQueue}};
|
||||
false ->
|
||||
{stop, {cannot_connect_node, Node}}
|
||||
end.
|
||||
|
@ -103,33 +93,32 @@ qname(Node, Topic) ->
|
|||
iolist_to_binary(["Bridge:", Node, ":", Topic]).
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[Bridge] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Bridge] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[Bridge] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Bridge] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({dispatch, _Topic, Msg}, State = #state{mqueue = MQ, status = down}) ->
|
||||
{noreply, State#state{mqueue = emqx_mqueue:in(Msg, MQ)}};
|
||||
handle_info({dispatch, _Topic, Msg}, State = #state{mqueue = Q, status = down}) ->
|
||||
%% TODO: how to drop???
|
||||
{noreply, State#state{mqueue = emqx_mqueue:in(Msg, Q)}};
|
||||
|
||||
handle_info({dispatch, _Topic, Msg}, State = #state{node = Node, status = up}) ->
|
||||
emqx_rpc:cast(Node, emqx, publish, [transform(Msg, State)]),
|
||||
{noreply, State, hibernate};
|
||||
ok = emqx_rpc:cast(Node, emqx_broker, publish, [transform(Msg, State)]),
|
||||
{noreply, State};
|
||||
|
||||
handle_info({nodedown, Node}, State = #state{node = Node, ping_down_interval = Interval}) ->
|
||||
emqx_logger:warning("[Bridge] Node Down: ~s", [Node]),
|
||||
emqx_logger:warning("[Bridge] node down: ~s", [Node]),
|
||||
erlang:send_after(Interval, self(), ping_down_node),
|
||||
{noreply, State#state{status = down}, hibernate};
|
||||
|
||||
handle_info({nodeup, Node}, State = #state{node = Node}) ->
|
||||
%% TODO: Really fast??
|
||||
case emqx:is_running(Node) of
|
||||
true ->
|
||||
emqx_logger:warning("[Bridge] Node up: ~s", [Node]),
|
||||
true -> emqx_logger:warning("[Bridge] Node up: ~s", [Node]),
|
||||
{noreply, dequeue(State#state{status = up})};
|
||||
false ->
|
||||
self() ! {nodedown, Node},
|
||||
false -> self() ! {nodedown, Node},
|
||||
{noreply, State#state{status = down}}
|
||||
end;
|
||||
|
||||
|
@ -137,10 +126,8 @@ handle_info(ping_down_node, State = #state{node = Node, ping_down_interval = Int
|
|||
Self = self(),
|
||||
spawn_link(fun() ->
|
||||
case net_kernel:connect_node(Node) of
|
||||
true -> %%TODO: this is not right... fixme later
|
||||
Self ! {nodeup, Node};
|
||||
false ->
|
||||
erlang:send_after(Interval, Self, ping_down_node)
|
||||
true -> Self ! {nodeup, Node};
|
||||
false -> erlang:send_after(Interval, Self, ping_down_node)
|
||||
end
|
||||
end),
|
||||
{noreply, State};
|
||||
|
@ -149,7 +136,7 @@ handle_info({'EXIT', _Pid, normal}, State) ->
|
|||
{noreply, State};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[Bridge] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Bridge] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,16 +11,14 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_bridge_sup).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
-export([start_link/3]).
|
||||
|
||||
|
||||
%% @doc Start bridge pool supervisor
|
||||
-spec(start_link(atom(), binary(), [emqx_bridge:option()])
|
||||
-> {ok, pid()} | {error, term()}).
|
||||
-spec(start_link(node(), topic(), [emqx_bridge:option()]) -> {ok, pid()} | {error, term()}).
|
||||
start_link(Node, Topic, Options) ->
|
||||
MFA = {emqx_bridge, start_link, [Node, Topic, Options]},
|
||||
emqx_pool_sup:start_link({bridge, Node, Topic}, random, MFA).
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_bridge_sup_sup).
|
||||
|
||||
|
@ -23,6 +21,7 @@
|
|||
-export([start_link/0, bridges/0]).
|
||||
-export([start_bridge/2, start_bridge/3, stop_bridge/2]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-define(CHILD_ID(Node, Topic), {bridge_sup, Node, Topic}).
|
||||
|
@ -30,10 +29,6 @@
|
|||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc List all bridges
|
||||
-spec(bridges() -> [{node(), topic(), pid()}]).
|
||||
bridges() ->
|
||||
|
@ -50,8 +45,7 @@ start_bridge(Node, Topic) when is_atom(Node), is_binary(Topic) ->
|
|||
start_bridge(Node, _Topic, _Options) when Node =:= node() ->
|
||||
{error, bridge_to_self};
|
||||
start_bridge(Node, Topic, Options) when is_atom(Node), is_binary(Topic) ->
|
||||
{ok, BridgeEnv} = emqx_config:get_env(bridge),
|
||||
Options1 = emqx_misc:merge_opts(BridgeEnv, Options),
|
||||
Options1 = emqx_misc:merge_opts(emqx_config:get_env(bridge, []), Options),
|
||||
supervisor:start_child(?MODULE, bridge_spec(Node, Topic, Options1)).
|
||||
|
||||
%% @doc Stop a bridge
|
||||
|
@ -63,15 +57,18 @@ stop_bridge(Node, Topic) when is_atom(Node), is_binary(Topic) ->
|
|||
Error -> Error
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_one, 10, 3600}, []}}.
|
||||
|
||||
bridge_spec(Node, Topic, Options) ->
|
||||
{?CHILD_ID(Node, Topic),
|
||||
{emqx_bridge_sup, start_link, [Node, Topic, Options]},
|
||||
permanent, infinity, supervisor, [emqx_bridge_sup]}.
|
||||
#{id => ?CHILD_ID(Node, Topic),
|
||||
start => {emqx_bridge_sup, start_link, [Node, Topic, Options]},
|
||||
restart => permanent,
|
||||
shutdown => infinity,
|
||||
type => supervisor,
|
||||
modules => [emqx_bridge_sup]}.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_broker).
|
||||
|
||||
|
@ -21,18 +19,17 @@
|
|||
-include("emqx.hrl").
|
||||
|
||||
-export([start_link/2]).
|
||||
|
||||
-export([subscribe/1, subscribe/2, subscribe/3, subscribe/4]).
|
||||
-export([publish/1, publish/2]).
|
||||
-export([publish/1, publish/2, safe_publish/1]).
|
||||
-export([unsubscribe/1, unsubscribe/2]).
|
||||
-export([dispatch/2, dispatch/3]).
|
||||
-export([subscriptions/1, subscribers/1, subscribed/2]).
|
||||
-export([get_subopts/2, set_subopts/3]).
|
||||
-export([topics/0]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {pool, id, submon}).
|
||||
|
||||
|
@ -44,19 +41,14 @@
|
|||
-define(SUBSCRIBER, emqx_subscriber).
|
||||
-define(SUBSCRIPTION, emqx_subscription).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Start a broker
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-spec(start_link(atom(), pos_integer())
|
||||
-> {ok, pid()} | ignore | {error, term()}).
|
||||
-spec(start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link(Pool, Id) ->
|
||||
gen_server:start_link({local, emqx_misc:proc_name(?MODULE, Id)},
|
||||
?MODULE, [Pool, Id], [{hibernate_after, 2000}]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Subscriber/Unsubscribe
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Subscribe/Unsubscribe
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(subscribe(topic()) -> ok | {error, term()}).
|
||||
subscribe(Topic) when is_binary(Topic) ->
|
||||
|
@ -85,52 +77,60 @@ unsubscribe(Topic) when is_binary(Topic) ->
|
|||
unsubscribe(Topic, Subscriber) when is_binary(Topic) ->
|
||||
unsubscribe(Topic, Subscriber, ?TIMEOUT).
|
||||
|
||||
-spec(unsubscribe(topic(), subscriber(), timeout())
|
||||
-> ok | {error, term()}).
|
||||
-spec(unsubscribe(topic(), subscriber(), timeout()) -> ok | {error, term()}).
|
||||
unsubscribe(Topic, Subscriber, Timeout) ->
|
||||
{Topic1, _} = emqx_topic:parse(Topic),
|
||||
UnsubReq = {unsubscribe, Topic1, with_subpid(Subscriber)},
|
||||
async_call(pick(Subscriber), UnsubReq, Timeout).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Publish
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(publish(topic(), payload()) -> delivery() | stopped).
|
||||
publish(Topic, Payload) when is_binary(Topic), is_binary(Payload) ->
|
||||
publish(emqx_message:make(Topic, Payload)).
|
||||
|
||||
-spec(publish(message()) -> delivery() | stopped).
|
||||
-spec(publish(message()) -> {ok, delivery()} | {error, stopped}).
|
||||
publish(Msg = #message{from = From}) ->
|
||||
%% Hook to trace?
|
||||
trace(publish, From, Msg),
|
||||
_ = trace(publish, From, Msg),
|
||||
case emqx_hooks:run('message.publish', [], Msg) of
|
||||
{ok, Msg1 = #message{topic = Topic}} ->
|
||||
route(aggre(emqx_router:match_routes(Topic)), delivery(Msg1));
|
||||
{ok, route(aggre(emqx_router:match_routes(Topic)), delivery(Msg1))};
|
||||
{stop, Msg1} ->
|
||||
emqx_logger:warning("Stop publishing: ~s", [emqx_message:format(Msg1)]),
|
||||
stopped
|
||||
{error, stopped}
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% called internally
|
||||
safe_publish(Msg) ->
|
||||
try
|
||||
publish(Msg)
|
||||
catch
|
||||
_:Error:Stacktrace ->
|
||||
emqx_logger:error("[Broker] publish error: ~p~n~p~n~p", [Error, Msg, Stacktrace])
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Trace
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
trace(publish, From, _Msg) when is_atom(From) ->
|
||||
%% Dont' trace '$SYS' publish
|
||||
ignore;
|
||||
trace(public, #client{client_id = ClientId, username = Username},
|
||||
trace(public, #client{id = ClientId, username = Username},
|
||||
#message{topic = Topic, payload = Payload}) ->
|
||||
emqx_logger:info([{client, ClientId}, {topic, Topic}],
|
||||
"~s/~s PUBLISH to ~s: ~p", [ClientId, Username, Topic, Payload]);
|
||||
"~s/~s PUBLISH to ~s: ~p", [Username, ClientId, Topic, Payload]);
|
||||
trace(public, From, #message{topic = Topic, payload = Payload})
|
||||
when is_binary(From); is_list(From) ->
|
||||
emqx_logger:info([{client, From}, {topic, Topic}],
|
||||
"~s PUBLISH to ~s: ~p", [From, Topic, Payload]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Route
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
route([], Delivery = #delivery{message = Msg}) ->
|
||||
emqx_hooks:run('message.dropped', [undefined, Msg]),
|
||||
|
@ -193,7 +193,7 @@ dispatch({SubId, SubPid}, Topic, Msg) when is_binary(SubId), is_pid(SubPid) ->
|
|||
dispatch(SubId, Topic, Msg) when is_binary(SubId) ->
|
||||
emqx_sm:dispatch(SubId, Topic, Msg);
|
||||
dispatch({share, _Group, _Sub}, _Topic, _Msg) ->
|
||||
ignore.
|
||||
ignored.
|
||||
|
||||
dropped(<<"$SYS/", _/binary>>) ->
|
||||
ok;
|
||||
|
@ -201,7 +201,7 @@ dropped(_Topic) ->
|
|||
emqx_metrics:inc('messages/dropped').
|
||||
|
||||
delivery(Msg) ->
|
||||
#delivery{message = Msg, flows = []}.
|
||||
#delivery{node = node(), message = Msg, flows = []}.
|
||||
|
||||
subscribers(Topic) ->
|
||||
try ets:lookup_element(?SUBSCRIBER, Topic, 2) catch error:badarg -> [] end.
|
||||
|
@ -221,9 +221,7 @@ subscribed(Topic, SubPid) when is_binary(Topic), is_pid(SubPid) ->
|
|||
ets:member(?SUBOPTION, {Topic, SubPid});
|
||||
subscribed(Topic, SubId) when is_binary(Topic), is_binary(SubId) ->
|
||||
length(ets:match_object(?SUBOPTION, {{Topic, {SubId, '_'}}, '_'}, 1)) == 1;
|
||||
subscribed(Topic, {SubId, SubPid}) when is_binary(Topic),
|
||||
is_binary(SubId),
|
||||
is_pid(SubPid) ->
|
||||
subscribed(Topic, {SubId, SubPid}) when is_binary(Topic), is_binary(SubId), is_pid(SubPid) ->
|
||||
ets:member(?SUBOPTION, {Topic, {SubId, SubPid}}).
|
||||
|
||||
-spec(get_subopts(topic(), subscriber()) -> [suboption()]).
|
||||
|
@ -262,22 +260,22 @@ pick(SubPid) when is_pid(SubPid) ->
|
|||
pick(SubId) when is_binary(SubId) ->
|
||||
gproc_pool:pick_worker(broker, SubId);
|
||||
pick({SubId, SubPid}) when is_binary(SubId), is_pid(SubPid) ->
|
||||
pick(SubId).
|
||||
pick(SubPid).
|
||||
|
||||
-spec(topics() -> [topic()]).
|
||||
topics() -> emqx_router:topics().
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id]) ->
|
||||
gproc_pool:connect_worker(Pool, {Pool, Id}),
|
||||
true = gproc_pool:connect_worker(Pool, {Pool, Id}),
|
||||
{ok, #state{pool = Pool, id = Id, submon = emqx_pmon:new()}}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[Broker] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Broker] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({From, {subscribe, Topic, Subscriber, Options}}, State) ->
|
||||
case ets:lookup(?SUBOPTION, {Topic, Subscriber}) of
|
||||
|
@ -307,11 +305,10 @@ handle_cast({From, {unsubscribe, Topic, Subscriber}}, State) ->
|
|||
{noreply, State};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[Broker] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Broker] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({'DOWN', _MRef, process, SubPid, _Reason},
|
||||
State = #state{submon = SubMon}) ->
|
||||
handle_info({'DOWN', _MRef, process, SubPid, _Reason}, State = #state{submon = SubMon}) ->
|
||||
Subscriber = case SubMon:find(SubPid) of
|
||||
undefined -> SubPid;
|
||||
SubId -> {SubId, SubPid}
|
||||
|
@ -321,7 +318,8 @@ handle_info({'DOWN', _MRef, process, SubPid, _Reason},
|
|||
({_, Topic}) ->
|
||||
Topic
|
||||
end, ets:lookup(?SUBSCRIPTION, Subscriber)),
|
||||
lists:foreach(fun(Topic) ->
|
||||
lists:foreach(
|
||||
fun(Topic) ->
|
||||
case ets:lookup(?SUBOPTION, {Topic, Subscriber}) of
|
||||
[{_, Options}] ->
|
||||
Group = proplists:get_value(share, Options),
|
||||
|
@ -336,18 +334,18 @@ handle_info({'DOWN', _MRef, process, SubPid, _Reason},
|
|||
{noreply, demonitor_subscriber(SubPid, State)};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[Broker] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Broker] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
||||
gproc_pool:disconnect_worker(Pool, {Pool, Id}).
|
||||
true = gproc_pool:disconnect_worker(Pool, {Pool, Id}).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal Functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
do_subscribe(Group, Topic, Subscriber, Options) ->
|
||||
ets:insert(?SUBSCRIPTION, {Subscriber, shared(Group, Topic)}),
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_broker_helper).
|
||||
|
||||
|
@ -20,8 +18,8 @@
|
|||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-define(HELPER, ?MODULE).
|
||||
|
||||
|
@ -31,24 +29,24 @@
|
|||
start_link() ->
|
||||
gen_server:start_link({local, ?HELPER}, ?MODULE, [], []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
emqx_stats:update_interval(broker_stats, stats_fun()),
|
||||
{ok, #state{}, hibernate}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[BrokerHelper] Unexpected request: ~p", [Req]),
|
||||
emqx_logger:error("[BrokerHelper] unexpected call: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[BrokerHelper] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[BrokerHelper] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[BrokerHelper] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[BrokerHelper] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{}) ->
|
||||
|
@ -57,9 +55,9 @@ terminate(_Reason, #state{}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
stats_fun() ->
|
||||
fun() ->
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_broker_sup).
|
||||
|
||||
|
@ -27,15 +25,15 @@
|
|||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
%% Create the pubsub tables
|
||||
lists:foreach(fun create_tab/1, [subscription, subscriber, suboption]),
|
||||
ok = lists:foreach(fun create_tab/1, [subscription, subscriber, suboption]),
|
||||
|
||||
%% Shared Subscription
|
||||
%% Shared subscription
|
||||
SharedSub = {shared_sub, {emqx_shared_sub, start_link, []},
|
||||
permanent, 5000, worker, [emqx_shared_sub]},
|
||||
|
||||
|
@ -43,16 +41,16 @@ init([]) ->
|
|||
Helper = {broker_helper, {emqx_broker_helper, start_link, []},
|
||||
permanent, 5000, worker, [emqx_broker_helper]},
|
||||
|
||||
%% Broker Pool
|
||||
%% Broker pool
|
||||
BrokerPool = emqx_pool_sup:spec(emqx_broker_pool,
|
||||
[broker, hash, emqx_vm:schedulers() * 2,
|
||||
{emqx_broker, start_link, []}]),
|
||||
|
||||
{ok, {{one_for_all, 0, 1}, [SharedSub, Helper, BrokerPool]}}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Create tables
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
create_tab(suboption) ->
|
||||
%% Suboption: {Topic, Sub} -> [{qos, 1}]
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_cli).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_client).
|
||||
|
||||
|
@ -142,9 +140,9 @@
|
|||
|
||||
-define(PROPERTY(Name, Val), #state{properties = #{Name := Val}}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(start_link() -> gen_statem:start_ret()).
|
||||
start_link() -> start_link([]).
|
||||
|
@ -302,9 +300,9 @@ disconnect(Client, ReasonCode) ->
|
|||
disconnect(Client, ReasonCode, Properties) ->
|
||||
gen_statem:call(Client, {disconnect, ReasonCode, Properties}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% For test cases
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
puback(Client, PacketId) when is_integer(PacketId) ->
|
||||
puback(Client, PacketId, ?RC_SUCCESS).
|
||||
|
@ -357,9 +355,9 @@ pause(Client) ->
|
|||
resume(Client) ->
|
||||
gen_statem:call(Client, resume).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_statem callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([Options]) ->
|
||||
process_flag(trap_exit, true),
|
||||
|
@ -892,9 +890,9 @@ terminate(_Reason, _State, #state{socket = Socket}) ->
|
|||
code_change(_Vsn, State, Data, _Extra) ->
|
||||
{ok, State, Data}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
ensure_keepalive_timer(State = ?PROPERTY('Server-Keep-Alive', Secs)) ->
|
||||
ensure_keepalive_timer(timer:seconds(Secs), State);
|
||||
|
@ -1017,7 +1015,7 @@ msg_to_packet(#mqtt_message{qos = Qos,
|
|||
payload = Payload}.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Socket Connect/Send
|
||||
|
||||
sock_connect(Hosts, SockOpts, Timeout) ->
|
||||
|
@ -1057,7 +1055,7 @@ send(Packet, State = #state{socket = Sock, proto_ver = Ver})
|
|||
run_sock(State = #state{socket = Sock}) ->
|
||||
emqx_client_sock:setopts(Sock, [{active, once}]), State.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Receive Loop
|
||||
|
||||
receive_loop(<<>>, State) ->
|
||||
|
@ -1076,7 +1074,7 @@ receive_loop(Bytes, State = #state{parse_state = ParseState}) ->
|
|||
{stop, Error}
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Next packet id
|
||||
|
||||
next_packet_id(State = #state{last_packet_id = 16#ffff}) ->
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_client_sock).
|
||||
|
||||
|
@ -26,8 +24,7 @@
|
|||
|
||||
-type(sockname() :: {inet:ip_address(), inet:port_number()}).
|
||||
|
||||
-type(option() :: gen_tcp:connect_option()
|
||||
| {ssl_opts, [ssl:ssl_option()]}).
|
||||
-type(option() :: gen_tcp:connect_option() | {ssl_opts, [ssl:ssl_option()]}).
|
||||
|
||||
-export_type([socket/0, option/0]).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_cm).
|
||||
|
||||
|
@ -22,20 +20,18 @@
|
|||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([lookup_client/1, register_client/1, register_client/2,
|
||||
unregister_client/1]).
|
||||
-export([lookup_client/1]).
|
||||
-export([register_client/1, register_client/2, unregister_client/1]).
|
||||
|
||||
-export([get_client_attrs/1, lookup_client_pid/1]).
|
||||
|
||||
-export([get_client_stats/1, set_client_stats/2]).
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {client_pmon}).
|
||||
|
||||
-define(CM, ?MODULE).
|
||||
|
||||
%% ETS Tables.
|
||||
-define(CLIENT, emqx_client).
|
||||
-define(CLIENT_ATTRS, emqx_client_attrs).
|
||||
|
@ -56,22 +52,20 @@ lookup_client(ClientId) when is_binary(ClientId) ->
|
|||
register_client(ClientId) when is_binary(ClientId) ->
|
||||
register_client({ClientId, self()});
|
||||
|
||||
register_client({ClientId, ClientPid}) when is_binary(ClientId),
|
||||
is_pid(ClientPid) ->
|
||||
register_client({ClientId, ClientPid}) when is_binary(ClientId), is_pid(ClientPid) ->
|
||||
register_client({ClientId, ClientPid}, []).
|
||||
|
||||
-spec(register_client({client_id(), pid()}, list()) -> ok).
|
||||
register_client({ClientId, ClientPid}, Attrs) when is_binary(ClientId),
|
||||
is_pid(ClientPid) ->
|
||||
ets:insert(?CLIENT, {ClientId, ClientPid}),
|
||||
ets:insert(?CLIENT_ATTRS, {{ClientId, ClientPid}, Attrs}),
|
||||
register_client(CObj = {ClientId, ClientPid}, Attrs) when is_binary(ClientId), is_pid(ClientPid) ->
|
||||
_ = ets:insert(?CLIENT, CObj),
|
||||
_ = ets:insert(?CLIENT_ATTRS, {CObj, Attrs}),
|
||||
notify({registered, ClientId, ClientPid}).
|
||||
|
||||
%% @doc Get client attrs
|
||||
-spec(get_client_attrs({client_id(), pid()}) -> list()).
|
||||
get_client_attrs({ClientId, ClientPid}) when is_binary(ClientId),
|
||||
is_pid(ClientPid) ->
|
||||
try ets:lookup_element(?CLIENT_ATTRS, {ClientId, ClientPid}, 2)
|
||||
get_client_attrs(CObj = {ClientId, ClientPid}) when is_binary(ClientId), is_pid(ClientPid) ->
|
||||
try
|
||||
ets:lookup_element(?CLIENT_ATTRS, CObj, 2)
|
||||
catch
|
||||
error:badarg -> []
|
||||
end.
|
||||
|
@ -81,11 +75,10 @@ get_client_attrs({ClientId, ClientPid}) when is_binary(ClientId),
|
|||
unregister_client(ClientId) when is_binary(ClientId) ->
|
||||
unregister_client({ClientId, self()});
|
||||
|
||||
unregister_client({ClientId, ClientPid}) when is_binary(ClientId),
|
||||
is_pid(ClientPid) ->
|
||||
ets:delete(?CLIENT_STATS, {ClientId, ClientPid}),
|
||||
ets:delete(?CLIENT_ATTRS, {ClientId, ClientPid}),
|
||||
ets:delete_object(?CLIENT, {ClientId, ClientPid}),
|
||||
unregister_client(CObj = {ClientId, ClientPid}) when is_binary(ClientId), is_pid(ClientPid) ->
|
||||
_ = ets:delete(?CLIENT_STATS, CObj),
|
||||
_ = ets:delete(?CLIENT_ATTRS, CObj),
|
||||
_ = ets:delete_object(?CLIENT, CObj),
|
||||
notify({unregistered, ClientId, ClientPid}).
|
||||
|
||||
%% @doc Lookup client pid
|
||||
|
@ -98,9 +91,8 @@ lookup_client_pid(ClientId) when is_binary(ClientId) ->
|
|||
|
||||
%% @doc Get client stats
|
||||
-spec(get_client_stats({client_id(), pid()}) -> list(emqx_stats:stats())).
|
||||
get_client_stats({ClientId, ClientPid}) when is_binary(ClientId),
|
||||
is_pid(ClientPid) ->
|
||||
try ets:lookup_element(?CLIENT_STATS, {ClientId, ClientPid}, 2)
|
||||
get_client_stats(CObj = {ClientId, ClientPid}) when is_binary(ClientId), is_pid(ClientPid) ->
|
||||
try ets:lookup_element(?CLIENT_STATS, CObj, 2)
|
||||
catch
|
||||
error:badarg -> []
|
||||
end.
|
||||
|
@ -110,16 +102,15 @@ get_client_stats({ClientId, ClientPid}) when is_binary(ClientId),
|
|||
set_client_stats(ClientId, Stats) when is_binary(ClientId) ->
|
||||
set_client_stats({ClientId, self()}, Stats);
|
||||
|
||||
set_client_stats({ClientId, ClientPid}, Stats) when is_binary(ClientId),
|
||||
is_pid(ClientPid) ->
|
||||
ets:insert(?CLIENT_STATS, {{ClientId, ClientPid}, Stats}).
|
||||
set_client_stats(CObj = {ClientId, ClientPid}, Stats) when is_binary(ClientId), is_pid(ClientPid) ->
|
||||
ets:insert(?CLIENT_STATS, {CObj, Stats}).
|
||||
|
||||
notify(Msg) ->
|
||||
gen_server:cast(?CM, {notify, Msg}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
TabOpts = [public, set, {write_concurrency, true}],
|
||||
|
@ -130,8 +121,8 @@ init([]) ->
|
|||
{ok, #state{client_pmon = emqx_pmon:new()}}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[CM] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[CM] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({notify, {registered, ClientId, Pid}}, State = #state{client_pmon = PMon}) ->
|
||||
{noreply, State#state{client_pmon = emqx_pmon:monitor(Pid, ClientId, PMon)}};
|
||||
|
@ -140,7 +131,7 @@ handle_cast({notify, {unregistered, _ClientId, Pid}}, State = #state{client_pmon
|
|||
{noreply, State#state{client_pmon = emqx_pmon:demonitor(Pid, PMon)}};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[CM] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[CM] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({'DOWN', _MRef, process, DownPid, _Reason}, State = #state{client_pmon = PMon}) ->
|
||||
|
@ -152,7 +143,7 @@ handle_info({'DOWN', _MRef, process, DownPid, _Reason}, State = #state{client_pm
|
|||
end;
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[CM] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[CM] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State = #state{}) ->
|
||||
|
@ -161,9 +152,9 @@ terminate(_Reason, _State = #state{}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
update_client_stats() ->
|
||||
case ets:info(?CLIENT, size) of
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_cm_sup).
|
||||
|
||||
|
@ -26,7 +25,11 @@ start_link() ->
|
|||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
CM = {emqx_cm, {emqx_cm, start_link, []},
|
||||
permanent, 5000, worker, [emqx_cm]},
|
||||
{ok, {{one_for_all, 10, 3600}, [CM]}}.
|
||||
{ok, {{one_for_all, 10, 3600},
|
||||
[#{id => manager,
|
||||
start => {emqx_cm, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_cm]}]}}.
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% 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 Hot Configuration
|
||||
%%
|
||||
|
@ -35,7 +33,7 @@
|
|||
|
||||
-define(APP, emqx).
|
||||
|
||||
-spec(get_env(Key :: atom(), Default :: any()) -> undefined | any()).
|
||||
-spec(get_env(Key :: atom(), Default :: term()) -> term()).
|
||||
get_env(Key, Default) ->
|
||||
application:get_env(?APP, Key, Default).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_connection).
|
||||
|
||||
|
@ -41,8 +39,8 @@
|
|||
-export([session/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
code_change/3, terminate/2]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3,
|
||||
terminate/2]).
|
||||
|
||||
%% Unused fields: connname, peerhost, peerport
|
||||
-record(state, {transport, socket, peername, conn_state, await_recv,
|
||||
|
@ -88,7 +86,7 @@ clean_acl_cache(CPid, Topic) ->
|
|||
gen_server:call(CPid, {clean_acl_cache, Topic}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% gen_server Callbacks
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init([Transport, Sock, Env]) ->
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_ctl).
|
||||
|
||||
|
@ -22,9 +20,8 @@
|
|||
-export([register_command/2, register_command/3, unregister_command/1]).
|
||||
-export([run_command/2, lookup_command/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {seq = 0}).
|
||||
|
||||
|
@ -33,10 +30,6 @@
|
|||
-define(SERVER, ?MODULE).
|
||||
-define(TAB, emqx_command).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
|
@ -64,9 +57,8 @@ run_command(Cmd, Args) when is_atom(Cmd) ->
|
|||
try Mod:Fun(Args) of
|
||||
_ -> ok
|
||||
catch
|
||||
_:Reason ->
|
||||
emqx_logger:error("[CTL] CMD Error:~p, Stacktrace:~p",
|
||||
[Reason, erlang:get_stacktrace()]),
|
||||
_:Reason:Stacktrace ->
|
||||
emqx_logger:error("[CTL] CMD Error:~p, Stacktrace:~p", [Reason, Stacktrace]),
|
||||
{error, Reason}
|
||||
end;
|
||||
[] ->
|
||||
|
@ -85,17 +77,17 @@ usage() ->
|
|||
[begin io:format("~80..-s~n", [""]), Mod:Cmd(usage) end
|
||||
|| {_, {Mod, Cmd}, _} <- ets:tab2list(?TAB)].
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
_ = emqx_tables:new(?TAB, [ordered_set, protected]),
|
||||
{ok, #state{seq = 0}}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({register_command, Cmd, MF, Opts}, State = #state{seq = Seq}) ->
|
||||
case ets:match(?TAB, {{'$1', Cmd}, '_', '_'}) of
|
||||
|
@ -111,11 +103,11 @@ handle_cast({unregister_command, Cmd}, State) ->
|
|||
noreply(State);
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("Unexpected cast: ~p", [Msg]),
|
||||
noreply(State).
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("unexpected info: ~p", [Info]),
|
||||
noreply(State).
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
|
@ -124,9 +116,9 @@ terminate(_Reason, _State) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal Function
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
noreply(State) ->
|
||||
{noreply, State, hibernate}.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,8 +11,8 @@
|
|||
%% 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 TODO:
|
||||
%% 1. Flapping Detection
|
||||
%% 2. Conflict Detection?
|
||||
-module(emqx_flapping).
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_flow_control).
|
||||
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_frame).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
-export([initial_state/0, initial_state/1]).
|
||||
-export([parse/2]).
|
||||
-export([serialize/1, serialize/2]).
|
||||
|
||||
-type(options() :: #{max_packet_size => 1..?MAX_PACKET_SIZE,
|
||||
version => mqtt_version()}).
|
||||
|
||||
|
@ -30,16 +31,11 @@
|
|||
|
||||
-export_type([options/0, parse_state/0]).
|
||||
|
||||
-export([initial_state/0, initial_state/1]).
|
||||
-export([parse/2]).
|
||||
-export([serialize/1, serialize/2]).
|
||||
-define(DEFAULT_OPTIONS, #{max_packet_size => ?MAX_PACKET_SIZE, version => ?MQTT_PROTO_V4}).
|
||||
|
||||
-define(DEFAULT_OPTIONS, #{max_packet_size => ?MAX_PACKET_SIZE,
|
||||
version => ?MQTT_PROTO_V4}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Init parse state
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(initial_state() -> {none, options()}).
|
||||
initial_state() ->
|
||||
|
@ -52,12 +48,11 @@ initial_state(Options) when is_map(Options) ->
|
|||
merge_opts(Options) ->
|
||||
maps:merge(?DEFAULT_OPTIONS, Options).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Parse MQTT Frame
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(parse(binary(), parse_state())
|
||||
-> {ok, mqtt_packet(), binary()} | {more, cont_fun(binary())}).
|
||||
-spec(parse(binary(), parse_state()) -> {ok, mqtt_packet(), binary()} | {more, cont_fun(binary())}).
|
||||
parse(<<>>, {none, Options}) ->
|
||||
{more, fun(Bin) -> parse(Bin, {none, Options}) end};
|
||||
parse(<<Type:4, Dup:1, QoS:2, Retain:1, Rest/binary>>, {none, Options}) ->
|
||||
|
@ -357,9 +352,9 @@ parse_utf8_string(<<Len:16/big, Str:Len/binary, Rest/binary>>) ->
|
|||
parse_binary_data(<<Len:16/big, Data:Len/binary, Rest/binary>>) ->
|
||||
{Data, Rest}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Serialize MQTT Packet
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(serialize(mqtt_packet()) -> iodata()).
|
||||
serialize(Packet) ->
|
||||
|
@ -369,8 +364,7 @@ serialize(Packet) ->
|
|||
serialize(#mqtt_packet{header = Header,
|
||||
variable = Variable,
|
||||
payload = Payload}, Options) when is_map(Options) ->
|
||||
serialize(Header, serialize_variable(Variable, merge_opts(Options)),
|
||||
serialize_payload(Payload)).
|
||||
serialize(Header, serialize_variable(Variable, merge_opts(Options)), serialize_payload(Payload)).
|
||||
|
||||
serialize(#mqtt_packet_header{type = Type,
|
||||
dup = Dup,
|
||||
|
@ -622,10 +616,6 @@ serialize_variable_byte_integer(N) when N =< ?LOWBITS ->
|
|||
serialize_variable_byte_integer(N) ->
|
||||
<<1:1, (N rem ?HIGHBIT):7, (serialize_variable_byte_integer(N div ?HIGHBIT))/binary>>.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
bool(0) -> false;
|
||||
bool(1) -> true.
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,12 +11,16 @@
|
|||
%% 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.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% GC Utility functions.
|
||||
|
||||
-module(emqx_gc).
|
||||
|
||||
%% Memory: (10, 100, 1000)
|
||||
%%
|
||||
|
||||
%%-record
|
||||
|
||||
-export([conn_max_gc_count/0, reset_conn_gc_count/2, maybe_force_gc/2,
|
||||
maybe_force_gc/3]).
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_gen_mod).
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% 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.
|
||||
%%
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_hooks).
|
||||
|
||||
|
|
|
@ -1,90 +1,89 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_inflight).
|
||||
|
||||
-export([new/1, contain/2, lookup/2, insert/3, update/3, delete/2, values/1,
|
||||
to_list/1, size/1, max_size/1, is_full/1, is_empty/1, window/1]).
|
||||
|
||||
-type(inflight() :: {max_size, gb_trees:tree()}).
|
||||
-type(max_size() :: pos_integer()).
|
||||
-type(inflight() :: {?MODULE, max_size(), gb_trees:tree()}).
|
||||
|
||||
-export_type([inflight/0]).
|
||||
|
||||
-spec(new(non_neg_integer()) -> inflight()).
|
||||
new(MaxSize) when MaxSize >= 0 ->
|
||||
{MaxSize, gb_trees:empty()}.
|
||||
{?MODULE, MaxSize, gb_trees:empty()}.
|
||||
|
||||
-spec(contain(Key :: term(), inflight()) -> boolean()).
|
||||
contain(Key, {_MaxSize, Tree}) ->
|
||||
contain(Key, {?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:is_defined(Key, Tree).
|
||||
|
||||
-spec(lookup(Key :: term(), inflight()) -> {value, term()} | none).
|
||||
lookup(Key, {_MaxSize, Tree}) ->
|
||||
lookup(Key, {?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:lookup(Key, Tree).
|
||||
|
||||
-spec(insert(Key :: term(), Value :: term(), inflight()) -> inflight()).
|
||||
insert(Key, Value, {MaxSize, Tree}) ->
|
||||
{MaxSize, gb_trees:insert(Key, Value, Tree)}.
|
||||
insert(Key, Value, {?MODULE, MaxSize, Tree}) ->
|
||||
{?MODULE, MaxSize, gb_trees:insert(Key, Value, Tree)}.
|
||||
|
||||
-spec(delete(Key :: term(), inflight()) -> inflight()).
|
||||
delete(Key, {MaxSize, Tree}) ->
|
||||
{MaxSize, gb_trees:delete(Key, Tree)}.
|
||||
delete(Key, {?MODULE, MaxSize, Tree}) ->
|
||||
{?MODULE, MaxSize, gb_trees:delete(Key, Tree)}.
|
||||
|
||||
-spec(update(Key :: term(), Val :: term(), inflight()) -> inflight()).
|
||||
update(Key, Val, {MaxSize, Tree}) ->
|
||||
{MaxSize, gb_trees:update(Key, Val, Tree)}.
|
||||
update(Key, Val, {?MODULE, MaxSize, Tree}) ->
|
||||
{?MODULE, MaxSize, gb_trees:update(Key, Val, Tree)}.
|
||||
|
||||
-spec(is_full(inflight()) -> boolean()).
|
||||
is_full({0, _Tree}) ->
|
||||
is_full({?MODULE, 0, _Tree}) ->
|
||||
false;
|
||||
is_full({MaxSize, Tree}) ->
|
||||
is_full({?MODULE, MaxSize, Tree}) ->
|
||||
MaxSize =< gb_trees:size(Tree).
|
||||
|
||||
-spec(is_empty(inflight()) -> boolean()).
|
||||
is_empty({_MaxSize, Tree}) ->
|
||||
is_empty({?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:is_empty(Tree).
|
||||
|
||||
-spec(smallest(inflight()) -> {K :: term(), V :: term()}).
|
||||
smallest({_MaxSize, Tree}) ->
|
||||
smallest({?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:smallest(Tree).
|
||||
|
||||
-spec(largest(inflight()) -> {K :: term(), V :: term()}).
|
||||
largest({_MaxSize, Tree}) ->
|
||||
largest({?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:largest(Tree).
|
||||
|
||||
-spec(values(inflight()) -> list()).
|
||||
values({_MaxSize, Tree}) ->
|
||||
values({?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:values(Tree).
|
||||
|
||||
-spec(to_list(inflight()) -> list({K :: term(), V :: term()})).
|
||||
to_list({_MaxSize, Tree}) ->
|
||||
to_list({?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:to_list(Tree).
|
||||
|
||||
-spec(window(inflight()) -> list()).
|
||||
window(Inflight = {_MaxSize, Tree}) ->
|
||||
window(Inflight = {?MODULE, _MaxSize, Tree}) ->
|
||||
case gb_trees:is_empty(Tree) of
|
||||
true -> [];
|
||||
false -> [Key || {Key, _Val} <- [smallest(Inflight), largest(Inflight)]]
|
||||
end.
|
||||
|
||||
-spec(size(inflight()) -> non_neg_integer()).
|
||||
size({_MaxSize, Tree}) ->
|
||||
size({?MODULE, _MaxSize, Tree}) ->
|
||||
gb_trees:size(Tree).
|
||||
|
||||
-spec(max_size(inflight()) -> non_neg_integer()).
|
||||
max_size({MaxSize, _Tree}) ->
|
||||
max_size({?MODULE, MaxSize, _Tree}) ->
|
||||
MaxSize.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_json).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_keepalive).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_kernel_sup).
|
||||
|
||||
|
@ -36,8 +34,18 @@ init([]) ->
|
|||
child_spec(emqx_tracer, worker)]}}.
|
||||
|
||||
child_spec(M, worker) ->
|
||||
{M, {M, start_link, []}, permanent, 5000, worker, [M]};
|
||||
#{id => M,
|
||||
start => {M, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [M]};
|
||||
child_spec(M, supervisor) ->
|
||||
{M, {M, start_link, []},
|
||||
permanent, infinity, supervisor, [M]}.
|
||||
#{id => M,
|
||||
start => {M, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => infinity,
|
||||
type => supervisor,
|
||||
modules => [M]}.
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_lager_backend).
|
||||
|
||||
|
|
|
@ -1,97 +1,62 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% 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 start/stop MQTT listeners.
|
||||
-module(emqx_listeners).
|
||||
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
-export([start/0, restart/0, stop/0]).
|
||||
-export([start_all/0, restart_all/0, stop_all/0]).
|
||||
-export([start_listener/1, stop_listener/1, restart_listener/1]).
|
||||
-export([all/0]).
|
||||
|
||||
-type(listener() :: {atom(), esockd:listen_on(), [esockd:option()]}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Start/Stop Listeners
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Start Listeners.
|
||||
-spec(start() -> ok).
|
||||
start() ->
|
||||
%% @doc Start all listeners
|
||||
-spec(start_all() -> ok).
|
||||
start_all() ->
|
||||
lists:foreach(fun start_listener/1, emqx_config:get_env(listeners, [])).
|
||||
|
||||
%% Start mqtt listener
|
||||
-spec(start_listener(listener()) -> {ok, pid()} | {error, any()}).
|
||||
start_listener({tcp, ListenOn, Opts}) ->
|
||||
start_listener('mqtt:tcp', ListenOn, Opts);
|
||||
%% Start MQTT/TCP listener
|
||||
-spec(start_listener(listener()) -> {ok, pid()} | {error, term()}).
|
||||
start_listener({tcp, ListenOn, Options}) ->
|
||||
start_mqtt_listener('mqtt:tcp', ListenOn, Options);
|
||||
%% Start MQTT/TLS listener
|
||||
start_listener({Proto, ListenOn, Options}) when Proto == ssl; Proto == tls ->
|
||||
start_mqtt_listener('mqtt:tls', ListenOn, Options);
|
||||
%% Start MQTT/WS listener
|
||||
start_listener({Proto, ListenOn, Options}) when Proto == http; Proto == ws ->
|
||||
start_http_listener('mqtt:ws', ListenOn, Options);
|
||||
%% Start MQTT/WSS listener
|
||||
start_listener({Proto, ListenOn, Options}) when Proto == https; Proto == wss ->
|
||||
start_http_listener('mqtt:wss', ListenOn, Options).
|
||||
|
||||
%% Start mqtt(SSL) listener
|
||||
start_listener({ssl, ListenOn, Opts}) ->
|
||||
start_listener('mqtt:ssl', ListenOn, Opts);
|
||||
start_mqtt_listener(Name, ListenOn, Options) ->
|
||||
{ok, _} = esockd:open(Name, ListenOn, merge_sockopts(Options), {emqx_connection, start_link, []}).
|
||||
|
||||
%% Start http listener
|
||||
start_listener({Proto, ListenOn, Opts}) when Proto == http; Proto == ws ->
|
||||
{ok, _} = mochiweb:start_http('mqtt:ws', ListenOn, Opts, {emqx_ws, handle_request, []});
|
||||
start_http_listener(Name, ListenOn, Options) ->
|
||||
{ok, _} = mochiweb:start_http(Name, ListenOn, Options, {emqx_ws, handle_request, []}).
|
||||
|
||||
%% Start https listener
|
||||
start_listener({Proto, ListenOn, Opts}) when Proto == https; Proto == wss ->
|
||||
{ok, _} = mochiweb:start_http('mqtt:wss', ListenOn, Opts, {emqx_ws, handle_request, []}).
|
||||
|
||||
start_listener(Proto, ListenOn, Opts) ->
|
||||
Env = lists:append(emqx_config:get_env(client, []),
|
||||
emqx_config:get_env(protocol, [])),
|
||||
MFArgs = {emqx_connection, start_link, [Env]},
|
||||
{ok, _} = esockd:open(Proto, ListenOn, merge_sockopts(Opts), MFArgs).
|
||||
|
||||
all() ->
|
||||
[Listener || Listener = {{Proto, _}, _Pid} <- esockd:listeners(), is_mqtt(Proto)].
|
||||
|
||||
is_mqtt('mqtt:tcp') -> true;
|
||||
is_mqtt('mqtt:ssl') -> true;
|
||||
is_mqtt('mqtt:ws') -> true;
|
||||
is_mqtt('mqtt:wss') -> true;
|
||||
is_mqtt(_Proto) -> false.
|
||||
|
||||
%% @doc Stop Listeners
|
||||
-spec(stop() -> ok).
|
||||
stop() ->
|
||||
lists:foreach(fun stop_listener/1, emqx_config:get_env(listeners, [])).
|
||||
|
||||
-spec(stop_listener(listener()) -> ok | {error, any()}).
|
||||
stop_listener({tcp, ListenOn, _Opts}) ->
|
||||
esockd:close('mqtt:tcp', ListenOn);
|
||||
stop_listener({ssl, ListenOn, _Opts}) ->
|
||||
esockd:close('mqtt:ssl', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws ->
|
||||
mochiweb:stop_http('mqtt:ws', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss ->
|
||||
mochiweb:stop_http('mqtt:wss', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) ->
|
||||
esockd:close(Proto, ListenOn).
|
||||
|
||||
%% @doc Restart Listeners
|
||||
-spec(restart() -> ok).
|
||||
restart() ->
|
||||
%% @doc Restart all listeners
|
||||
-spec(restart_all() -> ok).
|
||||
restart_all() ->
|
||||
lists:foreach(fun restart_listener/1, emqx_config:get_env(listeners, [])).
|
||||
|
||||
-spec(restart_listener(listener()) -> any()).
|
||||
restart_listener({tcp, ListenOn, _Opts}) ->
|
||||
esockd:reopen('mqtt:tcp', ListenOn);
|
||||
restart_listener({ssl, ListenOn, _Opts}) ->
|
||||
esockd:reopen('mqtt:ssl', ListenOn);
|
||||
restart_listener({Proto, ListenOn, _Opts}) when Proto == ssl; Proto == tls ->
|
||||
esockd:reopen('mqtt:tls', ListenOn);
|
||||
restart_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws ->
|
||||
mochiweb:restart_http('mqtt:ws', ListenOn);
|
||||
restart_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss ->
|
||||
|
@ -99,10 +64,36 @@ restart_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss ->
|
|||
restart_listener({Proto, ListenOn, _Opts}) ->
|
||||
esockd:reopen(Proto, ListenOn).
|
||||
|
||||
%% @doc Stop all listeners
|
||||
-spec(stop_all() -> ok).
|
||||
stop_all() ->
|
||||
lists:foreach(fun stop_listener/1, emqx_config:get_env(listeners, [])).
|
||||
|
||||
-spec(stop_listener(listener()) -> ok | {error, any()}).
|
||||
stop_listener({tcp, ListenOn, _Opts}) ->
|
||||
esockd:close('mqtt:tcp', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) when Proto == ssl; Proto == tls ->
|
||||
esockd:close('mqtt:tls', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) when Proto == http; Proto == ws ->
|
||||
mochiweb:stop_http('mqtt:ws', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) when Proto == https; Proto == wss ->
|
||||
mochiweb:stop_http('mqtt:wss', ListenOn);
|
||||
stop_listener({Proto, ListenOn, _Opts}) ->
|
||||
esockd:close(Proto, ListenOn).
|
||||
|
||||
merge_sockopts(Options) ->
|
||||
%%TODO: tcp_options?
|
||||
SockOpts = emqx_misc:merge_opts(
|
||||
?MQTT_SOCKOPTS, proplists:get_value(sockopts, Options, [])),
|
||||
emqx_misc:merge_opts(Options, [{sockopts, SockOpts}]).
|
||||
case lists:keytake(tcp_options, 1, Options) of
|
||||
{value, {tcp_options, TcpOpts}, Options1} ->
|
||||
[{tcp_options, emqx_misc:merge_opts(?MQTT_SOCKOPTS, TcpOpts)} | Options1];
|
||||
false ->
|
||||
[{tcp_options, ?MQTT_SOCKOPTS} | Options]
|
||||
end.
|
||||
|
||||
%% all() ->
|
||||
%% [Listener || Listener = {{Proto, _}, _Pid} <- esockd:listeners(), is_mqtt(Proto)].
|
||||
%%is_mqtt('mqtt:tcp') -> true;
|
||||
%%is_mqtt('mqtt:tls') -> true;
|
||||
%%is_mqtt('mqtt:ws') -> true;
|
||||
%%is_mqtt('mqtt:wss') -> true;
|
||||
%%is_mqtt(_Proto) -> false.
|
||||
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_logger).
|
||||
|
||||
-compile({no_auto_import,[error/1]}).
|
||||
|
||||
-export([debug/1, debug/2, debug/3,
|
||||
info/1, info/2, info/3,
|
||||
warning/1, warning/2, warning/3,
|
||||
error/1, error/2, error/3,
|
||||
critical/1, critical/2, critical/3]).
|
||||
-export([debug/1, debug/2, debug/3]).
|
||||
-export([info/1, info/2, info/3]).
|
||||
-export([warning/1, warning/2, warning/3]).
|
||||
-export([error/1, error/2, error/3]).
|
||||
-export([critical/1, critical/2, critical/3]).
|
||||
|
||||
debug(Msg) ->
|
||||
lager:debug(Msg).
|
||||
|
|
|
@ -1,45 +1,46 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_message).
|
||||
|
||||
-include("emqx.hrl").
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
-export([make/2, make/3, make/4]).
|
||||
-export([get_flag/2, get_flag/3, set_flag/2, unset_flag/2]).
|
||||
-export([new/2, new/3, new/4, new/5]).
|
||||
-export([get_flag/2, get_flag/3, set_flag/2, set_flag/3, unset_flag/2]).
|
||||
-export([get_header/2, get_header/3, set_header/3]).
|
||||
-export([get_user_property/2, get_user_property/3, set_user_property/3]).
|
||||
|
||||
-spec(make(topic(), payload()) -> message()).
|
||||
make(Topic, Payload) ->
|
||||
make(undefined, Topic, Payload).
|
||||
-spec(new(topic(), payload()) -> message()).
|
||||
new(Topic, Payload) ->
|
||||
new(undefined, Topic, Payload).
|
||||
|
||||
%% Create a message
|
||||
-spec(make(atom() | client(), topic(), payload()) -> message()).
|
||||
make(From, Topic, Payload) when is_atom(From); is_record(From, client) ->
|
||||
make(From, ?QOS_0, Topic, Payload).
|
||||
-spec(new(atom() | client(), topic(), payload()) -> message()).
|
||||
new(From, Topic, Payload) when is_atom(From); is_record(From, client) ->
|
||||
new(From, #{qos => ?QOS0}, Topic, Payload).
|
||||
|
||||
make(From, QoS, Topic, Payload) when is_atom(From); is_record(From, client) ->
|
||||
-spec(new(atom() | client(), message_flags(), topic(), payload()) -> message()).
|
||||
new(From, Flags, Topic, Payload) when is_atom(From); is_record(From, client) ->
|
||||
new(From, Flags, #{}, Topic, Payload).
|
||||
|
||||
-spec(new(atom() | client(), message_flags(), message_headers(), topic(), payload()) -> message()).
|
||||
new(From, Flags, Headers, Topic, Payload) when is_atom(From); is_record(From, client) ->
|
||||
#message{id = msgid(),
|
||||
qos = ?QOS_I(QoS),
|
||||
from = From,
|
||||
sender = self(),
|
||||
flags = #{},
|
||||
headers = #{},
|
||||
flags = Flags,
|
||||
headers = Headers,
|
||||
topic = Topic,
|
||||
properties = #{},
|
||||
payload = Payload,
|
||||
|
@ -58,6 +59,10 @@ get_flag(Flag, #message{flags = Flags}, Default) ->
|
|||
set_flag(Flag, Msg = #message{flags = Flags}) when is_atom(Flag) ->
|
||||
Msg#message{flags = maps:put(Flag, true, Flags)}.
|
||||
|
||||
-spec(set_flag(message_flag(), boolean() | integer(), message()) -> message()).
|
||||
set_flag(Flag, Val, Msg = #message{flags = Flags}) when is_atom(Flag) ->
|
||||
Msg#message{flags = maps:put(Flag, Val, Flags)}.
|
||||
|
||||
%% @doc Unset flag
|
||||
-spec(unset_flag(message_flag(), message()) -> message()).
|
||||
unset_flag(Flag, Msg = #message{flags = Flags}) ->
|
||||
|
|
|
@ -1,35 +1,30 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_metrics).
|
||||
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([new/1, all/0]).
|
||||
|
||||
-export([val/1, inc/1, inc/2, inc/3, dec/2, dec/3, set/2]).
|
||||
|
||||
%% Received/sent metrics
|
||||
-export([received/1, sent/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {}).
|
||||
|
||||
|
@ -86,7 +81,6 @@
|
|||
]).
|
||||
|
||||
-define(TAB, ?MODULE).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
%% @doc Start the metrics server
|
||||
|
@ -94,9 +88,9 @@
|
|||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Metrics API
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
new({gauge, Name}) ->
|
||||
ets:insert(?TAB, {{Name, 0}, 0});
|
||||
|
@ -168,9 +162,9 @@ key(counter, Metric) ->
|
|||
update_counter(Key, UpOp) ->
|
||||
ets:update_counter(?TAB, Key, UpOp).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Receive/Sent metrics
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Received/Sent metrics
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
%% @doc Count packets received.
|
||||
-spec(received(mqtt_packet()) -> ok).
|
||||
|
@ -248,9 +242,9 @@ qos_sent(?QOS_1) ->
|
|||
qos_sent(?QOS_2) ->
|
||||
inc('messages/qos2/sent').
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
% Create metrics table
|
||||
|
@ -259,15 +253,15 @@ init([]) ->
|
|||
{ok, #state{}, hibernate}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[METRICS] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Metrics] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[METRICS] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Metrics] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[METRICS] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Metrics] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{}) ->
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_misc).
|
||||
|
||||
-export([merge_opts/2, start_timer/2, start_timer/3, cancel_timer/1,
|
||||
proc_name/2, proc_stats/0, proc_stats/1]).
|
||||
|
||||
%% @doc Merge Options
|
||||
%% @doc Merge options
|
||||
-spec(merge_opts(list(), list()) -> list()).
|
||||
merge_opts(Defaults, Options) ->
|
||||
lists:foldl(
|
||||
|
@ -42,7 +40,8 @@ cancel_timer(undefined) ->
|
|||
ok;
|
||||
cancel_timer(Timer) ->
|
||||
case catch erlang:cancel_timer(Timer) of
|
||||
false -> receive {timeout, Timer, _} -> ok after 0 -> ok end;
|
||||
false ->
|
||||
receive {timeout, Timer, _} -> ok after 0 -> ok end;
|
||||
_ -> ok
|
||||
end.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_mod_presence).
|
||||
|
||||
|
@ -21,14 +19,13 @@
|
|||
-include("emqx.hrl").
|
||||
|
||||
-export([load/1, unload/1]).
|
||||
|
||||
-export([on_client_connected/3, on_client_disconnected/3]).
|
||||
|
||||
load(Env) ->
|
||||
emqx:hook('client.connected', fun ?MODULE:on_client_connected/3, [Env]),
|
||||
emqx:hook('client.disconnected', fun ?MODULE:on_client_disconnected/3, [Env]).
|
||||
|
||||
on_client_connected(ConnAck, Client = #client{client_id = ClientId,
|
||||
on_client_connected(ConnAck, Client = #client{id = ClientId,
|
||||
username = Username,
|
||||
peername = {IpAddr, _}
|
||||
%%clean_sess = CleanSess,
|
||||
|
@ -36,7 +33,7 @@ on_client_connected(ConnAck, Client = #client{client_id = ClientId,
|
|||
}, Env) ->
|
||||
case emqx_json:safe_encode([{clientid, ClientId},
|
||||
{username, Username},
|
||||
{ipaddress, iolist_to_binary(emqx_net:ntoa(IpAddr))},
|
||||
{ipaddress, iolist_to_binary(esockd_net:ntoa(IpAddr))},
|
||||
%%{clean_sess, CleanSess}, %%TODO:: fixme later
|
||||
%%{protocol, ProtoVer},
|
||||
{connack, ConnAck},
|
||||
|
@ -49,8 +46,7 @@ on_client_connected(ConnAck, Client = #client{client_id = ClientId,
|
|||
end,
|
||||
{ok, Client}.
|
||||
|
||||
on_client_disconnected(Reason, #client{client_id = ClientId,
|
||||
username = Username}, Env) ->
|
||||
on_client_disconnected(Reason, #client{id = ClientId, username = Username}, Env) ->
|
||||
case emqx_json:safe_encode([{clientid, ClientId},
|
||||
{username, Username},
|
||||
{reason, reason(Reason)},
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_mod_rewrite).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_mod_subscription).
|
||||
|
||||
|
@ -33,9 +31,7 @@
|
|||
load(Topics) ->
|
||||
emqx:hook('client.connected', fun ?MODULE:on_client_connected/3, [Topics]).
|
||||
|
||||
on_client_connected(RC, Client = #client{client_id = ClientId,
|
||||
client_pid = ClientPid,
|
||||
username = Username}, Topics)
|
||||
on_client_connected(RC, Client = #client{id = ClientId, pid = ClientPid, username = Username}, Topics)
|
||||
when RC < 16#80 ->
|
||||
Replace = fun(Topic) -> rep(<<"%u">>, Username, rep(<<"%c">>, ClientId, Topic)) end,
|
||||
TopicTable = [{Replace(Topic), Qos} || {Topic, Qos} <- Topics],
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,27 +11,17 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_mod_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
%% API
|
||||
-export([start_link/0, start_child/1, start_child/2, stop_child/1]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
%% Helper macro for declaring children of supervisor
|
||||
-define(CHILD(Mod, Type), {Mod, {Mod, start_link, []}, permanent, 5000, Type, [Mod]}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
|
@ -49,10 +38,9 @@ stop_child(ChildId) ->
|
|||
Error -> Error
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Supervisor callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_one, 10, 100}, []}}.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_modules).
|
||||
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% 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 MQTT5 Properties
|
||||
-module(emqx_mqtt_properties).
|
||||
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,8 +11,8 @@
|
|||
%% 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 be a bound queue.
|
||||
%% @doc A Simple in-memory message queue.
|
||||
%%
|
||||
%% Notice that MQTT is not an enterprise messaging queue. MQTT assume that client
|
||||
|
@ -155,7 +154,7 @@ stats(#mqueue{type = Type, q = Q, max_len = MaxLen, len = Len, dropped = Dropped
|
|||
|
||||
%% @doc Enqueue a message.
|
||||
-spec(in(message(), mqueue()) -> mqueue()).
|
||||
in(#message{qos = ?QOS_0}, MQ = #mqueue{qos0 = false}) ->
|
||||
in(#message{flags = #{qos := ?QOS_0}}, MQ = #mqueue{qos0 = false}) ->
|
||||
MQ;
|
||||
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len, max_len = 0}) ->
|
||||
MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1};
|
||||
|
|
232
src/emqx_net.erl
232
src/emqx_net.erl
|
@ -1,232 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_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([peername/1, sockname/1, format/2, format/1, ntoa/1,
|
||||
connection_string/2]).
|
||||
|
||||
-define(FIRST_TEST_BIND_PORT, 10000).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% inet_parse:address takes care of ip string, like "0.0.0.0"
|
||||
%% inet:getaddr returns immediately for ip tuple {0,0,0,0},
|
||||
%% and runs 'inet_gethost' port process for dns lookups.
|
||||
%% On Windows inet:getaddr runs dns resolver for ip string, which may fail.
|
||||
getaddr(Host, Family) ->
|
||||
case inet_parse:address(Host) of
|
||||
{ok, IPAddress} -> [{IPAddress, resolve_family(IPAddress, Family)}];
|
||||
{error, _} -> gethostaddr(Host, Family)
|
||||
end.
|
||||
|
||||
gethostaddr(Host, auto) ->
|
||||
Lookups = [{Family, inet:getaddr(Host, Family)} || Family <- [inet, inet6]],
|
||||
case [{IP, Family} || {Family, {ok, IP}} <- Lookups] of
|
||||
[] -> host_lookup_error(Host, Lookups);
|
||||
IPs -> IPs
|
||||
end;
|
||||
|
||||
gethostaddr(Host, Family) ->
|
||||
case inet:getaddr(Host, Family) of
|
||||
{ok, IPAddress} -> [{IPAddress, Family}];
|
||||
{error, Reason} -> host_lookup_error(Host, Reason)
|
||||
end.
|
||||
|
||||
host_lookup_error(Host, Reason) ->
|
||||
error_logger:error_msg("invalid host ~p - ~p~n", [Host, Reason]),
|
||||
throw({error, {invalid_host, Host, Reason}}).
|
||||
|
||||
resolve_family({_,_,_,_}, auto) -> inet;
|
||||
resolve_family({_,_,_,_,_,_,_,_}, auto) -> inet6;
|
||||
resolve_family(IP, auto) -> throw({error, {strange_family, IP}});
|
||||
resolve_family(_, F) -> F.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% There are three kinds of machine (for our purposes).
|
||||
%%
|
||||
%% * Those which treat IPv4 addresses as a special kind of IPv6 address
|
||||
%% ("Single stack")
|
||||
%% - Linux by default, Windows Vista and later
|
||||
%% - We also treat any (hypothetical?) IPv6-only machine the same way
|
||||
%% * Those which consider IPv6 and IPv4 to be completely separate things
|
||||
%% ("Dual stack")
|
||||
%% - OpenBSD, Windows XP / 2003, Linux if so configured
|
||||
%% * Those which do not support IPv6.
|
||||
%% - Ancient/weird OSes, Linux if so configured
|
||||
%%
|
||||
%% How to reconfigure Linux to test this:
|
||||
%% Single stack (default):
|
||||
%% echo 0 > /proc/sys/net/ipv6/bindv6only
|
||||
%% Dual stack:
|
||||
%% echo 1 > /proc/sys/net/ipv6/bindv6only
|
||||
%% IPv4 only:
|
||||
%% add ipv6.disable=1 to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub then
|
||||
%% sudo update-grub && sudo reboot
|
||||
%%
|
||||
%% This matters in (and only in) the case where the sysadmin (or the
|
||||
%% app descriptor) has only supplied a port and we wish to bind to
|
||||
%% "all addresses". This means different things depending on whether
|
||||
%% we're single or dual stack. On single stack binding to "::"
|
||||
%% implicitly includes all IPv4 addresses, and subsequently attempting
|
||||
%% to bind to "0.0.0.0" will fail. On dual stack, binding to "::" will
|
||||
%% only bind to IPv6 addresses, and we need another listener bound to
|
||||
%% "0.0.0.0" for IPv4. Finally, on IPv4-only systems we of course only
|
||||
%% want to bind to "0.0.0.0".
|
||||
%%
|
||||
%% Unfortunately it seems there is no way to detect single vs dual stack
|
||||
%% apart from attempting to bind to the port.
|
||||
port_to_listeners(Port) ->
|
||||
IPv4 = {"0.0.0.0", Port, inet},
|
||||
IPv6 = {"::", Port, inet6},
|
||||
case ipv6_status(?FIRST_TEST_BIND_PORT) of
|
||||
single_stack -> [IPv6];
|
||||
ipv6_only -> [IPv6];
|
||||
dual_stack -> [IPv6, IPv4];
|
||||
ipv4_only -> [IPv4]
|
||||
end.
|
||||
|
||||
ipv6_status(TestPort) ->
|
||||
IPv4 = [inet, {ip, {0,0,0,0}}],
|
||||
IPv6 = [inet6, {ip, {0,0,0,0,0,0,0,0}}],
|
||||
case gen_tcp:listen(TestPort, IPv6) of
|
||||
{ok, LSock6} ->
|
||||
case gen_tcp:listen(TestPort, IPv4) of
|
||||
{ok, LSock4} ->
|
||||
%% Dual stack
|
||||
gen_tcp:close(LSock6),
|
||||
gen_tcp:close(LSock4),
|
||||
dual_stack;
|
||||
%% Checking the error here would only let us
|
||||
%% distinguish single stack IPv6 / IPv4 vs IPv6 only,
|
||||
%% which we figure out below anyway.
|
||||
{error, _} ->
|
||||
gen_tcp:close(LSock6),
|
||||
case gen_tcp:listen(TestPort, IPv4) of
|
||||
%% Single stack
|
||||
{ok, LSock4} -> gen_tcp:close(LSock4),
|
||||
single_stack;
|
||||
%% IPv6-only machine. Welcome to the future.
|
||||
{error, eafnosupport} -> ipv6_only; %% Linux
|
||||
{error, eprotonosupport}-> ipv6_only; %% FreeBSD
|
||||
%% Dual stack machine with something already
|
||||
%% on IPv4.
|
||||
{error, _} -> ipv6_status(TestPort + 1)
|
||||
end
|
||||
end;
|
||||
%% IPv4-only machine. Welcome to the 90s.
|
||||
{error, eafnosupport} -> %% Linux
|
||||
ipv4_only;
|
||||
{error, eprotonosupport} -> %% FreeBSD
|
||||
ipv4_only;
|
||||
%% Port in use
|
||||
{error, _} ->
|
||||
ipv6_status(TestPort + 1)
|
||||
end.
|
||||
|
||||
tcp_name(Prefix, IPAddress, Port)
|
||||
when is_atom(Prefix) andalso is_number(Port) ->
|
||||
list_to_atom(
|
||||
lists:flatten(
|
||||
io_lib:format(
|
||||
"~w_~s:~w", [Prefix, inet_parse:ntoa(IPAddress), Port]))).
|
||||
|
||||
connection_string(Sock, Direction) ->
|
||||
case socket_ends(Sock, Direction) of
|
||||
{ok, {FromAddress, FromPort, ToAddress, ToPort}} ->
|
||||
{ok, lists:flatten(
|
||||
io_lib:format(
|
||||
"~s:~p -> ~s:~p",
|
||||
[maybe_ntoab(FromAddress), FromPort,
|
||||
maybe_ntoab(ToAddress), ToPort]))};
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
socket_ends(Sock, Direction) ->
|
||||
{From, To} = sock_funs(Direction),
|
||||
case {From(Sock), To(Sock)} of
|
||||
{{ok, {FromAddress, FromPort}}, {ok, {ToAddress, ToPort}}} ->
|
||||
{ok, {rdns(FromAddress), FromPort,
|
||||
rdns(ToAddress), ToPort}};
|
||||
{{error, _Reason} = Error, _} ->
|
||||
Error;
|
||||
{_, {error, _Reason} = Error} ->
|
||||
Error
|
||||
end.
|
||||
|
||||
maybe_ntoab(Addr) when is_tuple(Addr) -> ntoab(Addr);
|
||||
maybe_ntoab(Host) -> Host.
|
||||
|
||||
rdns(Addr) -> Addr.
|
||||
|
||||
sock_funs(inbound) -> {fun peername/1, fun sockname/1};
|
||||
sock_funs(outbound) -> {fun sockname/1, fun peername/1}.
|
||||
|
||||
getopts(Sock, Options) when is_port(Sock) ->
|
||||
inet:getopts(Sock, Options).
|
||||
|
||||
setopts(Sock, Options) when is_port(Sock) ->
|
||||
inet:setopts(Sock, Options).
|
||||
|
||||
sockname(Sock) when is_port(Sock) -> inet:sockname(Sock).
|
||||
|
||||
peername(Sock) when is_port(Sock) -> inet:peername(Sock).
|
||||
|
||||
format(sockname, SockName) ->
|
||||
format(SockName);
|
||||
format(peername, PeerName) ->
|
||||
format(PeerName).
|
||||
format({Addr, Port}) ->
|
||||
lists:flatten(io_lib:format("~s:~p", [maybe_ntoab(Addr), Port])).
|
||||
|
||||
ntoa({0,0,0,0,0,16#ffff,AB,CD}) ->
|
||||
inet_parse:ntoa({AB bsr 8, AB rem 256, CD bsr 8, CD rem 256});
|
||||
ntoa(IP) ->
|
||||
inet_parse:ntoa(IP).
|
||||
|
||||
ntoab(IP) ->
|
||||
Str = ntoa(IP),
|
||||
case string:str(Str, ":") of
|
||||
0 -> Str;
|
||||
_ -> "[" ++ Str ++ "]"
|
||||
end.
|
||||
|
||||
tcp_host({0,0,0,0}) ->
|
||||
hostname();
|
||||
|
||||
tcp_host({0,0,0,0,0,0,0,0}) ->
|
||||
hostname();
|
||||
|
||||
tcp_host(IPAddress) ->
|
||||
case inet:gethostbyaddr(IPAddress) of
|
||||
{ok, #hostent{h_name = Name}} -> Name;
|
||||
{error, _Reason} -> ntoa(IPAddress)
|
||||
end.
|
||||
|
||||
hostname() ->
|
||||
{ok, Hostname} = inet:gethostname(),
|
||||
case inet:gethostbyname(Hostname) of
|
||||
{ok, #hostent{h_name = Name}} -> Name;
|
||||
{error, _Reason} -> Hostname
|
||||
end.
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
|
@ -12,7 +11,6 @@
|
|||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_packet).
|
||||
|
||||
|
@ -21,9 +19,7 @@
|
|||
-include("emqx_mqtt.hrl").
|
||||
|
||||
-export([protocol_name/1, type_name/1]).
|
||||
|
||||
-export([format/1]).
|
||||
|
||||
-export([to_message/1, from_message/1]).
|
||||
|
||||
%% @doc Protocol name of version
|
||||
|
@ -39,9 +35,8 @@ type_name(Type) when Type > ?RESERVED andalso Type =< ?AUTH ->
|
|||
|
||||
%% @doc From Message to Packet
|
||||
-spec(from_message(message()) -> mqtt_packet()).
|
||||
from_message(Msg = #message{qos = Qos,
|
||||
topic = Topic,
|
||||
payload = Payload}) ->
|
||||
from_message(Msg = #message{topic = Topic, payload = Payload}) ->
|
||||
Qos = emqx_message:get_flag(qos, Msg, 0),
|
||||
Dup = emqx_message:get_flag(dup, Msg, false),
|
||||
Retain = emqx_message:get_flag(retain, Msg, false),
|
||||
PacketId = emqx_message:get_header(packet_id, Msg),
|
||||
|
@ -61,13 +56,12 @@ to_message(#mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
|
|||
dup = Dup},
|
||||
variable = #mqtt_packet_publish{topic_name = Topic,
|
||||
packet_id = PacketId,
|
||||
properties = Props},
|
||||
properties = Properties},
|
||||
payload = Payload}) ->
|
||||
Msg = emqx_message:make(undefined, Topic, Payload),
|
||||
Msg#message{qos = Qos,
|
||||
flags = #{dup => Dup, retain => Retain},
|
||||
headers = #{packet_id => PacketId},
|
||||
properties = Props};
|
||||
Flags = #{dup => Dup, retain => Retain, qos => Qos},
|
||||
Msg = emqx_message:new(undefined, Flags, #{packet_id => PacketId}, Topic, Payload),
|
||||
Msg#message{properties = Properties};
|
||||
|
||||
to_message(#mqtt_packet_connect{will_flag = false}) ->
|
||||
undefined;
|
||||
to_message(#mqtt_packet_connect{will_retain = Retain,
|
||||
|
@ -75,10 +69,8 @@ to_message(#mqtt_packet_connect{will_retain = Retain,
|
|||
will_topic = Topic,
|
||||
will_props = Props,
|
||||
will_payload = Payload}) ->
|
||||
Msg = emqx_message:make(undefined, Topic, Payload),
|
||||
Msg#message{flags = #{retain => Retain},
|
||||
headers = #{qos => Qos},
|
||||
properties = Props}.
|
||||
Msg = emqx_message:new(undefined, #{qos => Qos, retain => Retain}, Topic, Payload),
|
||||
Msg#message{properties = Props}.
|
||||
|
||||
%% @doc Format packet
|
||||
-spec(format(mqtt_packet()) -> iolist()).
|
||||
|
|
|
@ -1,57 +1,52 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_pmon).
|
||||
|
||||
-export([new/0]).
|
||||
|
||||
-export([monitor/2, monitor/3, demonitor/2, find/2, erase/2]).
|
||||
|
||||
-compile({no_auto_import,[monitor/3]}).
|
||||
-type(pmon() :: map()).
|
||||
|
||||
-type(pmon() :: {?MODULE, map()}).
|
||||
-export_type([pmon/0]).
|
||||
|
||||
-spec(new() -> pmon()).
|
||||
new() ->
|
||||
maps:new().
|
||||
new() -> {?MODULE, maps:new()}.
|
||||
|
||||
-spec(monitor(pid(), pmon()) -> pmon()).
|
||||
monitor(Pid, PM) ->
|
||||
monitor(Pid, undefined, PM).
|
||||
|
||||
monitor(Pid, Val, PM) ->
|
||||
case maps:is_key(Pid, PM) of
|
||||
monitor(Pid, Val, {?MODULE, PM}) ->
|
||||
{?MODULE, case maps:is_key(Pid, PM) of
|
||||
true -> PM;
|
||||
false -> Ref = erlang:monitor(process, Pid),
|
||||
maps:put(Pid, {Ref, Val}, PM)
|
||||
end.
|
||||
end}.
|
||||
|
||||
-spec(demonitor(pid(), pmon()) -> pmon()).
|
||||
demonitor(Pid, PM) ->
|
||||
case maps:find(Pid, PM) of
|
||||
demonitor(Pid, {?MODULE, PM}) ->
|
||||
{?MODULE, case maps:find(Pid, PM) of
|
||||
{ok, {Ref, _Val}} ->
|
||||
%% Don't flush
|
||||
_ = erlang:demonitor(Ref),
|
||||
maps:remove(Pid, PM);
|
||||
error -> PM
|
||||
end.
|
||||
end}.
|
||||
|
||||
-spec(find(pid(), pmon()) -> undefined | term()).
|
||||
find(Pid, PM) ->
|
||||
find(Pid, {?MODULE, PM}) ->
|
||||
case maps:find(Pid, PM) of
|
||||
{ok, {_Ref, Val}} ->
|
||||
Val;
|
||||
|
@ -59,6 +54,6 @@ find(Pid, PM) ->
|
|||
end.
|
||||
|
||||
-spec(erase(pid(), pmon()) -> pmon()).
|
||||
erase(Pid, PM) ->
|
||||
maps:remove(Pid, PM).
|
||||
erase(Pid, {?MODULE, PM}) ->
|
||||
{?MODULE, maps:remove(Pid, PM)}.
|
||||
|
||||
|
|
|
@ -1,50 +1,40 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_pool).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% Start the pool supervisor
|
||||
-export([start_link/0]).
|
||||
-export([start_link/0, start_link/2]).
|
||||
-export([submit/1, async_submit/1]).
|
||||
|
||||
%% API Exports
|
||||
-export([start_link/2, submit/1, async_submit/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {pool, id}).
|
||||
|
||||
-define(POOL, ?MODULE).
|
||||
|
||||
%% @doc Start Pooler Supervisor.
|
||||
%% @doc Start pooler supervisor.
|
||||
start_link() ->
|
||||
emqx_pool_sup:start_link(?POOL, random, {?MODULE, start_link, []}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-spec(start_link(atom(), pos_integer())
|
||||
-> {ok, pid()} | ignore | {error, term()}).
|
||||
%% @doc Start pool
|
||||
-spec(start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link(Pool, Id) ->
|
||||
gen_server:start_link({local, emqx_misc:proc_name(?MODULE, Id)},
|
||||
?MODULE, [Pool, Id], []).
|
||||
gen_server:start_link({local, emqx_misc:proc_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
%% @doc Submit work to the pool
|
||||
-spec(submit(fun()) -> any()).
|
||||
|
@ -59,45 +49,45 @@ async_submit(Fun) ->
|
|||
worker() ->
|
||||
gproc_pool:pick_worker(pool).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id]) ->
|
||||
gproc_pool:connect_worker(Pool, {Pool, Id}),
|
||||
true = gproc_pool:connect_worker(Pool, {Pool, Id}),
|
||||
{ok, #state{pool = Pool, id = Id}}.
|
||||
|
||||
handle_call({submit, Fun}, _From, State) ->
|
||||
{reply, catch run(Fun), State};
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[POOL] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Pool] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({async_submit, Fun}, State) ->
|
||||
try run(Fun)
|
||||
catch _:Error ->
|
||||
emqx_logger:error("[POOL] Error: ~p, ~p", [Error, erlang:get_stacktrace()])
|
||||
catch _:Error:Stacktrace ->
|
||||
emqx_logger:error("[Pool] error: ~p, ~p", [Error, Stacktrace])
|
||||
end,
|
||||
{noreply, State};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[POOL] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Pool] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[POOL] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Pool] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{pool = Pool, id = Id}) ->
|
||||
gproc_pool:disconnect_worker(Pool, {Pool, Id}).
|
||||
true = gproc_pool:disconnect_worker(Pool, {Pool, Id}).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
run({M, F, A}) ->
|
||||
erlang:apply(M, F, A);
|
||||
|
|
|
@ -1,27 +1,23 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_pool_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([spec/1, spec/2, start_link/3, start_link/4]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-spec(spec(list()) -> supervisor:child_spec()).
|
||||
|
@ -35,8 +31,7 @@ spec(ChildId, Args) ->
|
|||
|
||||
-spec(start_link(atom() | tuple(), atom(), mfa()) -> {ok, pid()} | {error, term()}).
|
||||
start_link(Pool, Type, MFA) ->
|
||||
Schedulers = erlang:system_info(schedulers),
|
||||
start_link(Pool, Type, Schedulers, MFA).
|
||||
start_link(Pool, Type, emqx_vm:schedulers(schedulers), MFA).
|
||||
|
||||
-spec(start_link(atom() | tuple(), atom(), pos_integer(), mfa()) -> {ok, pid()} | {error, term()}).
|
||||
start_link(Pool, Type, Size, MFA) when is_atom(Pool) ->
|
||||
|
@ -49,8 +44,7 @@ init([Pool, Type, Size, {M, F, Args}]) ->
|
|||
{ok, {{one_for_one, 10, 3600}, [
|
||||
begin
|
||||
ensure_pool_worker(Pool, {Pool, I}, I),
|
||||
{{M, I}, {M, F, [Pool, I | Args]},
|
||||
transient, 5000, worker, [M]}
|
||||
{{M, I}, {M, F, [Pool, I | Args]}, transient, 5000, worker, [M]}
|
||||
end || I <- lists:seq(1, Size)]}}.
|
||||
|
||||
ensure_pool(Pool, Type, Opts) ->
|
||||
|
|
|
@ -129,11 +129,10 @@ client(#proto_state{client_id = ClientId,
|
|||
WillMsg =:= undefined -> undefined;
|
||||
true -> WillMsg#message.topic
|
||||
end,
|
||||
#client{client_id = ClientId,
|
||||
client_pid = ClientPid,
|
||||
#client{id = ClientId,
|
||||
pid = ClientPid,
|
||||
username = Username,
|
||||
peername = Peername,
|
||||
mountpoint = MountPoint}.
|
||||
peername = Peername}.
|
||||
|
||||
session(#proto_state{session = Session}) ->
|
||||
Session.
|
||||
|
@ -334,7 +333,7 @@ publish(Packet = ?PUBLISH_PACKET(?QOS_0, _PacketId),
|
|||
mountpoint = MountPoint,
|
||||
session = Session}) ->
|
||||
Msg = emqx_packet:to_message(Packet),
|
||||
Msg1 = Msg#message{from = #client{client_id = ClientId, username = Username}},
|
||||
Msg1 = Msg#message{from = #client{id = ClientId, username = Username}},
|
||||
emqx_session:publish(Session, mount(replvar(MountPoint, State), Msg1));
|
||||
|
||||
publish(Packet = ?PUBLISH_PACKET(?QOS_1, _PacketId), State) ->
|
||||
|
@ -350,7 +349,7 @@ with_puback(Type, Packet = ?PUBLISH_PACKET(_Qos, PacketId),
|
|||
session = Session}) ->
|
||||
%% TODO: ...
|
||||
Msg = emqx_packet:to_message(Packet),
|
||||
Msg1 = Msg#message{from = #client{client_id = ClientId, username = Username}},
|
||||
Msg1 = Msg#message{from = #client{id = ClientId, username = Username}},
|
||||
case emqx_session:publish(Session, mount(replvar(MountPoint, State), Msg1)) of
|
||||
ok ->
|
||||
case Type of
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% 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 MQTT5 reason codes
|
||||
-module(emqx_reason_codes).
|
||||
|
||||
-export([name/1, text/1]).
|
||||
|
@ -61,7 +60,7 @@ name(16#9F) -> connection_rate_exceeded;
|
|||
name(16#A0) -> maximum_connect_time;
|
||||
name(16#A1) -> subscription_identifiers_not_supported;
|
||||
name(16#A2) -> wildcard_subscriptions_not_supported;
|
||||
name(Code) -> list_to_atom("unkown_" ++ integer_to_list(Code)).
|
||||
name(Code) -> list_to_atom("unkown_reason_code" ++ integer_to_list(Code)).
|
||||
|
||||
text(16#00) -> <<"Success">>;
|
||||
text(16#01) -> <<"Granted QoS 1">>;
|
||||
|
@ -106,5 +105,5 @@ text(16#9F) -> <<"Connection rate exceeded">>;
|
|||
text(16#A0) -> <<"Maximum connect time">>;
|
||||
text(16#A1) -> <<"Subscription Identifiers not supported">>;
|
||||
text(16#A2) -> <<"Wildcard Subscriptions not supported">>;
|
||||
text(Code) -> iolist_to_binary(["Unkown", integer_to_list(Code)]).
|
||||
text(Code) -> iolist_to_binary(["Unkown Reason Code:", integer_to_list(Code)]).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_router).
|
||||
|
||||
|
@ -34,13 +32,11 @@
|
|||
-export([get_routes/1]).
|
||||
-export([del_route/1, del_route/2, del_route/3]).
|
||||
-export([has_routes/1, match_routes/1, print_routes/1]).
|
||||
|
||||
%% Topics
|
||||
-export([topics/0]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-type(destination() :: node() | {binary(), node()}).
|
||||
|
||||
|
@ -49,15 +45,12 @@
|
|||
-record(state, {pool, id, batch :: #batch{}}).
|
||||
|
||||
-define(ROUTE, emqx_route).
|
||||
|
||||
-define(BATCH(Enabled), #batch{enabled = Enabled}).
|
||||
-define(BATCH(Enabled, Pending), #batch{enabled = Enabled, pending = Pending}).
|
||||
|
||||
-define(BATCH(Enabled, Pending),
|
||||
#batch{enabled = Enabled, pending = Pending}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Mnesia bootstrap
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
mnesia(boot) ->
|
||||
ok = ekka_mnesia:create_table(?ROUTE, [
|
||||
|
@ -65,23 +58,21 @@ mnesia(boot) ->
|
|||
{ram_copies, [node()]},
|
||||
{record_name, route},
|
||||
{attributes, record_info(fields, route)}]);
|
||||
|
||||
mnesia(copy) ->
|
||||
ok = ekka_mnesia:copy_table(?ROUTE).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Strat a Router
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Strat a router
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(start_link(atom(), pos_integer())
|
||||
-> {ok, pid()} | ignore | {error, term()}).
|
||||
-spec(start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link(Pool, Id) ->
|
||||
gen_server:start_link({local, emqx_misc:proc_name(?MODULE, Id)},
|
||||
?MODULE, [Pool, Id], [{hibernate_after, 2000}]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Route APIs
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(add_route(topic() | route()) -> ok).
|
||||
add_route(Topic) when is_binary(Topic) ->
|
||||
|
@ -95,8 +86,7 @@ add_route(Topic, Dest) when is_binary(Topic) ->
|
|||
|
||||
-spec(add_route({pid(), reference()}, topic(), destination()) -> ok).
|
||||
add_route(From, Topic, Dest) when is_binary(Topic) ->
|
||||
Route = #route{topic = Topic, dest = Dest},
|
||||
cast(pick(Topic), {add_route, From, Route}).
|
||||
cast(pick(Topic), {add_route, From, #route{topic = Topic, dest = Dest}}).
|
||||
|
||||
-spec(get_routes(topic()) -> [route()]).
|
||||
get_routes(Topic) ->
|
||||
|
@ -114,8 +104,7 @@ del_route(Topic, Dest) when is_binary(Topic) ->
|
|||
|
||||
-spec(del_route({pid(), reference()}, topic(), destination()) -> ok).
|
||||
del_route(From, Topic, Dest) when is_binary(Topic) ->
|
||||
Route = #route{topic = Topic, dest = Dest},
|
||||
cast(pick(Topic), {del_route, From, Route}).
|
||||
cast(pick(Topic), {del_route, From, #route{topic = Topic, dest = Dest}}).
|
||||
|
||||
-spec(has_routes(topic()) -> boolean()).
|
||||
has_routes(Topic) when is_binary(Topic) ->
|
||||
|
@ -144,9 +133,9 @@ cast(Router, Msg) ->
|
|||
pick(Topic) ->
|
||||
gproc_pool:pick_worker(router, Topic).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([Pool, Id]) ->
|
||||
rand:seed(exsplus, erlang:timestamp()),
|
||||
|
@ -156,12 +145,12 @@ init([Pool, Id]) ->
|
|||
{ok, ensure_batch_timer(#state{pool = Pool, id = Id, batch = Batch})}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[Router] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Router] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({add_route, From, Route}, State) ->
|
||||
{noreply, NewState} = handle_cast({add_route, Route}, State),
|
||||
gen_server:reply(From, ok),
|
||||
_ = gen_server:reply(From, ok),
|
||||
{noreply, NewState};
|
||||
|
||||
handle_cast({add_route, Route = #route{topic = Topic, dest = Dest}}, State) ->
|
||||
|
@ -178,7 +167,7 @@ handle_cast({add_route, Route = #route{topic = Topic, dest = Dest}}, State) ->
|
|||
|
||||
handle_cast({del_route, From, Route}, State) ->
|
||||
{noreply, NewState} = handle_cast({del_route, Route}, State),
|
||||
gen_server:reply(From, ok),
|
||||
_ = gen_server:reply(From, ok),
|
||||
{noreply, NewState};
|
||||
|
||||
handle_cast({del_route, Route = #route{topic = Topic}}, State) ->
|
||||
|
@ -194,7 +183,7 @@ handle_cast({del_route, Route = #route{topic = Topic}}, State) ->
|
|||
end};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[Router] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Router] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({timeout, _TRef, batch_delete}, State = #state{batch = Batch}) ->
|
||||
|
@ -202,7 +191,7 @@ handle_info({timeout, _TRef, batch_delete}, State = #state{batch = Batch}) ->
|
|||
{noreply, ensure_batch_timer(State#state{batch = ?BATCH(true, sets:new())}), hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[Router] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Router] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{pool = Pool, id = Id, batch = Batch}) ->
|
||||
|
@ -212,9 +201,9 @@ terminate(_Reason, #state{pool = Pool, id = Id, batch = Batch}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
ensure_batch_timer(State = #state{batch = #batch{enabled = false}}) ->
|
||||
State;
|
||||
|
@ -225,7 +214,7 @@ ensure_batch_timer(State = #state{batch = Batch}) ->
|
|||
cacel_batch_timer(#batch{enabled = false}) ->
|
||||
ok;
|
||||
cacel_batch_timer(#batch{enabled = true, timer = TRef}) ->
|
||||
erlang:cancel_timer(TRef).
|
||||
catch erlang:cancel_timer(TRef).
|
||||
|
||||
add_direct_route(Route) ->
|
||||
mnesia:async_dirty(fun mnesia:write/3, [?ROUTE, Route, sticky_write]).
|
||||
|
@ -275,6 +264,6 @@ trans(Fun, Args) ->
|
|||
end.
|
||||
|
||||
log(ok) -> ok;
|
||||
log({error, Error}) ->
|
||||
emqx_logger:error("[Router] Mnesia aborted: ~p", [Error]).
|
||||
log({error, Reason}) ->
|
||||
emqx_logger:error("[Router] mnesia aborted: ~p", [Reason]).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_router_helper).
|
||||
|
||||
|
@ -30,11 +28,10 @@
|
|||
-export([start_link/0, monitor/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(routing_node, {name, const = unused}).
|
||||
|
||||
-record(state, {nodes = []}).
|
||||
|
||||
-compile({no_auto_import, [monitor/1]}).
|
||||
|
@ -42,12 +39,11 @@
|
|||
-define(SERVER, ?MODULE).
|
||||
-define(ROUTE, emqx_route).
|
||||
-define(ROUTING_NODE, emqx_routing_node).
|
||||
|
||||
-define(LOCK, {?MODULE, cleanup_routes}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Mnesia bootstrap
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
mnesia(boot) ->
|
||||
ok = ekka_mnesia:create_table(?ROUTING_NODE, [
|
||||
|
@ -59,9 +55,9 @@ mnesia(boot) ->
|
|||
mnesia(copy) ->
|
||||
ok = ekka_mnesia:copy_table(?ROUTING_NODE).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% @doc Starts the router helper
|
||||
-spec(start_link() -> {ok, pid()} | ignore | {error, any()}).
|
||||
|
@ -79,9 +75,9 @@ monitor(Node) when is_atom(Node) ->
|
|||
false -> mnesia:dirty_write(?ROUTING_NODE, #routing_node{name = Node})
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
ekka:monitor(membership),
|
||||
|
@ -98,16 +94,15 @@ init([]) ->
|
|||
{ok, #state{nodes = Nodes}, hibernate}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[RouterHelper] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[RouterHelper] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[RouterHelper] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[RouterHelper] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({mnesia_table_event, {write, #routing_node{name = Node}, _}},
|
||||
State = #state{nodes = Nodes}) ->
|
||||
emqx_logger:info("[RouterHelper] New routing node: ~s", [Node]),
|
||||
handle_info({mnesia_table_event, {write, #routing_node{name = Node}, _}}, State = #state{nodes = Nodes}) ->
|
||||
emqx_logger:info("[RouterHelper] write routing node: ~s", [Node]),
|
||||
case ekka:is_member(Node) orelse lists:member(Node, Nodes) of
|
||||
true -> {noreply, State};
|
||||
false -> _ = erlang:monitor_node(Node, true),
|
||||
|
@ -132,7 +127,7 @@ handle_info({membership, _Event}, State) ->
|
|||
{noreply, State};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[RouteHelper] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[RouteHelper] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{}) ->
|
||||
|
@ -143,9 +138,9 @@ terminate(_Reason, #state{}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
stats_fun() ->
|
||||
fun() ->
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_router_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([init/1]).
|
||||
|
||||
start_link() ->
|
||||
|
@ -34,6 +31,5 @@ init([]) ->
|
|||
RouterPool = emqx_pool_sup:spec(emqx_router_pool,
|
||||
[router, hash, emqx_vm:schedulers(),
|
||||
{emqx_router, start_link, []}]),
|
||||
|
||||
{ok, {{one_for_all, 0, 1}, [Helper, RouterPool]}}.
|
||||
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% 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 wrap gen_rpc?
|
||||
-module(emqx_rpc).
|
||||
|
||||
-export([call/4, cast/4]).
|
||||
|
||||
-export([multicall/4]).
|
||||
|
||||
-define(RPC, rpc).
|
||||
-define(RPC, gen_rpc).
|
||||
|
||||
call(Node, Mod, Fun, Args) ->
|
||||
?RPC:call(Node, Mod, Fun, Args).
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_session_sup).
|
||||
|
||||
|
@ -37,6 +35,10 @@ start_session(Attrs) ->
|
|||
|
||||
init([]) ->
|
||||
{ok, {{simple_one_for_one, 0, 1},
|
||||
[{session, {emqx_session, start_link, []},
|
||||
temporary, 5000, worker, [emqx_session]}]}}.
|
||||
[#{id => session,
|
||||
start => {emqx_session, start_link, []},
|
||||
restart => temporary,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_session]}]}}.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_shared_sub).
|
||||
|
||||
|
@ -33,20 +31,18 @@
|
|||
-export([dispatch/3]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
-define(TAB, emqx_shared_subscription).
|
||||
|
||||
-record(state, {pmon}).
|
||||
|
||||
-record(shared_subscription, {group, topic, subpid}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Mnesia bootstrap
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
mnesia(boot) ->
|
||||
ok = ekka_mnesia:create_table(?TAB, [
|
||||
|
@ -58,15 +54,15 @@ mnesia(boot) ->
|
|||
mnesia(copy) ->
|
||||
ok = ekka_mnesia:copy_table(?TAB).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(start_link() -> {ok, pid()} | ignore | {error, any()}).
|
||||
-spec(start_link() -> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
-spec(strategy() -> random | hash).
|
||||
-spec(strategy() -> round_robin | random | hash).
|
||||
strategy() ->
|
||||
emqx_config:get_env(shared_subscription_strategy, random).
|
||||
|
||||
|
@ -84,7 +80,7 @@ unsubscribe(Group, Topic, SubPid) when is_pid(SubPid) ->
|
|||
record(Group, Topic, SubPid) ->
|
||||
#shared_subscription{group = Group, topic = Topic, subpid = SubPid}.
|
||||
|
||||
%% TODO: ensure the delivery...
|
||||
%% TODO: dispatch strategy, ensure the delivery...
|
||||
dispatch(Group, Topic, Delivery = #delivery{message = Msg, flows = Flows}) ->
|
||||
case pick(subscribers(Group, Topic)) of
|
||||
false -> Delivery;
|
||||
|
@ -97,16 +93,15 @@ pick([]) ->
|
|||
pick([SubPid]) ->
|
||||
SubPid;
|
||||
pick(SubPids) ->
|
||||
X = abs(erlang:monotonic_time()
|
||||
bxor erlang:unique_integer()),
|
||||
X = abs(erlang:monotonic_time() bxor erlang:unique_integer()),
|
||||
lists:nth((X rem length(SubPids)) + 1, SubPids).
|
||||
|
||||
subscribers(Group, Topic) ->
|
||||
ets:select(?TAB, [{{shared_subscription, Group, Topic, '$1'}, [], ['$1']}]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
{atomic, PMon} = mnesia:transaction(fun init_monitors/0),
|
||||
|
@ -120,14 +115,14 @@ init_monitors() ->
|
|||
end, emqx_pmon:new(), ?TAB).
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[Shared] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[SharedSub] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({monitor, SubPid}, State= #state{pmon = PMon}) ->
|
||||
{noreply, update_stats(State#state{pmon = emqx_pmon:monitor(SubPid, PMon)})};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[Shared] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[SharedSub] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({mnesia_table_event, {write, NewRecord, _}}, State = #state{pmon = PMon}) ->
|
||||
|
@ -142,12 +137,12 @@ handle_info({mnesia_table_event, _Event}, State) ->
|
|||
{noreply, State};
|
||||
|
||||
handle_info({'DOWN', _MRef, process, SubPid, _Reason}, State = #state{pmon = PMon}) ->
|
||||
emqx_logger:info("Shared subscription down: ~p", [SubPid]),
|
||||
emqx_logger:info("[SharedSub] shared subscriber down: ~p", [SubPid]),
|
||||
mnesia:async_dirty(fun cleanup_down/1, [SubPid]),
|
||||
{noreply, update_stats(State#state{pmon = emqx_pmon:erase(SubPid, PMon)})};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[Shared] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[SharedSub] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
|
@ -161,8 +156,8 @@ code_change(_OldVsn, State, _Extra) ->
|
|||
%%--------------------------------------------------------------------
|
||||
|
||||
cleanup_down(SubPid) ->
|
||||
Pat = #shared_subscription{_ = '_', subpid = SubPid},
|
||||
lists:foreach(fun(Record) -> mnesia:delete_object(?TAB, Record) end, mnesia:match_object(Pat)).
|
||||
lists:foreach(fun(Record) -> mnesia:delete_object(?TAB, Record) end,
|
||||
mnesia:match_object(#shared_subscription{_ = '_', subpid = SubPid})).
|
||||
|
||||
update_stats(State) ->
|
||||
emqx_stats:setstat('subscriptions/shared/count', 'subscriptions/shared/max', ets:info(?TAB, size)), State.
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sm).
|
||||
|
||||
|
@ -30,8 +28,8 @@
|
|||
%% Internal functions for rpc
|
||||
-export([dispatch/3]).
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
-record(state, {session_pmon}).
|
||||
|
||||
|
@ -50,7 +48,8 @@ start_link() ->
|
|||
%% @doc Open a session.
|
||||
-spec(open_session(map()) -> {ok, pid()} | {error, term()}).
|
||||
open_session(Attrs = #{clean_start := true,
|
||||
client_id := ClientId, client_pid := ClientPid}) ->
|
||||
client_id := ClientId,
|
||||
client_pid := ClientPid}) ->
|
||||
CleanStart = fun(_) ->
|
||||
ok = discard_session(ClientId, ClientPid),
|
||||
emqx_session_sup:start_session(Attrs)
|
||||
|
@ -58,7 +57,8 @@ open_session(Attrs = #{clean_start := true,
|
|||
emqx_sm_locker:trans(ClientId, CleanStart);
|
||||
|
||||
open_session(Attrs = #{clean_start := false,
|
||||
client_id := ClientId, client_pid := ClientPid}) ->
|
||||
client_id := ClientId,
|
||||
client_pid := ClientPid}) ->
|
||||
ResumeStart = fun(_) ->
|
||||
case resume_session(ClientId, ClientPid) of
|
||||
{ok, SessionPid} ->
|
||||
|
@ -72,7 +72,7 @@ open_session(Attrs = #{clean_start := false,
|
|||
emqx_sm_locker:trans(ClientId, ResumeStart).
|
||||
|
||||
%% @doc Discard all the sessions identified by the ClientId.
|
||||
-spec(discard_session(map()) -> ok).
|
||||
-spec(discard_session(client_id()) -> ok).
|
||||
discard_session(ClientId) when is_binary(ClientId) ->
|
||||
discard_session(ClientId, self()).
|
||||
|
||||
|
@ -80,8 +80,8 @@ discard_session(ClientId, ClientPid) when is_binary(ClientId) ->
|
|||
lists:foreach(
|
||||
fun({_ClientId, SessionPid}) ->
|
||||
case catch emqx_session:discard(SessionPid, ClientPid) of
|
||||
{'EXIT', Error} ->
|
||||
emqx_logger:error("[SM] Failed to discard ~p: ~p", [SessionPid, Error]);
|
||||
{Err, Reason} when Err =:= 'EXIT'; Err =:= error ->
|
||||
emqx_logger:error("[SM] Failed to discard ~p: ~p", [SessionPid, Reason]);
|
||||
ok -> ok
|
||||
end
|
||||
end, lookup_session(ClientId)).
|
||||
|
@ -197,11 +197,12 @@ safe_lookup_element(Tab, Key, Default) ->
|
|||
error:badarg -> Default
|
||||
end.
|
||||
|
||||
notify(Event) -> gen_server:cast(?SM, {notify, Event}).
|
||||
notify(Event) ->
|
||||
gen_server:cast(?SM, {notify, Event}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
TabOpts = [public, set, {write_concurrency, true}],
|
||||
|
@ -213,8 +214,8 @@ init([]) ->
|
|||
{ok, #state{session_pmon = emqx_pmon:new()}}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[SM] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[SM] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({notify, {registered, ClientId, SessionPid}}, State = #state{session_pmon = PMon}) ->
|
||||
{noreply, State#state{session_pmon = emqx_pmon:monitor(SessionPid, ClientId, PMon)}};
|
||||
|
@ -223,7 +224,7 @@ handle_cast({notify, {unregistered, _ClientId, SessionPid}}, State = #state{sess
|
|||
{noreply, State#state{session_pmon = emqx_pmon:demonitor(SessionPid, PMon)}};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[SM] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[SM] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({'DOWN', _MRef, process, DownPid, _Reason}, State = #state{session_pmon = PMon}) ->
|
||||
|
@ -235,24 +236,23 @@ handle_info({'DOWN', _MRef, process, DownPid, _Reason}, State = #state{session_p
|
|||
end;
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[SM] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[SM] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
emqx_stats:cancel_update(cm_stats).
|
||||
emqx_stats:cancel_update(sm_stats).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
stats_fun() ->
|
||||
fun () ->
|
||||
fun() ->
|
||||
safe_update_stats(?SESSION, 'sessions/count', 'sessions/max'),
|
||||
safe_update_stats(?SESSION_P, 'sessions/persistent/count',
|
||||
'sessions/persistent/max')
|
||||
safe_update_stats(?SESSION_P, 'sessions/persistent/count', 'sessions/persistent/max')
|
||||
end.
|
||||
|
||||
safe_update_stats(Tab, Stat, MaxStat) ->
|
||||
|
|
|
@ -1,27 +1,23 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sm_locker).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([trans/2, trans/3]).
|
||||
|
||||
-export([lock/1, lock/2, unlock/1]).
|
||||
|
||||
-spec(start_link() -> {ok, pid()} | ignore | {error, term()}).
|
||||
|
@ -32,9 +28,7 @@ start_link() ->
|
|||
trans(ClientId, Fun) ->
|
||||
trans(ClientId, Fun, undefined).
|
||||
|
||||
-spec(trans(client_id() | undefined,
|
||||
fun(([node()]) -> any()),
|
||||
ekka_locker:piggyback()) -> any()).
|
||||
-spec(trans(client_id() | undefined, fun(([node()]) -> any()), ekka_locker:piggyback()) -> any()).
|
||||
trans(undefined, Fun, _Piggyback) ->
|
||||
Fun([]);
|
||||
trans(ClientId, Fun, Piggyback) ->
|
||||
|
@ -49,8 +43,7 @@ trans(ClientId, Fun, Piggyback) ->
|
|||
lock(ClientId) ->
|
||||
ekka_locker:aquire(?MODULE, ClientId, strategy()).
|
||||
|
||||
-spec(lock(client_id(), ekka_locker:piggyback())
|
||||
-> ekka_locker:lock_result()).
|
||||
-spec(lock(client_id(), ekka_locker:piggyback()) -> ekka_locker:lock_result()).
|
||||
lock(ClientId, Piggyback) ->
|
||||
ekka_locker:aquire(?MODULE, ClientId, strategy(), Piggyback).
|
||||
|
||||
|
@ -60,5 +53,5 @@ unlock(ClientId) ->
|
|||
|
||||
-spec(strategy() -> local | one | quorum | all).
|
||||
strategy() ->
|
||||
application:get_env(emqx, session_locking_strategy, quorum).
|
||||
emqx_config:get_env(session_locking_strategy, quorum).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sm_registry).
|
||||
|
||||
|
@ -20,25 +18,17 @@
|
|||
|
||||
-include("emqx.hrl").
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([is_enabled/0]).
|
||||
|
||||
-export([register_session/1, lookup_session/1, unregister_session/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
-define(REGISTRY, ?MODULE).
|
||||
|
||||
-define(TAB, emqx_session_registry).
|
||||
|
||||
-define(LOCK, {?MODULE, cleanup_sessions}).
|
||||
|
||||
-record(global_session, {sid, pid}).
|
||||
|
||||
-record(state, {}).
|
||||
|
||||
-type(session_pid() :: pid()).
|
||||
|
@ -58,21 +48,19 @@ lookup_session(ClientId) ->
|
|||
<- mnesia:dirty_read(?TAB, ClientId)].
|
||||
|
||||
-spec(register_session({client_id(), session_pid()}) -> ok).
|
||||
register_session({ClientId, SessionPid}) when is_binary(ClientId),
|
||||
is_pid(SessionPid) ->
|
||||
register_session({ClientId, SessionPid}) when is_binary(ClientId), is_pid(SessionPid) ->
|
||||
mnesia:dirty_write(?TAB, record(ClientId, SessionPid)).
|
||||
|
||||
-spec(unregister_session({client_id(), session_pid()}) -> ok).
|
||||
unregister_session({ClientId, SessionPid}) when is_binary(ClientId),
|
||||
is_pid(SessionPid) ->
|
||||
unregister_session({ClientId, SessionPid}) when is_binary(ClientId), is_pid(SessionPid) ->
|
||||
mnesia:dirty_delete_object(?TAB, record(ClientId, SessionPid)).
|
||||
|
||||
record(ClientId, SessionPid) ->
|
||||
#global_session{sid = ClientId, pid = SessionPid}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
ok = ekka_mnesia:create_table(?TAB, [
|
||||
|
@ -85,11 +73,11 @@ init([]) ->
|
|||
{ok, #state{}}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[Registry] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Registry] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[Registry] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Registry] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({membership, {mnesia, down, Node}}, State) ->
|
||||
|
@ -103,7 +91,7 @@ handle_info({membership, _Event}, State) ->
|
|||
{noreply, State};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[Registry] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Registry] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
|
@ -112,9 +100,9 @@ terminate(_Reason, _State) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
cleanup_sessions(Node) ->
|
||||
Pat = [{#global_session{pid = '$1', _ = '_'},
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sm_sup).
|
||||
|
||||
|
@ -26,17 +25,26 @@ start_link() ->
|
|||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
%% Session Locker
|
||||
Locker = {locker, {emqx_sm_locker, start_link, []},
|
||||
permanent, 5000, worker, [emqx_sm_locker]},
|
||||
|
||||
%% Session Registry
|
||||
Registry = {registry, {emqx_sm_registry, start_link, []},
|
||||
permanent, 5000, worker, [emqx_sm_registry]},
|
||||
|
||||
%% Session locker
|
||||
Locker = #{id => locker,
|
||||
start => {emqx_sm_locker, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_sm_locker]},
|
||||
%% Session registry
|
||||
Registry = #{id => registry,
|
||||
start => {emqx_sm_registry, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_sm_registry]},
|
||||
%% Session Manager
|
||||
Manager = {manager, {emqx_sm, start_link, []},
|
||||
permanent, 5000, worker, [emqx_sm]},
|
||||
|
||||
Manager = #{id => manager,
|
||||
start => {emqx_sm, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_sm]},
|
||||
{ok, {{rest_for_one, 10, 3600}, [Locker, Registry, Manager]}}.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_stats).
|
||||
|
||||
|
@ -27,15 +25,13 @@
|
|||
|
||||
%% Stats API.
|
||||
-export([statsfun/1, statsfun/2, getstats/0, getstat/1, setstat/2, setstat/3]).
|
||||
|
||||
-export([update_interval/2, update_interval/3, cancel_update/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(update, {name, countdown, interval, func}).
|
||||
|
||||
-record(state, {timer, updates :: #update{}}).
|
||||
|
||||
-type(stats() :: list({atom(), non_neg_integer()})).
|
||||
|
@ -85,10 +81,6 @@
|
|||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% Get all stats.
|
||||
-spec(all() -> stats()).
|
||||
all() -> getstats().
|
||||
|
@ -147,23 +139,23 @@ rec(Name, Secs, UpFun) ->
|
|||
cast(Msg) ->
|
||||
gen_server:cast(?SERVER, Msg).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
_ = emqx_tables:new(?TAB, [set, public, {write_concurrency, true}]),
|
||||
Stats = lists:append([?CLIENT_STATS, ?SESSION_STATS, ?PUBSUB_STATS,
|
||||
?ROUTE_STATS, ?RETAINED_STATS]),
|
||||
ets:insert(?TAB, [{Name, 0} || Name <- Stats]),
|
||||
true = ets:insert(?TAB, [{Name, 0} || Name <- Stats]),
|
||||
{ok, start_timer(#state{updates = []}), hibernate}.
|
||||
|
||||
start_timer(State) ->
|
||||
State#state{timer = emqx_misc:start_timer(timer:seconds(1), tick)}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[STATS] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Stats] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast({setstat, Stat, MaxStat, Val}, State) ->
|
||||
try ets:lookup_element(?TAB, MaxStat, 2) of
|
||||
|
@ -177,11 +169,10 @@ handle_cast({setstat, Stat, MaxStat, Val}, State) ->
|
|||
safe_update_element(Stat, Val),
|
||||
{noreply, State};
|
||||
|
||||
handle_cast({update_interval, Update = #update{name = Name}},
|
||||
State = #state{updates = Updates}) ->
|
||||
handle_cast({update_interval, Update = #update{name = Name}}, State = #state{updates = Updates}) ->
|
||||
case lists:keyfind(Name, #update.name, Updates) of
|
||||
#update{} ->
|
||||
emqx_logger:error("[STATS]: Duplicated update: ~s", [Name]),
|
||||
emqx_logger:error("[Stats]: duplicated update: ~s", [Name]),
|
||||
{noreply, State};
|
||||
false ->
|
||||
{noreply, State#state{updates = [Update | Updates]}}
|
||||
|
@ -191,17 +182,16 @@ handle_cast({cancel_update, Name}, State = #state{updates = Updates}) ->
|
|||
{noreply, State#state{updates = lists:keydelete(Name, #update.name, Updates)}};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[STATS] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Stats] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({timeout, TRef, tick}, State = #state{timer = TRef,
|
||||
updates = Updates}) ->
|
||||
handle_info({timeout, TRef, tick}, State = #state{timer= TRef, updates = Updates}) ->
|
||||
lists:foldl(
|
||||
fun(Update = #update{name = Name, countdown = C, interval = I,
|
||||
func = UpFun}, Acc) when C =< 0 ->
|
||||
try UpFun()
|
||||
catch _:Error ->
|
||||
emqx_logger:error("[STATS] Update ~s error: ~p", [Name, Error])
|
||||
emqx_logger:error("[Stats] update ~s error: ~p", [Name, Error])
|
||||
end,
|
||||
[Update#update{countdown = I} | Acc];
|
||||
(Update = #update{countdown = C}, Acc) ->
|
||||
|
@ -210,7 +200,7 @@ handle_info({timeout, TRef, tick}, State = #state{timer = TRef,
|
|||
{noreply, start_timer(State), hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[STATS] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Stats] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{timer = TRef}) ->
|
||||
|
@ -219,9 +209,9 @@ terminate(_Reason, #state{timer = TRef}) ->
|
|||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
safe_update_element(Key, Val) ->
|
||||
try ets:update_element(?TAB, Key, {2, Val})
|
||||
|
|
104
src/emqx_sys.erl
104
src/emqx_sys.erl
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sys).
|
||||
|
||||
|
@ -21,13 +19,10 @@
|
|||
-include("emqx.hrl").
|
||||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([version/0, uptime/0, datetime/0, sysdescr/0, sys_interval/0]).
|
||||
|
||||
-export([info/0]).
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-import(emqx_topic, [systop/1]).
|
||||
-import(emqx_misc, [start_timer/2]).
|
||||
|
@ -48,10 +43,6 @@
|
|||
start_link() ->
|
||||
gen_server:start_link({local, ?SYS}, ?MODULE, [], []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @doc Get sys version
|
||||
-spec(version() -> string()).
|
||||
version() ->
|
||||
|
@ -64,7 +55,8 @@ sysdescr() ->
|
|||
|
||||
%% @doc Get sys uptime
|
||||
-spec(uptime() -> string()).
|
||||
uptime() -> gen_server:call(?SYS, uptime).
|
||||
uptime() ->
|
||||
gen_server:call(?SYS, uptime).
|
||||
|
||||
%% @doc Get sys datetime
|
||||
-spec(datetime() -> string()).
|
||||
|
@ -87,9 +79,9 @@ info() ->
|
|||
{uptime, uptime()},
|
||||
{datetime, datetime()}].
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
State = #state{start_time = erlang:timestamp(),
|
||||
|
@ -106,11 +98,11 @@ handle_call(uptime, _From, State) ->
|
|||
{reply, uptime(State), State};
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[SYS] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[SYS] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[SYS] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[SYS] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({timeout, TRef, heartbeat}, State = #state{heartbeat = TRef}) ->
|
||||
|
@ -118,9 +110,7 @@ handle_info({timeout, TRef, heartbeat}, State = #state{heartbeat = TRef}) ->
|
|||
publish(datetime, iolist_to_binary(datetime())),
|
||||
{noreply, heartbeat(State)};
|
||||
|
||||
handle_info({timeout, TRef, tick}, State = #state{ticker = TRef,
|
||||
version = Version,
|
||||
sysdescr = Descr}) ->
|
||||
handle_info({timeout, TRef, tick}, State = #state{ticker = TRef, version = Version, sysdescr = Descr}) ->
|
||||
publish(version, Version),
|
||||
publish(sysdescr, Descr),
|
||||
publish(brokers, ekka_mnesia:running_nodes()),
|
||||
|
@ -129,19 +119,18 @@ handle_info({timeout, TRef, tick}, State = #state{ticker = TRef,
|
|||
{noreply, tick(State), hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[SYS] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[SYS] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{heartbeat = HBRef, ticker = TRef}) ->
|
||||
emqx_misc:cancel_timer(HBRef),
|
||||
emqx_misc:cancel_timer(TRef).
|
||||
terminate(_Reason, #state{heartbeat = TRef1, ticker = TRef2}) ->
|
||||
lists:foreach(fun emqx_misc:cancel_timer/1, [TRef1, TRef2]).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
uptime(#state{start_time = Ts}) ->
|
||||
Secs = timer:now_diff(erlang:timestamp(), Ts) div 1000000,
|
||||
|
@ -162,37 +151,26 @@ uptime(days, D) ->
|
|||
[integer_to_list(D), " days,"].
|
||||
|
||||
publish(uptime, Uptime) ->
|
||||
safe_publish(systop(uptime), [sys], Uptime);
|
||||
safe_publish(systop(uptime), Uptime);
|
||||
publish(datetime, Datetime) ->
|
||||
safe_publish(systop(datatype), [sys], Datetime);
|
||||
safe_publish(systop(datatype), Datetime);
|
||||
publish(version, Version) ->
|
||||
safe_publish(systop(version), [sys, retain], Version);
|
||||
safe_publish(systop(version), #{retain => true}, Version);
|
||||
publish(sysdescr, Descr) ->
|
||||
safe_publish(systop(sysdescr), [sys, retain], Descr);
|
||||
safe_publish(systop(sysdescr), #{retain => true}, Descr);
|
||||
publish(brokers, Nodes) ->
|
||||
Payload = string:join([atom_to_list(N) || N <- Nodes], ","),
|
||||
safe_publish(<<"$SYS/brokers">>, [sys, retain], Payload);
|
||||
safe_publish(<<"$SYS/brokers">>, #{retain => true}, Payload);
|
||||
publish(stats, Stats) ->
|
||||
[begin
|
||||
Topic = systop(lists:concat(['stats/', Stat])),
|
||||
safe_publish(Topic, [sys], integer_to_binary(Val))
|
||||
end || {Stat, Val} <- Stats, is_atom(Stat), is_integer(Val)];
|
||||
[safe_publish(systop(lists:concat(['stats/', Stat])), integer_to_binary(Val))
|
||||
|| {Stat, Val} <- Stats, is_atom(Stat), is_integer(Val)];
|
||||
publish(metrics, Metrics) ->
|
||||
[begin
|
||||
Topic = systop(lists:concat(['metrics/', Metric])),
|
||||
safe_publish(Topic, [sys], integer_to_binary(Val))
|
||||
end || {Metric, Val} <- Metrics, is_atom(Metric), is_integer(Val)].
|
||||
[safe_publish(systop(lists:concat(['metrics/', Metric])), integer_to_binary(Val))
|
||||
|| {Metric, Val} <- Metrics, is_atom(Metric), is_integer(Val)].
|
||||
|
||||
safe_publish(Topic, Payload) ->
|
||||
safe_publish(Topic, #{}, Payload).
|
||||
safe_publish(Topic, Flags, Payload) ->
|
||||
try do_publish(Topic, Flags, Payload)
|
||||
catch
|
||||
_:Error ->
|
||||
emqx_logger:error("[SYS] Publish error: ~p", [Error])
|
||||
end.
|
||||
|
||||
do_publish(Topic, Flags, Payload) ->
|
||||
Msg0 = emqx_message:make(?SYS, Topic, iolist_to_binary(Payload)),
|
||||
emqx_broker:publish(lists:foldl(fun(Flag, Msg) ->
|
||||
emqx_message:set_flag(Flag, Msg)
|
||||
end, Msg0, Flags)).
|
||||
Flags1 = maps:merge(#{sys => true, qos => 0}, Flags),
|
||||
emqx_broker:safe_publish(emqx_message:new(?SYS, Flags1, Topic, iolist_to_binary(Payload))).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sys_mon).
|
||||
|
||||
|
@ -20,30 +18,25 @@
|
|||
|
||||
-export([start_link/1]).
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {timer, events}).
|
||||
|
||||
-define(LOG(Msg, ProcInfo),
|
||||
emqx_logger:warning([{sysmon, true}],
|
||||
"[SYSMON] ~s~n~p", [WarnMsg, ProcInfo])).
|
||||
|
||||
-define(LOG(Msg, ProcInfo, PortInfo),
|
||||
emqx_logger:warning([{sysmon, true}],
|
||||
"[SYSMON] ~s~n~p~n~p", [WarnMsg, ProcInfo, PortInfo])).
|
||||
|
||||
-define(SYSMON, ?MODULE).
|
||||
-define(LOG(Msg, ProcInfo),
|
||||
emqx_logger:warning([{sysmon, true}], "[SYSMON] ~s~n~p", [WarnMsg, ProcInfo])).
|
||||
-define(LOG(Msg, ProcInfo, PortInfo),
|
||||
emqx_logger:warning([{sysmon, true}], "[SYSMON] ~s~n~p~n~p", [WarnMsg, ProcInfo, PortInfo])).
|
||||
|
||||
%% @doc Start system monitor
|
||||
-spec(start_link(Opts :: list(tuple()))
|
||||
-> {ok, pid()} | ignore | {error, term()}).
|
||||
-spec(start_link(Opts :: list(tuple())) -> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link(Opts) ->
|
||||
gen_server:start_link({local, ?SYSMON}, ?MODULE, [Opts], []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%-----------------------------------------------------------------------------
|
||||
|
||||
init([Opts]) ->
|
||||
erlang:system_monitor(self(), parse_opt(Opts)),
|
||||
|
@ -78,50 +71,56 @@ parse_opt([_Opt|Opts], Acc) ->
|
|||
parse_opt(Opts, Acc).
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[SYSMON] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[SYSMON] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[SYSMON] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[SYSMON] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({monitor, Pid, long_gc, Info}, State) ->
|
||||
suppress({long_gc, Pid}, fun() ->
|
||||
suppress({long_gc, Pid},
|
||||
fun() ->
|
||||
WarnMsg = io_lib:format("long_gc warning: pid = ~p, info: ~p", [Pid, Info]),
|
||||
?LOG(WarnMsg, procinfo(Pid)),
|
||||
safe_publish(long_gc, WarnMsg)
|
||||
end, State);
|
||||
|
||||
handle_info({monitor, Pid, long_schedule, Info}, State) when is_pid(Pid) ->
|
||||
suppress({long_schedule, Pid}, fun() ->
|
||||
suppress({long_schedule, Pid},
|
||||
fun() ->
|
||||
WarnMsg = io_lib:format("long_schedule warning: pid = ~p, info: ~p", [Pid, Info]),
|
||||
?LOG(WarnMsg, procinfo(Pid)),
|
||||
safe_publish(long_schedule, WarnMsg)
|
||||
end, State);
|
||||
|
||||
handle_info({monitor, Port, long_schedule, Info}, State) when is_port(Port) ->
|
||||
suppress({long_schedule, Port}, fun() ->
|
||||
suppress({long_schedule, Port},
|
||||
fun() ->
|
||||
WarnMsg = io_lib:format("long_schedule warning: port = ~p, info: ~p", [Port, Info]),
|
||||
?LOG(WarnMsg, erlang:port_info(Port)),
|
||||
safe_publish(long_schedule, WarnMsg)
|
||||
end, State);
|
||||
|
||||
handle_info({monitor, Pid, large_heap, Info}, State) ->
|
||||
suppress({large_heap, Pid}, fun() ->
|
||||
suppress({large_heap, Pid},
|
||||
fun() ->
|
||||
WarnMsg = io_lib:format("large_heap warning: pid = ~p, info: ~p", [Pid, Info]),
|
||||
?LOG(WarnMsg, procinfo(Pid)),
|
||||
safe_publish(large_heap, WarnMsg)
|
||||
end, State);
|
||||
|
||||
handle_info({monitor, SusPid, busy_port, Port}, State) ->
|
||||
suppress({busy_port, Port}, fun() ->
|
||||
suppress({busy_port, Port},
|
||||
fun() ->
|
||||
WarnMsg = io_lib:format("busy_port warning: suspid = ~p, port = ~p", [SusPid, Port]),
|
||||
?LOG(WarnMsg, procinfo(SusPid), erlang:port_info(Port)),
|
||||
safe_publish(busy_port, WarnMsg)
|
||||
end, State);
|
||||
|
||||
handle_info({monitor, SusPid, busy_dist_port, Port}, State) ->
|
||||
suppress({busy_dist_port, Port}, fun() ->
|
||||
suppress({busy_dist_port, Port},
|
||||
fun() ->
|
||||
WarnMsg = io_lib:format("busy_dist_port warning: suspid = ~p, port = ~p", [SusPid, Port]),
|
||||
?LOG(WarnMsg, procinfo(SusPid), erlang:port_info(Port)),
|
||||
safe_publish(busy_dist_port, WarnMsg)
|
||||
|
@ -131,7 +130,7 @@ handle_info(reset, State) ->
|
|||
{noreply, State#state{events = []}, hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
lager:error("[SYSMON] Unexpected Info: ~p", [Info]),
|
||||
lager:error("[SYSMON] unexpected Info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{timer = TRef}) ->
|
||||
|
@ -155,12 +154,9 @@ procinfo(Pid) ->
|
|||
end.
|
||||
|
||||
safe_publish(Event, WarnMsg) ->
|
||||
try
|
||||
Topic = emqx_topic:systop(lists:concat(['sysmon/', Event])),
|
||||
Msg = emqx_message:make(?SYSMON, Topic, iolist_to_binary(WarnMsg)),
|
||||
emqx_broker:publish(emqx_message:set_flag(sys, Msg))
|
||||
catch
|
||||
_:Error ->
|
||||
emqx_logger:error("[SYSMON] Publish error: ~p", [Error])
|
||||
end.
|
||||
emqx_broker:safe_publish(sysmon_msg(Topic, iolist_to_binary(WarnMsg))).
|
||||
|
||||
sysmon_msg(Topic, Payload) ->
|
||||
emqx_message:new(?SYSMON, #{sys => true, qos => 0}, Topic, Payload).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_sys_sup).
|
||||
|
||||
|
@ -26,11 +24,18 @@ start_link() ->
|
|||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
Sys = {sys, {emqx_sys, start_link, []},
|
||||
permanent, 5000, worker, [emqx_sys]},
|
||||
|
||||
{ok, Env} = emqx_config:get_env(sysmon),
|
||||
Sysmon = {sys_mon, {emqx_sys_mon, start_link, [Env]},
|
||||
permanent, 5000, worker, [emqx_sys_mon]},
|
||||
Sys = #{id => sys,
|
||||
start => {emqx_sys, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_sys]},
|
||||
Sysmon = #{id => sys_mon,
|
||||
start => {emqx_sys_mon, start_link,
|
||||
[emqx_config:get_env(sysmon, [])]},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [emqx_sys_mon]},
|
||||
{ok, {{one_for_one, 10, 100}, [Sys, Sysmon]}}.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_tables).
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_time).
|
||||
|
||||
|
|
|
@ -1,39 +1,31 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_topic).
|
||||
|
||||
-include("emqx.hrl").
|
||||
|
||||
-include("emqx_mqtt.hrl").
|
||||
|
||||
-import(lists, [reverse/1]).
|
||||
|
||||
-export([match/2, validate/1, triples/1, words/1, wildcard/1]).
|
||||
|
||||
-export([join/1, feed_var/3, systop/1]).
|
||||
|
||||
-export([parse/1, parse/2]).
|
||||
|
||||
-type(option() :: {qos, mqtt_qos()} | {share, '$queue' | binary()}).
|
||||
|
||||
-type(word() :: '' | '+' | '#' | binary()).
|
||||
|
||||
-type(words() :: list(word())).
|
||||
|
||||
-type(option() :: {qos, mqtt_qos()} | {share, '$queue' | binary()}).
|
||||
-type(triple() :: {root | binary(), word(), binary()}).
|
||||
|
||||
-export_type([option/0, word/0, triple/0]).
|
||||
|
@ -110,14 +102,13 @@ validate3(<<C/utf8, _Rest/binary>>) when C == $#; C == $+; C == 0 ->
|
|||
validate3(<<_/utf8, Rest/binary>>) ->
|
||||
validate3(Rest).
|
||||
|
||||
%% @doc Topic to Triples
|
||||
%% @doc Topic to triples
|
||||
-spec(triples(topic()) -> list(triple())).
|
||||
triples(Topic) when is_binary(Topic) ->
|
||||
triples(words(Topic), root, []).
|
||||
|
||||
triples([], _Parent, Acc) ->
|
||||
reverse(Acc);
|
||||
|
||||
triples([W|Words], Parent, Acc) ->
|
||||
Node = join(Parent, W),
|
||||
triples(Words, Node, [{Parent, W, Node}|Acc]).
|
||||
|
@ -176,24 +167,16 @@ join(Words) ->
|
|||
parse(Topic) when is_binary(Topic) ->
|
||||
parse(Topic, []).
|
||||
|
||||
parse(Topic = <<"$fastlane/", Topic1/binary>>, Options) ->
|
||||
case lists:member(fastlane, Options) of
|
||||
true -> error({invalid_topic, Topic});
|
||||
false -> parse(Topic1, [fastlane | Options])
|
||||
end;
|
||||
|
||||
parse(Topic = <<"$queue/", Topic1/binary>>, Options) ->
|
||||
case lists:keyfind(share, 1, Options) of
|
||||
{share, _} -> error({invalid_topic, Topic});
|
||||
false -> parse(Topic1, [{share, '$queue'} | Options])
|
||||
end;
|
||||
|
||||
parse(Topic = <<"$share/", Topic1/binary>>, Options) ->
|
||||
case lists:keyfind(share, 1, Options) of
|
||||
{share, _} -> error({invalid_topic, Topic});
|
||||
false -> [Group, Topic2] = binary:split(Topic1, <<"/">>),
|
||||
{Topic2, [{share, Group} | Options]}
|
||||
end;
|
||||
|
||||
parse(Topic, Options) -> {Topic, Options}.
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_tracer).
|
||||
|
||||
|
@ -21,32 +19,29 @@
|
|||
-include("emqx.hrl").
|
||||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([start_trace/2, lookup_traces/0, stop_trace/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-record(state, {level, traces}).
|
||||
|
||||
-type(trace_who() :: {client | topic, binary()}).
|
||||
|
||||
-define(TRACER, ?MODULE).
|
||||
-define(OPTIONS, [{formatter_config, [time, " [",severity,"] ", message, "\n"]}]).
|
||||
|
||||
-define(TRACER, ?MODULE).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Start the tracer
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
-spec(start_link() -> {ok, pid()} | ignore | {error, term()}).
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?TRACER}, ?MODULE, [], []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Start/Stop Trace
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Start/Stop trace
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% @doc Start to trace client or topic.
|
||||
-spec(start_trace(trace_who(), string()) -> ok | {error, term()}).
|
||||
|
@ -55,8 +50,7 @@ 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.
|
||||
-spec(stop_trace(trace_who()) -> ok | {error, term()}).
|
||||
|
@ -70,26 +64,24 @@ stop_trace({topic, Topic}) ->
|
|||
lookup_traces() ->
|
||||
gen_server:call(?TRACER, lookup_traces).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([]) ->
|
||||
Level = emqx_config:get_env(trace_level, debug),
|
||||
{ok, #state{level = Level, traces = #{}}}.
|
||||
{ok, #state{level = emqx_config:get_env(trace_level, debug), traces = #{}}}.
|
||||
|
||||
handle_call({start_trace, Who, LogFile}, _From,
|
||||
State = #state{level = Level, traces = Traces}) ->
|
||||
handle_call({start_trace, Who, LogFile}, _From, State = #state{level = Level, traces = Traces}) ->
|
||||
case catch lager:trace_file(LogFile, [Who], Level, ?OPTIONS) of
|
||||
{ok, exists} ->
|
||||
{reply, {error, alread_existed}, State};
|
||||
{reply, {error, already_existed}, State};
|
||||
{ok, Trace} ->
|
||||
{reply, ok, State#state{traces = maps:put(Who, {Trace, LogFile}, Traces)}};
|
||||
{error, Reason} ->
|
||||
emqx_logger:error("[TRACER] trace error: ~p", [Reason]),
|
||||
emqx_logger:error("[Tracer] trace error: ~p", [Reason]),
|
||||
{reply, {error, Reason}, State};
|
||||
{'EXIT', Error} ->
|
||||
emqx_logger:error("[TRACER] trace exit: ~p", [Error]),
|
||||
emqx_logger:error("[Tracer] trace exit: ~p", [Error]),
|
||||
{reply, {error, Error}, State}
|
||||
end;
|
||||
|
||||
|
@ -98,27 +90,27 @@ handle_call({stop_trace, Who}, _From, State = #state{traces = Traces}) ->
|
|||
{ok, {Trace, _LogFile}} ->
|
||||
case lager:stop_trace(Trace) of
|
||||
ok -> ok;
|
||||
{error, Error} -> lager:error("Stop trace ~p error: ~p", [Who, Error])
|
||||
{error, Error} ->
|
||||
emqx_logger:error("[Tracer] stop trace ~p error: ~p", [Who, Error])
|
||||
end,
|
||||
{reply, ok, State#state{traces = maps:remove(Who, Traces)}};
|
||||
error ->
|
||||
{reply, {error, trance_not_found}, State}
|
||||
{reply, {error, not_found}, State}
|
||||
end;
|
||||
|
||||
handle_call(lookup_traces, _From, State = #state{traces = Traces}) ->
|
||||
{reply, [{Who, LogFile} || {Who, {_Trace, LogFile}}
|
||||
<- maps:to_list(Traces)], State};
|
||||
{reply, [{Who, LogFile} || {Who, {_Trace, LogFile}} <- maps:to_list(Traces)], State};
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
emqx_logger:error("[TRACER] Unexpected request: ~p", [Req]),
|
||||
{reply, ignore, State}.
|
||||
emqx_logger:error("[Tracer] unexpected call: ~p", [Req]),
|
||||
{reply, ignored, State}.
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
emqx_logger:error("[TRACER] Unexpected msg: ~p", [Msg]),
|
||||
emqx_logger:error("[Tracer] unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(Info, State) ->
|
||||
emqx_logger:error("[TRACER] Unexpected info: ~p", [Info]),
|
||||
emqx_logger:error("[Tracer] unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
%%%===================================================================
|
||||
%%% Copyright (c) 2013-2018 EMQ Inc. All rights reserved.
|
||||
%%%
|
||||
%%% 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.
|
||||
%%%===================================================================
|
||||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_trie).
|
||||
|
||||
|
@ -31,9 +29,9 @@
|
|||
-define(TRIE, emqx_trie).
|
||||
-define(TRIE_NODE, emqx_trie_node).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Mnesia bootstrap
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% @doc Create or replicate trie tables.
|
||||
-spec(mnesia(boot | copy) -> ok).
|
||||
|
@ -55,9 +53,9 @@ mnesia(copy) ->
|
|||
%% Copy trie_node table
|
||||
ok = ekka_mnesia:copy_table(?TRIE_NODE).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Trie APIs
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% @doc Insert a topic into the trie
|
||||
-spec(insert(Topic :: topic()) -> ok).
|
||||
|
@ -94,13 +92,12 @@ delete(Topic) when is_binary(Topic) ->
|
|||
delete_path(lists:reverse(emqx_topic:triples(Topic)));
|
||||
[TrieNode] ->
|
||||
write_trie_node(TrieNode#trie_node{topic = undefined});
|
||||
[] ->
|
||||
ok
|
||||
[] -> ok
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% @private
|
||||
%% @doc Add a path to the trie.
|
||||
|
@ -112,8 +109,7 @@ add_path({Node, Word, Child}) ->
|
|||
[] ->
|
||||
write_trie_node(TrieNode#trie_node{edge_count = Count + 1}),
|
||||
write_trie(#trie{edge = Edge, node_id = Child});
|
||||
[_] ->
|
||||
ok
|
||||
[_] -> ok
|
||||
end;
|
||||
[] ->
|
||||
write_trie_node(#trie_node{node_id = Node, edge_count = 1}),
|
||||
|
@ -145,8 +141,7 @@ match_node(NodeId, [W|Words], ResAcc) ->
|
|||
case mnesia:read(?TRIE, #trie_edge{node_id = NodeId, word = '#'}) of
|
||||
[#trie{node_id = ChildId}] ->
|
||||
mnesia:read(?TRIE_NODE, ChildId) ++ ResAcc;
|
||||
[] ->
|
||||
ResAcc
|
||||
[] -> ResAcc
|
||||
end.
|
||||
|
||||
%% @private
|
||||
|
|
Loading…
Reference in New Issue