Merge pull request #9893 from lafirest/feat/filiter_banned
feat(banned): filter out banned messages from mqueue
This commit is contained in:
commit
e8cf604ad4
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
-include("emqx.hrl").
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("types.hrl").
|
-include("types.hrl").
|
||||||
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
||||||
|
@ -297,9 +298,9 @@ open_session(false, ClientInfo = #{clientid := ClientId}, ConnInfo) ->
|
||||||
register_channel(ClientId, Self, ConnInfo),
|
register_channel(ClientId, Self, ConnInfo),
|
||||||
|
|
||||||
{ok, #{
|
{ok, #{
|
||||||
session => Session1,
|
session => clean_session(Session1),
|
||||||
present => true,
|
present => true,
|
||||||
pendings => Pendings
|
pendings => clean_pendings(Pendings)
|
||||||
}};
|
}};
|
||||||
{living, ConnMod, ChanPid, Session} ->
|
{living, ConnMod, ChanPid, Session} ->
|
||||||
ok = emqx_session:resume(ClientInfo, Session),
|
ok = emqx_session:resume(ClientInfo, Session),
|
||||||
|
@ -316,9 +317,9 @@ open_session(false, ClientInfo = #{clientid := ClientId}, ConnInfo) ->
|
||||||
),
|
),
|
||||||
register_channel(ClientId, Self, ConnInfo),
|
register_channel(ClientId, Self, ConnInfo),
|
||||||
{ok, #{
|
{ok, #{
|
||||||
session => Session1,
|
session => clean_session(Session1),
|
||||||
present => true,
|
present => true,
|
||||||
pendings => Pendings
|
pendings => clean_pendings(Pendings)
|
||||||
}};
|
}};
|
||||||
{error, _} ->
|
{error, _} ->
|
||||||
CreateSess()
|
CreateSess()
|
||||||
|
@ -732,3 +733,14 @@ get_connected_client_count() ->
|
||||||
undefined -> 0;
|
undefined -> 0;
|
||||||
Size -> Size
|
Size -> Size
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
clean_session(Session) ->
|
||||||
|
emqx_session:filter_queue(fun is_banned_msg/1, Session).
|
||||||
|
|
||||||
|
clean_pendings(Pendings) ->
|
||||||
|
lists:filter(fun is_banned_msg/1, Pendings).
|
||||||
|
|
||||||
|
is_banned_msg(#message{from = ClientId}) ->
|
||||||
|
[] =:= emqx_banned:look_up({clientid, ClientId});
|
||||||
|
is_banned_msg({deliver, _Topic, Msg}) ->
|
||||||
|
is_banned_msg(Msg).
|
||||||
|
|
|
@ -67,7 +67,8 @@
|
||||||
out/1,
|
out/1,
|
||||||
stats/1,
|
stats/1,
|
||||||
dropped/1,
|
dropped/1,
|
||||||
to_list/1
|
to_list/1,
|
||||||
|
filter/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(NO_PRIORITY_TABLE, disabled).
|
-define(NO_PRIORITY_TABLE, disabled).
|
||||||
|
@ -158,6 +159,19 @@ max_len(#mqueue{max_len = MaxLen}) -> MaxLen.
|
||||||
to_list(MQ) ->
|
to_list(MQ) ->
|
||||||
to_list(MQ, []).
|
to_list(MQ, []).
|
||||||
|
|
||||||
|
-spec filter(fun((any()) -> boolean()), mqueue()) -> mqueue().
|
||||||
|
filter(_Pred, #mqueue{len = 0} = MQ) ->
|
||||||
|
MQ;
|
||||||
|
filter(Pred, #mqueue{q = Q, len = Len, dropped = Droppend} = MQ) ->
|
||||||
|
Q2 = ?PQUEUE:filter(Pred, Q),
|
||||||
|
case ?PQUEUE:len(Q2) of
|
||||||
|
Len ->
|
||||||
|
MQ;
|
||||||
|
Len2 ->
|
||||||
|
Diff = Len - Len2,
|
||||||
|
MQ#mqueue{q = Q2, len = Len2, dropped = Droppend + Diff}
|
||||||
|
end.
|
||||||
|
|
||||||
to_list(MQ, Acc) ->
|
to_list(MQ, Acc) ->
|
||||||
case out(MQ) of
|
case out(MQ) of
|
||||||
{empty, _MQ} ->
|
{empty, _MQ} ->
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
deliver/3,
|
deliver/3,
|
||||||
enqueue/3,
|
enqueue/3,
|
||||||
dequeue/2,
|
dequeue/2,
|
||||||
|
filter_queue/2,
|
||||||
ignore_local/4,
|
ignore_local/4,
|
||||||
retry/2,
|
retry/2,
|
||||||
terminate/3
|
terminate/3
|
||||||
|
@ -529,6 +530,9 @@ dequeue(ClientInfo, Cnt, Msgs, Q) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
filter_queue(Pred, #session{mqueue = Q} = Session) ->
|
||||||
|
Session#session{mqueue = emqx_mqueue:filter(Pred, Q)}.
|
||||||
|
|
||||||
acc_cnt(#message{qos = ?QOS_0}, Cnt) -> Cnt;
|
acc_cnt(#message{qos = ?QOS_0}, Cnt) -> Cnt;
|
||||||
acc_cnt(_Msg, Cnt) -> Cnt - 1.
|
acc_cnt(_Msg, Cnt) -> Cnt - 1.
|
||||||
|
|
||||||
|
|
|
@ -141,3 +141,73 @@ t_kick(_) ->
|
||||||
snabbkaffe:stop(),
|
snabbkaffe:stop(),
|
||||||
emqx_banned:delete(Who),
|
emqx_banned:delete(Who),
|
||||||
?assertEqual(1, length(?of_kind(kick_session_due_to_banned, Trace))).
|
?assertEqual(1, length(?of_kind(kick_session_due_to_banned, Trace))).
|
||||||
|
|
||||||
|
t_session_taken(_) ->
|
||||||
|
erlang:process_flag(trap_exit, true),
|
||||||
|
Topic = <<"t/banned">>,
|
||||||
|
ClientId2 = <<"t_session_taken">>,
|
||||||
|
MsgNum = 3,
|
||||||
|
Connect = fun() ->
|
||||||
|
{ok, C} = emqtt:start_link([
|
||||||
|
{clientid, <<"client1">>},
|
||||||
|
{proto_ver, v5},
|
||||||
|
{clean_start, false},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 120}}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:connect(C),
|
||||||
|
{ok, _, [0]} = emqtt:subscribe(C, Topic, []),
|
||||||
|
C
|
||||||
|
end,
|
||||||
|
|
||||||
|
Publish = fun() ->
|
||||||
|
lists:foreach(
|
||||||
|
fun(_) ->
|
||||||
|
Msg = emqx_message:make(ClientId2, Topic, <<"payload">>),
|
||||||
|
emqx_broker:safe_publish(Msg)
|
||||||
|
end,
|
||||||
|
lists:seq(1, MsgNum)
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
|
||||||
|
C1 = Connect(),
|
||||||
|
ok = emqtt:disconnect(C1),
|
||||||
|
|
||||||
|
Publish(),
|
||||||
|
|
||||||
|
C2 = Connect(),
|
||||||
|
?assertEqual(MsgNum, length(receive_messages(MsgNum + 1))),
|
||||||
|
ok = emqtt:disconnect(C2),
|
||||||
|
|
||||||
|
Publish(),
|
||||||
|
|
||||||
|
Now = erlang:system_time(second),
|
||||||
|
Who = {clientid, ClientId2},
|
||||||
|
emqx_banned:create(#{
|
||||||
|
who => Who,
|
||||||
|
by => <<"test">>,
|
||||||
|
reason => <<"test">>,
|
||||||
|
at => Now,
|
||||||
|
until => Now + 120
|
||||||
|
}),
|
||||||
|
|
||||||
|
C3 = Connect(),
|
||||||
|
?assertEqual(0, length(receive_messages(MsgNum + 1))),
|
||||||
|
emqx_banned:delete(Who),
|
||||||
|
{ok, #{}, [0]} = emqtt:unsubscribe(C3, Topic),
|
||||||
|
ok = emqtt:disconnect(C3).
|
||||||
|
|
||||||
|
receive_messages(Count) ->
|
||||||
|
receive_messages(Count, []).
|
||||||
|
receive_messages(0, Msgs) ->
|
||||||
|
Msgs;
|
||||||
|
receive_messages(Count, Msgs) ->
|
||||||
|
receive
|
||||||
|
{publish, Msg} ->
|
||||||
|
ct:log("Msg: ~p ~n", [Msg]),
|
||||||
|
receive_messages(Count - 1, [Msg | Msgs]);
|
||||||
|
Other ->
|
||||||
|
ct:log("Other Msg: ~p~n", [Other]),
|
||||||
|
receive_messages(Count, Msgs)
|
||||||
|
after 1200 ->
|
||||||
|
Msgs
|
||||||
|
end.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
When connecting with the flag `clean_start=false`, the new session will filter out banned messages from the `mqueue` before deliver.
|
|
@ -0,0 +1 @@
|
||||||
|
当使用 `clean_start=false` 标志连接时,新会话将在传递之前从 `mqueue` 中过滤掉被封禁的消息。
|
Loading…
Reference in New Issue