Use multicast routing for more packets generated by muc

This commit is contained in:
Paweł Chmielowski 2021-07-13 16:01:25 +02:00
parent 2e2667bbd7
commit 0de6f1c538
3 changed files with 153 additions and 42 deletions

View File

@ -880,7 +880,7 @@ get_priority_from_presence(#presence{priority = Prio}) ->
-spec route_multiple(state(), [jid()], stanza()) -> ok.
route_multiple(#{lserver := LServer}, JIDs, Pkt) ->
From = xmpp:get_from(Pkt),
ejabberd_router_multicast:route_multicast(From, LServer, JIDs, Pkt).
ejabberd_router_multicast:route_multicast(From, LServer, JIDs, Pkt, false).
get_subscription(#jid{luser = LUser, lserver = LServer}, JID) ->
{Subscription, _, _} = ejabberd_hooks:run_fold(

View File

@ -30,7 +30,7 @@
-behaviour(gen_server).
%% API
-export([route_multicast/4,
-export([route_multicast/5,
register_route/1,
unregister_route/1
]).
@ -58,9 +58,11 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-spec route_multicast(jid(), binary(), [jid()], stanza()) -> ok.
route_multicast(From, Domain, Destinations, Packet) ->
case catch do_route(Domain, Destinations, xmpp:set_from(Packet, From)) of
-spec route_multicast(jid(), binary(), [jid()], stanza(), boolean()) -> ok.
route_multicast(From0, Domain0, Destinations0, Packet0, Wrapped0) ->
{From, Domain, Destinations, Packet, Wrapped} =
ejabberd_hooks:run_fold(multicast_route, {From0, Domain0, Destinations0, Packet0, Wrapped0}, []),
case catch do_route(Domain, Destinations, xmpp:set_from(Packet, From), Wrapped) of
{'EXIT', Reason} ->
?ERROR_MSG("~p~nwhen processing: ~p",
[Reason, {From, Domain, Destinations, Packet}]);
@ -157,7 +159,7 @@ handle_cast(Msg, State) ->
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info({route_multicast, Domain, Destinations, Packet}, State) ->
case catch do_route(Domain, Destinations, Packet) of
case catch do_route(Domain, Destinations, Packet, false) of
{'EXIT', Reason} ->
?ERROR_MSG("~p~nwhen processing: ~p",
[Reason, {Domain, Destinations, Packet}]);
@ -204,13 +206,41 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-spec update_to_in_wrapped(stanza(), jid()) -> stanza().
update_to_in_wrapped(Packet, To) ->
case Packet of
#message{sub_els = [#ps_event{
items = #ps_items{
items = [#ps_item{
sub_els = [Internal]
} = PSItem]
} = PSItems
} = PSEvent]} ->
Internal2 = xmpp:set_to(Internal, To),
PSItem2 = PSItem#ps_item{sub_els = Internal2},
PSItems2 = PSItems#ps_items{items = PSItem2},
PSEvent2 = PSEvent#ps_event{items = PSItems2},
Packet#message{sub_els = [PSEvent2]};
_ ->
Packet
end.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
%% From = #jid
%% Destinations = [#jid]
-spec do_route(binary(), [jid()], stanza()) -> any().
do_route(Domain, Destinations, Packet) ->
-spec do_route(binary(), [jid()], stanza(), boolean()) -> any().
do_route(Domain, Destinations, Packet, true) ->
?DEBUG("Route multicast:~n~ts~nDomain: ~ts~nDestinations: ~ts~n",
[xmpp:pp(Packet), Domain,
str:join([jid:encode(To) || To <- Destinations], <<", ">>)]),
lists:foreach(
fun(To) ->
Packet2 = update_to_in_wrapped(Packet, To),
ejabberd_router:route(Packet2)
end, Destinations);
do_route(Domain, Destinations, Packet, false) ->
?DEBUG("Route multicast:~n~ts~nDomain: ~ts~nDestinations: ~ts~n",
[xmpp:pp(Packet), Domain,
str:join([jid:encode(To) || To <- Destinations], <<", ">>)]),
@ -236,4 +266,7 @@ pick_multicast_pid(Rs) ->
-spec do_route_normal([jid()], stanza()) -> any().
do_route_normal(Destinations, Packet) ->
[ejabberd_router:route(xmpp:set_to(Packet, To)) || To <- Destinations].
lists:foreach(
fun(To) ->
ejabberd_router:route(xmpp:set_to(Packet, To))
end, Destinations).

View File

@ -4624,37 +4624,55 @@ store_room_no_checks(StateData, ChangesHints) ->
-spec send_subscriptions_change_notifications(jid(), binary(), subscribe|unsubscribe, state()) -> ok.
send_subscriptions_change_notifications(From, Nick, Type, State) ->
maps:fold(fun(_, #subscriber{nodes = Nodes, jid = JID}, _) ->
case lists:member(?NS_MUCSUB_NODES_SUBSCRIBERS, Nodes) of
{WJ, WN} =
maps:fold(
fun({WithJid, WithNick} = Res, #subscriber{nodes = Nodes, jid = JID}, _) ->
case lists:member(?NS_MUCSUB_NODES_SUBSCRIBERS, Nodes) of
true ->
case (State#state.config)#config.anonymous == false orelse
get_role(JID, State) == moderator orelse
get_default_role(get_affiliation(JID, State), State) == moderator of
true ->
ShowJid = case (State#state.config)#config.anonymous == false orelse
get_role(JID, State) == moderator orelse
get_default_role(get_affiliation(JID, State), State) == moderator of
true -> true;
_ -> false
end,
Payload = case {Type, ShowJid} of
{subscribe, true} ->
#muc_subscribe{jid = From, nick = Nick};
{subscribe, _} ->
#muc_subscribe{nick = Nick};
{unsubscribe, true} ->
#muc_unsubscribe{jid = From, nick = Nick};
{unsubscribe, _} ->
#muc_unsubscribe{nick = Nick}
end,
Packet = #message{
sub_els = [#ps_event{
items = #ps_items{
node = ?NS_MUCSUB_NODES_SUBSCRIBERS,
items = [#ps_item{
id = p1_rand:get_string(),
sub_els = [Payload]}]}}]},
ejabberd_router:route(xmpp:set_from_to(Packet, State#state.jid, JID));
false ->
ok
end
end, ok, State#state.subscribers).
{[JID | WithJid], WithNick};
_ ->
{WithJid, [JID | WithNick]}
end;
false ->
Res
end
end, ok, State#state.subscribers),
if WJ /= [] ->
Payload1 = case Type of
subscribe -> #muc_subscribe{jid = From, nick = Nick};
_ -> #muc_unsubscribe{jid = From, nick = Nick}
end,
Packet1 = #message{
sub_els = [#ps_event{
items = #ps_items{
node = ?NS_MUCSUB_NODES_SUBSCRIBERS,
items = [#ps_item{
id = p1_rand:get_string(),
sub_els = [Payload1]}]}}]},
ejabberd_router_multicast:route_multicast(State#state.jid, State#state.server_host,
WJ, Packet1, true);
true -> ok
end,
if WN /= [] ->
Payload2 = case Type of
subscribe -> #muc_subscribe{nick = Nick};
_ -> #muc_unsubscribe{nick = Nick}
end,
Packet2 = #message{
sub_els = [#ps_event{
items = #ps_items{
node = ?NS_MUCSUB_NODES_SUBSCRIBERS,
items = [#ps_item{
id = p1_rand:get_string(),
sub_els = [Payload2]}]}}]},
ejabberd_router_multicast:route_multicast(State#state.jid, State#state.server_host,
WN, Packet2, true);
true -> ok
end.
-spec send_wrapped(jid(), jid(), stanza(), binary(), state()) -> ok.
send_wrapped(From, To, Packet, Node, State) ->
@ -4727,10 +4745,70 @@ wrap(From, To, Packet, Node, Id) ->
-spec send_wrapped_multiple(jid(), users(), stanza(), binary(), state()) -> ok.
send_wrapped_multiple(From, Users, Packet, Node, State) ->
{Dir, Wra} =
maps:fold(
fun(_, #user{jid = To}, _) ->
send_wrapped(From, To, Packet, Node, State)
end, ok, Users).
fun(_, #user{jid = To, last_presence = LP}, {Direct, Wrapped} = Res) ->
IsOffline = LP == undefined,
if IsOffline ->
LBareTo = jid:tolower(jid:remove_resource(To)),
case maps:find(LBareTo, State#state.subscribers) of
{ok, #subscriber{nodes = Nodes}} ->
case lists:member(Node, Nodes) of
true ->
{Direct, [To | Wrapped]};
_ ->
Res
end;
_ ->
Res
end;
true ->
{[To | Direct], Wrapped}
end
end, {[],[]}, Users),
case Dir of
[] -> ok;
_ ->
case Packet of
#presence{type = unavailable} ->
case xmpp:get_subtag(Packet, #muc_user{}) of
#muc_user{destroy = Destroy,
status_codes = Codes} ->
case Destroy /= undefined orelse
(lists:member(110,Codes) andalso
not lists:member(303, Codes)) of
true ->
ejabberd_router_multicast:route_multicast(
State#state.jid, State#state.server_host, Dir,
#presence{id = p1_rand:get_string(),
type = unavailable}, false);
false ->
ok
end;
_ ->
false
end;
_ ->
ok
end,
ejabberd_router_multicast:route_multicast(State#state.jid, State#state.server_host,
Dir, Packet, false)
end,
case Wra of
[] -> ok;
_ ->
MamEnabled = (State#state.config)#config.mam,
Id = case xmpp:get_subtag(Packet, #stanza_id{by = #jid{}}) of
#stanza_id{id = Id2} ->
Id2;
_ ->
p1_rand:get_string()
end,
NewPacket = wrap(From, State#state.jid, Packet, Node, Id),
NewPacket2 = xmpp:put_meta(NewPacket, in_muc_mam, MamEnabled),
ejabberd_router_multicast:route_multicast(State#state.jid, State#state.server_host,
Wra, NewPacket2, true)
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Detect messange stanzas that don't have meaningful content