Improve the channel modules and fix the extension mods
This commit is contained in:
parent
32795321f5
commit
f8e28e39ed
|
@ -290,6 +290,13 @@ connected(info, Deliver = {deliver, _Topic, _Msg},
|
||||||
shutdown(Reason, State#state{proto_state = NProtoState})
|
shutdown(Reason, State#state{proto_state = NProtoState})
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
%% TODO: Improve later.
|
||||||
|
connected(info, {subscribe, TopicFilters}, State) ->
|
||||||
|
handle_request({subscribe, TopicFilters}, State);
|
||||||
|
|
||||||
|
connected(info, {unsubscribe, TopicFilters}, State) ->
|
||||||
|
handle_request({unsubscribe, TopicFilters}, State);
|
||||||
|
|
||||||
%% Keepalive timer
|
%% Keepalive timer
|
||||||
connected(info, {keepalive, check}, State = #state{keepalive = KeepAlive}) ->
|
connected(info, {keepalive, check}, State = #state{keepalive = KeepAlive}) ->
|
||||||
case emqx_keepalive:check(KeepAlive) of
|
case emqx_keepalive:check(KeepAlive) of
|
||||||
|
@ -451,6 +458,17 @@ terminate(Reason, _StateName, #state{transport = Transport,
|
||||||
ok = emqx_keepalive:cancel(KeepAlive),
|
ok = emqx_keepalive:cancel(KeepAlive),
|
||||||
emqx_protocol:terminate(Reason, ProtoState).
|
emqx_protocol:terminate(Reason, ProtoState).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Handle internal request
|
||||||
|
|
||||||
|
handle_request(Req, State = #state{proto_state = ProtoState}) ->
|
||||||
|
case emqx_protocol:handle_req(Req, ProtoState) of
|
||||||
|
{ok, _Result, NProtoState} -> %% TODO:: how to handle the result?
|
||||||
|
keep_state(State#state{proto_state = NProtoState});
|
||||||
|
{error, Reason, NProtoState} ->
|
||||||
|
shutdown(Reason, State#state{proto_state = NProtoState})
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Process incoming data
|
%% Process incoming data
|
||||||
|
|
||||||
|
|
|
@ -33,25 +33,34 @@
|
||||||
, unload/1
|
, unload/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(ATTR_KEYS, [clean_start, proto_ver, proto_name, keepalive]).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
load(Env) ->
|
load(Env) ->
|
||||||
emqx_hooks:add('client.connected', fun ?MODULE:on_client_connected/4, [Env]),
|
emqx_hooks:add('client.connected', {?MODULE, on_client_connected, [Env]}),
|
||||||
emqx_hooks:add('client.disconnected', fun ?MODULE:on_client_disconnected/3, [Env]).
|
emqx_hooks:add('client.disconnected', {?MODULE, on_client_disconnected, [Env]}).
|
||||||
|
|
||||||
on_client_connected(#{client_id := ClientId,
|
on_client_connected(#{client_id := ClientId,
|
||||||
username := Username,
|
username := Username,
|
||||||
peername := {IpAddr, _}}, ConnAck, ConnAttrs, Env) ->
|
peername := {IpAddr, _}
|
||||||
Attrs = #{},%maps:filter(fun(K, _) ->
|
}, ConnAck,
|
||||||
% lists:member(K, ?ATTR_KEYS)
|
#{session := #{clean_start := CleanStart,
|
||||||
% end, ConnAttrs),
|
expiry_interval := Interval
|
||||||
case emqx_json:safe_encode(Attrs#{clientid => ClientId,
|
},
|
||||||
|
proto_name := ProtoName,
|
||||||
|
proto_ver := ProtoVer,
|
||||||
|
keepalive := Keepalive
|
||||||
|
}, Env) ->
|
||||||
|
|
||||||
|
case emqx_json:safe_encode(#{clientid => ClientId,
|
||||||
username => Username,
|
username => Username,
|
||||||
ipaddress => iolist_to_binary(esockd_net:ntoa(IpAddr)),
|
ipaddress => iolist_to_binary(esockd_net:ntoa(IpAddr)),
|
||||||
|
proto_name => ProtoName,
|
||||||
|
proto_ver => ProtoVer,
|
||||||
|
keepalive => Keepalive,
|
||||||
|
clean_start => CleanStart,
|
||||||
|
expiry_interval => Interval,
|
||||||
connack => ConnAck,
|
connack => ConnAck,
|
||||||
ts => erlang:system_time(millisecond)
|
ts => erlang:system_time(millisecond)
|
||||||
}) of
|
}) of
|
||||||
|
@ -61,11 +70,13 @@ on_client_connected(#{client_id := ClientId,
|
||||||
?LOG(error, "Encoding connected event error: ~p", [Reason])
|
?LOG(error, "Encoding connected event error: ~p", [Reason])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_client_disconnected(#{client_id := ClientId, username := Username}, Reason, Env) ->
|
on_client_disconnected(#{client_id := ClientId,
|
||||||
case emqx_json:safe_encode([{clientid, ClientId},
|
username := Username}, Reason, Env) ->
|
||||||
{username, Username},
|
case emqx_json:safe_encode(#{clientid => ClientId,
|
||||||
{reason, reason(Reason)},
|
username => Username,
|
||||||
{ts, erlang:system_time(millisecond)}]) of
|
reason => reason(Reason),
|
||||||
|
ts => erlang:system_time(millisecond)
|
||||||
|
}) of
|
||||||
{ok, Payload} ->
|
{ok, Payload} ->
|
||||||
emqx_broker:publish(message(qos(Env), topic(disconnected, ClientId), Payload));
|
emqx_broker:publish(message(qos(Env), topic(disconnected, ClientId), Payload));
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -73,8 +84,8 @@ on_client_disconnected(#{client_id := ClientId, username := Username}, Reason, E
|
||||||
end.
|
end.
|
||||||
|
|
||||||
unload(_Env) ->
|
unload(_Env) ->
|
||||||
emqx_hooks:del('client.connected', fun ?MODULE:on_client_connected/4),
|
emqx_hooks:del('client.connected', {?MODULE, on_client_connected}),
|
||||||
emqx_hooks:del('client.disconnected', fun ?MODULE:on_client_disconnected/3).
|
emqx_hooks:del('client.disconnected', {?MODULE, on_client_disconnected}).
|
||||||
|
|
||||||
message(QoS, Topic, Payload) ->
|
message(QoS, Topic, Payload) ->
|
||||||
emqx_message:set_flag(
|
emqx_message:set_flag(
|
||||||
|
@ -91,3 +102,4 @@ qos(Env) -> proplists:get_value(qos, Env, 0).
|
||||||
reason(Reason) when is_atom(Reason) -> Reason;
|
reason(Reason) when is_atom(Reason) -> Reason;
|
||||||
reason({Error, _}) when is_atom(Error) -> Error;
|
reason({Error, _}) when is_atom(Error) -> Error;
|
||||||
reason(_) -> internal_error.
|
reason(_) -> internal_error.
|
||||||
|
|
||||||
|
|
|
@ -22,28 +22,32 @@
|
||||||
-include_lib("emqx_mqtt.hrl").
|
-include_lib("emqx_mqtt.hrl").
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([on_session_created/3]).
|
-export([on_client_connected/4]).
|
||||||
|
|
||||||
%% emqx_gen_mod callbacks
|
%% emqx_gen_mod callbacks
|
||||||
-export([ load/1
|
-export([ load/1
|
||||||
, unload/1
|
, unload/1
|
||||||
]).
|
]).
|
||||||
%%------------------------------------------------------------------------------
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
%% Load/Unload Hook
|
%% Load/Unload Hook
|
||||||
%%------------------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
load(Topics) ->
|
load(Topics) ->
|
||||||
emqx_hooks:add('session.created', fun ?MODULE:on_session_created/3, [Topics]).
|
emqx_hooks:add('client.connected', {?MODULE, on_client_connected, [Topics]}).
|
||||||
|
|
||||||
on_session_created(#{client_id := ClientId}, SessAttrs, Topics) ->
|
on_client_connected(#{client_id := ClientId,
|
||||||
Username = proplists:get_value(username, SessAttrs),
|
username := Username,
|
||||||
|
conn_mod := ConnMod
|
||||||
|
}, ?RC_SUCCESS, _ConnAttrs, Topics) ->
|
||||||
Replace = fun(Topic) ->
|
Replace = fun(Topic) ->
|
||||||
rep(<<"%u">>, Username, rep(<<"%c">>, ClientId, Topic))
|
rep(<<"%u">>, Username, rep(<<"%c">>, ClientId, Topic))
|
||||||
end,
|
end,
|
||||||
emqx_session:subscribe(self(), [{Replace(Topic), #{qos => QoS}} || {Topic, QoS} <- Topics]).
|
TopicFilters = [{Replace(Topic), #{qos => QoS}} || {Topic, QoS} <- Topics],
|
||||||
|
self() ! {subscribe, TopicFilters}.
|
||||||
|
|
||||||
unload(_) ->
|
unload(_) ->
|
||||||
emqx_hooks:del('session.created', fun ?MODULE:on_session_created/3).
|
emqx_hooks:del('client.connected', {?MODULE, on_client_connected}).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
-export([ init/2
|
-export([ init/2
|
||||||
, handle_in/2
|
, handle_in/2
|
||||||
|
, handle_req/2
|
||||||
, handle_deliver/2
|
, handle_deliver/2
|
||||||
, handle_out/2
|
, handle_out/2
|
||||||
, handle_timeout/3
|
, handle_timeout/3
|
||||||
|
@ -264,6 +265,31 @@ handle_in(Packet, PState) ->
|
||||||
io:format("In: ~p~n", [Packet]),
|
io:format("In: ~p~n", [Packet]),
|
||||||
{ok, PState}.
|
{ok, PState}.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Handle internal request
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-spec(handle_req(Req:: term(), proto_state())
|
||||||
|
-> {ok, Result :: term(), proto_state()} |
|
||||||
|
{error, Reason :: term(), proto_state()}).
|
||||||
|
handle_req({subscribe, TopicFilters}, PState = #protocol{client = Client}) ->
|
||||||
|
TopicFilters1 = emqx_hooks:run_fold('client.subscribe',
|
||||||
|
[Client, #{'Internal' => true}],
|
||||||
|
parse(subscribe, TopicFilters)),
|
||||||
|
{ReasonCodes, NPState} = process_subscribe(TopicFilters1, PState),
|
||||||
|
{ok, ReasonCodes, NPState};
|
||||||
|
|
||||||
|
handle_req({unsubscribe, TopicFilters}, PState = #protocol{client = Client}) ->
|
||||||
|
TopicFilters1 = emqx_hooks:run_fold('client.unsubscribe',
|
||||||
|
[Client, #{'Internal' => true}],
|
||||||
|
parse(unsubscribe, TopicFilters)),
|
||||||
|
{ReasonCodes, NPState} = process_unsubscribe(TopicFilters1, PState),
|
||||||
|
{ok, ReasonCodes, NPState};
|
||||||
|
|
||||||
|
handle_req(Req, PState) ->
|
||||||
|
?LOG(error, "Unexpected request: ~p~n", [Req]),
|
||||||
|
{ok, ignored, PState}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Handle delivers
|
%% Handle delivers
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -334,7 +360,7 @@ handle_out({connack, ReasonCode}, PState = #protocol{client = Client,
|
||||||
Reason = emqx_reason_codes:name(ReasonCode1, ProtoVer),
|
Reason = emqx_reason_codes:name(ReasonCode1, ProtoVer),
|
||||||
{error, Reason, ?CONNACK_PACKET(ReasonCode1), PState};
|
{error, Reason, ?CONNACK_PACKET(ReasonCode1), PState};
|
||||||
|
|
||||||
handle_out({publish, Publishes}, PState = #protocol{client = Client}) ->
|
handle_out({publish, Publishes}, PState) ->
|
||||||
Packets = [element(2, handle_out(Publish, PState)) || Publish <- Publishes],
|
Packets = [element(2, handle_out(Publish, PState)) || Publish <- Publishes],
|
||||||
{ok, Packets, PState};
|
{ok, Packets, PState};
|
||||||
|
|
||||||
|
@ -808,6 +834,26 @@ do_unsubscribe(TopicFilter, _SubOpts, PState = #protocol{client = Client,
|
||||||
is_acl_enabled(#{zone := Zone, is_superuser := IsSuperuser}) ->
|
is_acl_enabled(#{zone := Zone, is_superuser := IsSuperuser}) ->
|
||||||
(not IsSuperuser) andalso emqx_zone:get_env(Zone, enable_acl, true).
|
(not IsSuperuser) andalso emqx_zone:get_env(Zone, enable_acl, true).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Parse topic filters
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
parse(subscribe, TopicFilters) ->
|
||||||
|
[emqx_topic:parse(TopicFilter, SubOpts) || {TopicFilter, SubOpts} <- TopicFilters];
|
||||||
|
|
||||||
|
parse(unsubscribe, TopicFilters) ->
|
||||||
|
lists:map(fun emqx_topic:parse/1, TopicFilters).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Mount/Unmount
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
mount(#{mountpoint := MountPoint}, TopicOrMsg) ->
|
||||||
|
emqx_mountpoint:mount(MountPoint, TopicOrMsg).
|
||||||
|
|
||||||
|
unmount(#{mountpoint := MountPoint}, TopicOrMsg) ->
|
||||||
|
emqx_mountpoint:unmount(MountPoint, TopicOrMsg).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Pipeline
|
%% Pipeline
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -828,16 +874,6 @@ pipeline([Fun|More], Packet, PState) ->
|
||||||
{error, ReasonCode, NPState}
|
{error, ReasonCode, NPState}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Mount/Unmount
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
mount(#{mountpoint := MountPoint}, TopicOrMsg) ->
|
|
||||||
emqx_mountpoint:mount(MountPoint, TopicOrMsg).
|
|
||||||
|
|
||||||
unmount(#{mountpoint := MountPoint}, TopicOrMsg) ->
|
|
||||||
emqx_mountpoint:unmount(MountPoint, TopicOrMsg).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Helper functions
|
%% Helper functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -322,6 +322,12 @@ websocket_info({timeout, Timer, Msg},
|
||||||
stop(Reason, State#state{proto_state = NProtoState})
|
stop(Reason, State#state{proto_state = NProtoState})
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
websocket_info({subscribe, TopicFilters}, State) ->
|
||||||
|
handle_request({subscribe, TopicFilters}, State);
|
||||||
|
|
||||||
|
websocket_info({unsubscribe, TopicFilters}, State) ->
|
||||||
|
handle_request({unsubscribe, TopicFilters}, State);
|
||||||
|
|
||||||
websocket_info({shutdown, discard, {ClientId, ByPid}}, State) ->
|
websocket_info({shutdown, discard, {ClientId, ByPid}}, State) ->
|
||||||
?LOG(warning, "Discarded by ~s:~p", [ClientId, ByPid]),
|
?LOG(warning, "Discarded by ~s:~p", [ClientId, ByPid]),
|
||||||
stop(discard, State);
|
stop(discard, State);
|
||||||
|
@ -381,6 +387,17 @@ ensure_keepalive(Interval, #state{proto_state = ProtoState}) ->
|
||||||
keepalive_backoff, 0.75),
|
keepalive_backoff, 0.75),
|
||||||
emqx_keepalive:start(stat_fun(), round(Interval * Backoff), {keepalive, check}).
|
emqx_keepalive:start(stat_fun(), round(Interval * Backoff), {keepalive, check}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Handle internal request
|
||||||
|
|
||||||
|
handle_request(Req, State = #state{proto_state = ProtoState}) ->
|
||||||
|
case emqx_protocol:handle_req(Req, ProtoState) of
|
||||||
|
{ok, _Result, NProtoState} -> %% TODO:: how to handle the result?
|
||||||
|
{ok, State#state{proto_state = NProtoState}};
|
||||||
|
{error, Reason, NProtoState} ->
|
||||||
|
stop(Reason, State#state{proto_state = NProtoState})
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Process incoming data
|
%% Process incoming data
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue