do_subscribe_/4, do_unsubscribe_/3
This commit is contained in:
parent
6e64686f77
commit
0a967df15a
|
@ -162,18 +162,14 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
add_subscriber_(Topic, Subscriber) ->
|
add_subscriber_(Topic, Subscriber) ->
|
||||||
case ets:member(mqtt_subscriber, Topic) of
|
(not ets:member(mqtt_subscriber, Topic))
|
||||||
false -> emqttd_router:add_route(Topic, node());
|
andalso emqttd_router:add_route(Topic),
|
||||||
true -> ok
|
|
||||||
end,
|
|
||||||
ets:insert(mqtt_subscriber, {Topic, Subscriber}).
|
ets:insert(mqtt_subscriber, {Topic, Subscriber}).
|
||||||
|
|
||||||
del_subscriber_(Topic, Subscriber) ->
|
del_subscriber_(Topic, Subscriber) ->
|
||||||
ets:delete_object(mqtt_subscriber, {Topic, Subscriber}),
|
ets:delete_object(mqtt_subscriber, {Topic, Subscriber}),
|
||||||
case ets:member(mqtt_subscriber, Topic) of
|
(not ets:member(mqtt_subscriber, Topic))
|
||||||
false -> emqttd_router:del_route(Topic, node());
|
andalso emqttd_router:del_route(Topic).
|
||||||
true -> ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
setstats(State) ->
|
setstats(State) ->
|
||||||
emqttd_stats:setstats('subscribers/count', 'subscribers/max',
|
emqttd_stats:setstats('subscribers/count', 'subscribers/max',
|
||||||
|
|
|
@ -172,13 +172,13 @@ init([Pool, Id, Env]) ->
|
||||||
{ok, #state{pool = Pool, id = Id, env = Env, submon = emqttd_pmon:new()}}.
|
{ok, #state{pool = Pool, id = Id, env = Env, submon = emqttd_pmon:new()}}.
|
||||||
|
|
||||||
handle_call({subscribe, Topic, Subscriber, Options}, _From, State) ->
|
handle_call({subscribe, Topic, Subscriber, Options}, _From, State) ->
|
||||||
case subscribe_(Topic, Subscriber, Options, State) of
|
case do_subscribe_(Topic, Subscriber, Options, State) of
|
||||||
{ok, NewState} -> {reply, ok, setstats(NewState)};
|
{ok, NewState} -> {reply, ok, setstats(NewState)};
|
||||||
{error, Error} -> {reply, {error, Error}, State}
|
{error, Error} -> {reply, {error, Error}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call({unsubscribe, Topic, Subscriber}, _From, State) ->
|
handle_call({unsubscribe, Topic, Subscriber}, _From, State) ->
|
||||||
case unsubscribe_(Topic, Subscriber, State) of
|
case do_unsubscribe_(Topic, Subscriber, State) of
|
||||||
{ok, NewState} -> {reply, ok, setstats(NewState), hibernate};
|
{ok, NewState} -> {reply, ok, setstats(NewState), hibernate};
|
||||||
{error, Error} -> {reply, {error, Error}, State}
|
{error, Error} -> {reply, {error, Error}, State}
|
||||||
end;
|
end;
|
||||||
|
@ -198,13 +198,13 @@ handle_call(Req, _From, State) ->
|
||||||
?UNEXPECTED_REQ(Req, State).
|
?UNEXPECTED_REQ(Req, State).
|
||||||
|
|
||||||
handle_cast({subscribe, Topic, Subscriber, Options}, State) ->
|
handle_cast({subscribe, Topic, Subscriber, Options}, State) ->
|
||||||
case subscribe_(Topic, Subscriber, Options, State) of
|
case do_subscribe_(Topic, Subscriber, Options, State) of
|
||||||
{ok, NewState} -> {noreply, setstats(NewState)};
|
{ok, NewState} -> {noreply, setstats(NewState)};
|
||||||
{error, _Error} -> {noreply, State}
|
{error, _Error} -> {noreply, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_cast({unsubscribe, Topic, Subscriber}, State) ->
|
handle_cast({unsubscribe, Topic, Subscriber}, State) ->
|
||||||
case unsubscribe_(Topic, Subscriber, State) of
|
case do_unsubscribe_(Topic, Subscriber, State) of
|
||||||
{ok, NewState} -> {noreply, setstats(NewState), hibernate};
|
{ok, NewState} -> {noreply, setstats(NewState), hibernate};
|
||||||
{error, _Error} -> {noreply, State}
|
{error, _Error} -> {noreply, State}
|
||||||
end;
|
end;
|
||||||
|
@ -233,7 +233,7 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
%% Internal Functions
|
%% Internal Functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
subscribe_(Topic, Subscriber, Options, State) ->
|
do_subscribe_(Topic, Subscriber, Options, State) ->
|
||||||
case ets:lookup(mqtt_subproperty, {Topic, Subscriber}) of
|
case ets:lookup(mqtt_subproperty, {Topic, Subscriber}) of
|
||||||
[] ->
|
[] ->
|
||||||
emqttd_pubsub:async_subscribe(Topic, Subscriber),
|
emqttd_pubsub:async_subscribe(Topic, Subscriber),
|
||||||
|
@ -244,7 +244,12 @@ subscribe_(Topic, Subscriber, Options, State) ->
|
||||||
{error, {already_subscribed, Topic}}
|
{error, {already_subscribed, Topic}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
unsubscribe_(Topic, Subscriber, State) ->
|
monitor_subpid(SubPid, State = #state{submon = PMon}) when is_pid(SubPid) ->
|
||||||
|
State#state{submon = PMon:monitor(SubPid)};
|
||||||
|
monitor_subpid(_SubPid, State) ->
|
||||||
|
State.
|
||||||
|
|
||||||
|
do_unsubscribe_(Topic, Subscriber, State) ->
|
||||||
case ets:lookup(mqtt_subproperty, {Topic, Subscriber}) of
|
case ets:lookup(mqtt_subproperty, {Topic, Subscriber}) of
|
||||||
[_] ->
|
[_] ->
|
||||||
emqttd_pubsub:async_unsubscribe(Topic, Subscriber),
|
emqttd_pubsub:async_unsubscribe(Topic, Subscriber),
|
||||||
|
@ -258,11 +263,6 @@ unsubscribe_(Topic, Subscriber, State) ->
|
||||||
{error, {subscription_not_found, Topic}}
|
{error, {subscription_not_found, Topic}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
monitor_subpid(SubPid, State = #state{submon = PMon}) when is_pid(SubPid) ->
|
|
||||||
State#state{submon = PMon:monitor(SubPid)};
|
|
||||||
monitor_subpid(_SubPid, State) ->
|
|
||||||
State.
|
|
||||||
|
|
||||||
demonitor_subpid(SubPid, State = #state{submon = PMon}) when is_pid(SubPid) ->
|
demonitor_subpid(SubPid, State = #state{submon = PMon}) when is_pid(SubPid) ->
|
||||||
State#state{submon = PMon:demonitor(SubPid)};
|
State#state{submon = PMon:demonitor(SubPid)};
|
||||||
demonitor_subpid(_SubPid, State) ->
|
demonitor_subpid(_SubPid, State) ->
|
||||||
|
|
|
@ -284,14 +284,18 @@ handle_call({publish, Msg = #mqtt_message{qos = ?QOS_2, pktid = PktId}},
|
||||||
handle_call(Req, _From, State) ->
|
handle_call(Req, _From, State) ->
|
||||||
?UNEXPECTED_REQ(Req, State).
|
?UNEXPECTED_REQ(Req, State).
|
||||||
|
|
||||||
handle_cast({subscribe, TopicTable0, AckFun}, Session = #session{client_id = ClientId,
|
handle_cast({subscribe, RawTopicTable, AckFun}, Session = #session{client_id = ClientId,
|
||||||
subscriptions = Subscriptions}) ->
|
subscriptions = Subscriptions}) ->
|
||||||
|
%% TODO: Ugly...
|
||||||
|
TopicTable0 = lists:map(fun({T, Q}) ->
|
||||||
|
{T1, Opts} = emqttd_topic:strip(T),
|
||||||
|
{T1, [{qos, Q} | Opts]}
|
||||||
|
end, RawTopicTable),
|
||||||
case emqttd:run_hooks('client.subscribe', [ClientId], TopicTable0) of
|
case emqttd:run_hooks('client.subscribe', [ClientId], TopicTable0) of
|
||||||
{ok, TopicTable} ->
|
{ok, TopicTable} ->
|
||||||
?LOG(info, "Subscribe ~p", [TopicTable], Session),
|
?LOG(info, "Subscribe ~p", [TopicTable], Session),
|
||||||
Subscriptions1 = lists:foldl(
|
Subscriptions1 = lists:foldl(
|
||||||
fun({Topic, Qos}, SubDict) ->
|
fun({Topic, Opts = [{qos, Qos}|_]}, SubDict) ->
|
||||||
case dict:find(Topic, SubDict) of
|
case dict:find(Topic, SubDict) of
|
||||||
{ok, Qos} ->
|
{ok, Qos} ->
|
||||||
?LOG(warning, "duplicated subscribe: ~s, qos = ~w", [Topic, Qos], Session),
|
?LOG(warning, "duplicated subscribe: ~s, qos = ~w", [Topic, Qos], Session),
|
||||||
|
@ -301,7 +305,7 @@ handle_cast({subscribe, TopicTable0, AckFun}, Session = #session{client_id =
|
||||||
?LOG(warning, "duplicated subscribe ~s, old_qos=~w, new_qos=~w", [Topic, OldQos, Qos], Session),
|
?LOG(warning, "duplicated subscribe ~s, old_qos=~w, new_qos=~w", [Topic, OldQos, Qos], Session),
|
||||||
dict:store(Topic, Qos, SubDict);
|
dict:store(Topic, Qos, SubDict);
|
||||||
error ->
|
error ->
|
||||||
emqttd:subscribe(Topic, ClientId, [{qos, Qos}]),
|
emqttd:subscribe(Topic, ClientId, Opts),
|
||||||
%%TODO: the design is ugly...
|
%%TODO: the design is ugly...
|
||||||
%% <MQTT V3.1.1>: 3.8.4
|
%% <MQTT V3.1.1>: 3.8.4
|
||||||
%% Where the Topic Filter is not identical to any existing Subscription’s filter,
|
%% Where the Topic Filter is not identical to any existing Subscription’s filter,
|
||||||
|
@ -319,9 +323,11 @@ handle_cast({subscribe, TopicTable0, AckFun}, Session = #session{client_id =
|
||||||
hibernate(Session)
|
hibernate(Session)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_cast({unsubscribe, Topics0}, Session = #session{client_id = ClientId,
|
handle_cast({unsubscribe, RawTopics}, Session = #session{client_id = ClientId,
|
||||||
subscriptions = Subscriptions}) ->
|
subscriptions = Subscriptions}) ->
|
||||||
|
Topics0 = lists:map(fun(Topic) ->
|
||||||
|
{T, _Opts} = emqttd_topic:strip(Topic), T
|
||||||
|
end, RawTopics),
|
||||||
case emqttd:run_hooks('client.unsubscribe', [ClientId], Topics0) of
|
case emqttd:run_hooks('client.unsubscribe', [ClientId], Topics0) of
|
||||||
{ok, Topics} ->
|
{ok, Topics} ->
|
||||||
?LOG(info, "unsubscribe ~p", [Topics], Session),
|
?LOG(info, "unsubscribe ~p", [Topics], Session),
|
||||||
|
@ -329,7 +335,7 @@ handle_cast({unsubscribe, Topics0}, Session = #session{client_id = ClientId,
|
||||||
fun(Topic, SubDict) ->
|
fun(Topic, SubDict) ->
|
||||||
case dict:find(Topic, SubDict) of
|
case dict:find(Topic, SubDict) of
|
||||||
{ok, _Qos} ->
|
{ok, _Qos} ->
|
||||||
emqttd:unsubscribe(ClientId, Topic),
|
emqttd:unsubscribe(Topic, ClientId),
|
||||||
dict:erase(Topic, SubDict);
|
dict:erase(Topic, SubDict);
|
||||||
error ->
|
error ->
|
||||||
SubDict
|
SubDict
|
||||||
|
|
Loading…
Reference in New Issue