mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-20 17:27:00 +01:00
mod_client_state: Add "queue_pep" option
If the new "queue_pep" option is enabled and the client is inactive, PEP notifications are throttled in a similar way to presence stanzas and chat states. Only the most recent notification of a given node and payload type will be queued from a given contact.
This commit is contained in:
parent
4f009e64fc
commit
8f72c27b88
@ -31,8 +31,8 @@
|
|||||||
-behavior(gen_mod).
|
-behavior(gen_mod).
|
||||||
|
|
||||||
-export([start/2, stop/1, add_stream_feature/2,
|
-export([start/2, stop/1, add_stream_feature/2,
|
||||||
filter_presence/3, filter_chat_states/3, filter_other/3, flush_queue/2,
|
filter_presence/3, filter_chat_states/3, filter_pep/3, filter_other/3,
|
||||||
mod_opt_type/1]).
|
flush_queue/2, mod_opt_type/1]).
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
@ -41,13 +41,19 @@
|
|||||||
-define(CSI_QUEUE_MAX, 100).
|
-define(CSI_QUEUE_MAX, 100).
|
||||||
|
|
||||||
start(Host, Opts) ->
|
start(Host, Opts) ->
|
||||||
QueuePresence = gen_mod:get_opt(queue_presence, Opts,
|
QueuePresence =
|
||||||
fun(B) when is_boolean(B) -> B end,
|
gen_mod:get_opt(queue_presence, Opts,
|
||||||
true),
|
fun(B) when is_boolean(B) -> B end,
|
||||||
QueueChatStates = gen_mod:get_opt(queue_chat_states, Opts,
|
true),
|
||||||
fun(B) when is_boolean(B) -> B end,
|
QueueChatStates =
|
||||||
true),
|
gen_mod:get_opt(queue_chat_states, Opts,
|
||||||
if QueuePresence; QueueChatStates ->
|
fun(B) when is_boolean(B) -> B end,
|
||||||
|
true),
|
||||||
|
QueuePEP =
|
||||||
|
gen_mod:get_opt(queue_pep, Opts,
|
||||||
|
fun(B) when is_boolean(B) -> B end,
|
||||||
|
false),
|
||||||
|
if QueuePresence; QueueChatStates; QueuePEP ->
|
||||||
ejabberd_hooks:add(c2s_post_auth_features, Host, ?MODULE,
|
ejabberd_hooks:add(c2s_post_auth_features, Host, ?MODULE,
|
||||||
add_stream_feature, 50),
|
add_stream_feature, 50),
|
||||||
if QueuePresence ->
|
if QueuePresence ->
|
||||||
@ -60,6 +66,11 @@ start(Host, Opts) ->
|
|||||||
filter_chat_states, 50);
|
filter_chat_states, 50);
|
||||||
true -> ok
|
true -> ok
|
||||||
end,
|
end,
|
||||||
|
if QueuePEP ->
|
||||||
|
ejabberd_hooks:add(csi_filter_stanza, Host, ?MODULE,
|
||||||
|
filter_pep, 50);
|
||||||
|
true -> ok
|
||||||
|
end,
|
||||||
ejabberd_hooks:add(csi_filter_stanza, Host, ?MODULE,
|
ejabberd_hooks:add(csi_filter_stanza, Host, ?MODULE,
|
||||||
filter_other, 100),
|
filter_other, 100),
|
||||||
ejabberd_hooks:add(csi_flush_queue, Host, ?MODULE,
|
ejabberd_hooks:add(csi_flush_queue, Host, ?MODULE,
|
||||||
@ -68,13 +79,19 @@ start(Host, Opts) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
QueuePresence = gen_mod:get_module_opt(Host, ?MODULE, queue_presence,
|
QueuePresence =
|
||||||
fun(B) when is_boolean(B) -> B end,
|
gen_mod:get_module_opt(Host, ?MODULE, queue_presence,
|
||||||
true),
|
fun(B) when is_boolean(B) -> B end,
|
||||||
QueueChatStates = gen_mod:get_module_opt(Host, ?MODULE, queue_chat_states,
|
true),
|
||||||
fun(B) when is_boolean(B) -> B end,
|
QueueChatStates =
|
||||||
true),
|
gen_mod:get_module_opt(Host, ?MODULE, queue_chat_states,
|
||||||
if QueuePresence; QueueChatStates ->
|
fun(B) when is_boolean(B) -> B end,
|
||||||
|
true),
|
||||||
|
QueuePEP =
|
||||||
|
gen_mod:get_module_opt(Host, ?MODULE, queue_pep,
|
||||||
|
fun(B) when is_boolean(B) -> B end,
|
||||||
|
false),
|
||||||
|
if QueuePresence; QueueChatStates; QueuePEP ->
|
||||||
ejabberd_hooks:delete(c2s_post_auth_features, Host, ?MODULE,
|
ejabberd_hooks:delete(c2s_post_auth_features, Host, ?MODULE,
|
||||||
add_stream_feature, 50),
|
add_stream_feature, 50),
|
||||||
if QueuePresence ->
|
if QueuePresence ->
|
||||||
@ -87,6 +104,11 @@ stop(Host) ->
|
|||||||
filter_chat_states, 50);
|
filter_chat_states, 50);
|
||||||
true -> ok
|
true -> ok
|
||||||
end,
|
end,
|
||||||
|
if QueuePEP ->
|
||||||
|
ejabberd_hooks:delete(csi_filter_stanza, Host, ?MODULE,
|
||||||
|
filter_pep, 50);
|
||||||
|
true -> ok
|
||||||
|
end,
|
||||||
ejabberd_hooks:delete(csi_filter_stanza, Host, ?MODULE,
|
ejabberd_hooks:delete(csi_filter_stanza, Host, ?MODULE,
|
||||||
filter_other, 100),
|
filter_other, 100),
|
||||||
ejabberd_hooks:delete(csi_flush_queue, Host, ?MODULE,
|
ejabberd_hooks:delete(csi_flush_queue, Host, ?MODULE,
|
||||||
@ -122,6 +144,17 @@ filter_chat_states({C2SState, _OutStanzas} = Acc, Host,
|
|||||||
end;
|
end;
|
||||||
filter_chat_states(Acc, _Host, _Stanza) -> Acc.
|
filter_chat_states(Acc, _Host, _Stanza) -> Acc.
|
||||||
|
|
||||||
|
filter_pep({C2SState, _OutStanzas} = Acc, Host,
|
||||||
|
#xmlel{name = <<"message">>} = Stanza) ->
|
||||||
|
case find_pep(Stanza) of
|
||||||
|
{value, Type} ->
|
||||||
|
?DEBUG("Got PEP notification", []),
|
||||||
|
queue_add(Type, Stanza, Host, C2SState);
|
||||||
|
false ->
|
||||||
|
Acc
|
||||||
|
end;
|
||||||
|
filter_pep(Acc, _Host, _Stanza) -> Acc.
|
||||||
|
|
||||||
filter_other({C2SState, _OutStanzas}, Host, Stanza) ->
|
filter_other({C2SState, _OutStanzas}, Host, Stanza) ->
|
||||||
?DEBUG("Won't add stanza to CSI queue", []),
|
?DEBUG("Won't add stanza to CSI queue", []),
|
||||||
queue_take(Stanza, Host, C2SState).
|
queue_take(Stanza, Host, C2SState).
|
||||||
@ -132,6 +165,42 @@ flush_queue({C2SState, _OutStanzas}, Host) ->
|
|||||||
NewState = set_queue([], C2SState),
|
NewState = set_queue([], C2SState),
|
||||||
{stop, {NewState, get_stanzas(Queue, Host)}}.
|
{stop, {NewState, get_stanzas(Queue, Host)}}.
|
||||||
|
|
||||||
|
find_pep(#xmlel{name = <<"message">>} = Stanza) ->
|
||||||
|
From = fxml:get_tag_attr_s(<<"from">>, Stanza),
|
||||||
|
case jid:from_string(From) of
|
||||||
|
#jid{luser = <<>>} -> % It's not PEP.
|
||||||
|
false;
|
||||||
|
_ ->
|
||||||
|
case fxml:get_subtag_with_xmlns(Stanza, <<"event">>,
|
||||||
|
?NS_PUBSUB_EVENT) of
|
||||||
|
#xmlel{children = Els} ->
|
||||||
|
get_pep_node_and_xmlns(fxml:remove_cdata(Els));
|
||||||
|
false ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
get_pep_node_and_xmlns([#xmlel{name = <<"items">>, attrs = ItemsAttrs,
|
||||||
|
children = Item}]) ->
|
||||||
|
case {fxml:get_attr(<<"node">>, ItemsAttrs), fxml:remove_cdata(Item)} of
|
||||||
|
{{value, Node}, [#xmlel{name = <<"item">>, children = Payload}]} ->
|
||||||
|
case fxml:remove_cdata(Payload) of
|
||||||
|
[#xmlel{attrs = PayloadAttrs}] ->
|
||||||
|
case fxml:get_attr(<<"xmlns">>, PayloadAttrs) of
|
||||||
|
{value, XMLNS} ->
|
||||||
|
{value, {Node, XMLNS}};
|
||||||
|
false ->
|
||||||
|
false
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end;
|
||||||
|
get_pep_node_and_xmlns(_) ->
|
||||||
|
false.
|
||||||
|
|
||||||
queue_add(Type, Stanza, Host, C2SState) ->
|
queue_add(Type, Stanza, Host, C2SState) ->
|
||||||
case get_queue(C2SState) of
|
case get_queue(C2SState) of
|
||||||
Queue when length(Queue) >= ?CSI_QUEUE_MAX ->
|
Queue when length(Queue) >= ?CSI_QUEUE_MAX ->
|
||||||
@ -179,4 +248,6 @@ mod_opt_type(queue_presence) ->
|
|||||||
fun(B) when is_boolean(B) -> B end;
|
fun(B) when is_boolean(B) -> B end;
|
||||||
mod_opt_type(queue_chat_states) ->
|
mod_opt_type(queue_chat_states) ->
|
||||||
fun(B) when is_boolean(B) -> B end;
|
fun(B) when is_boolean(B) -> B end;
|
||||||
mod_opt_type(_) -> [queue_presence, queue_chat_states].
|
mod_opt_type(queue_pep) ->
|
||||||
|
fun(B) when is_boolean(B) -> B end;
|
||||||
|
mod_opt_type(_) -> [queue_presence, queue_chat_states, queue_pep].
|
||||||
|
@ -2255,12 +2255,41 @@ client_state_master(Config) ->
|
|||||||
ChatState = #message{to = Peer, thread = <<"1">>,
|
ChatState = #message{to = Peer, thread = <<"1">>,
|
||||||
sub_els = [#chatstate{type = active}]},
|
sub_els = [#chatstate{type = active}]},
|
||||||
Message = ChatState#message{body = [#text{data = <<"body">>}]},
|
Message = ChatState#message{body = [#text{data = <<"body">>}]},
|
||||||
|
PepPayload = xmpp_codec:encode(#presence{}),
|
||||||
|
PepOne = #message{
|
||||||
|
to = Peer,
|
||||||
|
sub_els =
|
||||||
|
[#pubsub_event{
|
||||||
|
items =
|
||||||
|
[#pubsub_event_items{
|
||||||
|
node = <<"foo-1">>,
|
||||||
|
items =
|
||||||
|
[#pubsub_event_item{
|
||||||
|
id = <<"pep-1">>,
|
||||||
|
xml_els = [PepPayload]}]}]}]},
|
||||||
|
PepTwo = #message{
|
||||||
|
to = Peer,
|
||||||
|
sub_els =
|
||||||
|
[#pubsub_event{
|
||||||
|
items =
|
||||||
|
[#pubsub_event_items{
|
||||||
|
node = <<"foo-2">>,
|
||||||
|
items =
|
||||||
|
[#pubsub_event_item{
|
||||||
|
id = <<"pep-2">>,
|
||||||
|
xml_els = [PepPayload]}]}]}]},
|
||||||
%% Wait for the slave to become inactive.
|
%% Wait for the slave to become inactive.
|
||||||
wait_for_slave(Config),
|
wait_for_slave(Config),
|
||||||
%% Should be queued (but see below):
|
%% Should be queued (but see below):
|
||||||
send(Config, Presence),
|
send(Config, Presence),
|
||||||
%% Should replace the previous presence in the queue:
|
%% Should replace the previous presence in the queue:
|
||||||
send(Config, Presence#presence{type = unavailable}),
|
send(Config, Presence#presence{type = unavailable}),
|
||||||
|
%% The following two PEP stanzas should be queued (but see below):
|
||||||
|
send(Config, PepOne),
|
||||||
|
send(Config, PepTwo),
|
||||||
|
%% The following two PEP stanzas should replace the previous two:
|
||||||
|
send(Config, PepOne),
|
||||||
|
send(Config, PepTwo),
|
||||||
%% Should be queued (but see below):
|
%% Should be queued (but see below):
|
||||||
send(Config, ChatState),
|
send(Config, ChatState),
|
||||||
%% Should replace the previous chat state in the queue:
|
%% Should replace the previous chat state in the queue:
|
||||||
@ -2279,6 +2308,28 @@ client_state_slave(Config) ->
|
|||||||
wait_for_master(Config),
|
wait_for_master(Config),
|
||||||
?recv1(#presence{from = Peer, type = unavailable,
|
?recv1(#presence{from = Peer, type = unavailable,
|
||||||
sub_els = [#delay{}]}),
|
sub_els = [#delay{}]}),
|
||||||
|
#message{
|
||||||
|
from = Peer,
|
||||||
|
sub_els =
|
||||||
|
[#pubsub_event{
|
||||||
|
items =
|
||||||
|
[#pubsub_event_items{
|
||||||
|
node = <<"foo-1">>,
|
||||||
|
items =
|
||||||
|
[#pubsub_event_item{
|
||||||
|
id = <<"pep-1">>}]}]},
|
||||||
|
#delay{}]} = recv(),
|
||||||
|
#message{
|
||||||
|
from = Peer,
|
||||||
|
sub_els =
|
||||||
|
[#pubsub_event{
|
||||||
|
items =
|
||||||
|
[#pubsub_event_items{
|
||||||
|
node = <<"foo-2">>,
|
||||||
|
items =
|
||||||
|
[#pubsub_event_item{
|
||||||
|
id = <<"pep-2">>}]}]},
|
||||||
|
#delay{}]} = recv(),
|
||||||
?recv1(#message{from = Peer, thread = <<"1">>,
|
?recv1(#message{from = Peer, thread = <<"1">>,
|
||||||
sub_els = [#chatstate{type = composing},
|
sub_els = [#chatstate{type = composing},
|
||||||
#delay{}]}),
|
#delay{}]}),
|
||||||
|
@ -215,6 +215,7 @@ Welcome to this XMPP server."
|
|||||||
mod_client_state:
|
mod_client_state:
|
||||||
queue_presence: true
|
queue_presence: true
|
||||||
queue_chat_states: true
|
queue_chat_states: true
|
||||||
|
queue_pep: true
|
||||||
mod_adhoc: []
|
mod_adhoc: []
|
||||||
mod_configure: []
|
mod_configure: []
|
||||||
mod_disco: []
|
mod_disco: []
|
||||||
@ -271,6 +272,7 @@ Welcome to this XMPP server."
|
|||||||
mod_client_state:
|
mod_client_state:
|
||||||
queue_presence: true
|
queue_presence: true
|
||||||
queue_chat_states: true
|
queue_chat_states: true
|
||||||
|
queue_pep: true
|
||||||
mod_adhoc: []
|
mod_adhoc: []
|
||||||
mod_configure: []
|
mod_configure: []
|
||||||
mod_disco: []
|
mod_disco: []
|
||||||
|
Loading…
Reference in New Issue
Block a user