mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
Optimize MucSub processing
This commit is contained in:
parent
3114ce4ed2
commit
5abc03ff8f
@ -87,6 +87,16 @@
|
|||||||
nick = <<>> :: binary(),
|
nick = <<>> :: binary(),
|
||||||
nodes = [] :: [binary()]}).
|
nodes = [] :: [binary()]}).
|
||||||
|
|
||||||
|
-record(muc_subscribers,
|
||||||
|
{subscribers = #{} :: subscribers(),
|
||||||
|
subscriber_nicks = #{} :: subscriber_nicks(),
|
||||||
|
subscriber_nodes = #{} :: subscriber_nodes()
|
||||||
|
}).
|
||||||
|
|
||||||
|
-type subscribers() :: #{ljid() => #subscriber{}}.
|
||||||
|
-type subscriber_nicks() :: #{binary() => [ljid()]}.
|
||||||
|
-type subscriber_nodes() :: #{binary() => subscribers()}.
|
||||||
|
|
||||||
-record(activity,
|
-record(activity,
|
||||||
{
|
{
|
||||||
message_time = 0 :: integer(),
|
message_time = 0 :: integer(),
|
||||||
@ -106,8 +116,7 @@
|
|||||||
jid = #jid{} :: jid(),
|
jid = #jid{} :: jid(),
|
||||||
config = #config{} :: config(),
|
config = #config{} :: config(),
|
||||||
users = #{} :: users(),
|
users = #{} :: users(),
|
||||||
subscribers = #{} :: subscribers(),
|
muc_subscribers = #muc_subscribers{} :: #muc_subscribers{},
|
||||||
subscriber_nicks = #{} :: subscriber_nicks(),
|
|
||||||
last_voice_request_time = treap:empty() :: treap:treap(),
|
last_voice_request_time = treap:empty() :: treap:treap(),
|
||||||
robots = #{} :: robots(),
|
robots = #{} :: robots(),
|
||||||
nicks = #{} :: nicks(),
|
nicks = #{} :: nicks(),
|
||||||
@ -126,5 +135,3 @@
|
|||||||
-type robots() :: #{jid() => {binary(), stanza()}}.
|
-type robots() :: #{jid() => {binary(), stanza()}}.
|
||||||
-type nicks() :: #{binary() => [ljid()]}.
|
-type nicks() :: #{binary() => [ljid()]}.
|
||||||
-type affiliations() :: #{ljid() => affiliation() | {affiliation(), binary()}}.
|
-type affiliations() :: #{ljid() => affiliation() | {affiliation(), binary()}}.
|
||||||
-type subscribers() :: #{ljid() => #subscriber{}}.
|
|
||||||
-type subscriber_nicks() :: #{binary() => [ljid()]}.
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
room_destroyed/4,
|
room_destroyed/4,
|
||||||
store_room/4,
|
store_room/4,
|
||||||
store_room/5,
|
store_room/5,
|
||||||
|
store_changes/4,
|
||||||
restore_room/3,
|
restore_room/3,
|
||||||
forget_room/3,
|
forget_room/3,
|
||||||
create_room/3,
|
create_room/3,
|
||||||
@ -91,6 +92,7 @@
|
|||||||
-callback init(binary(), gen_mod:opts()) -> any().
|
-callback init(binary(), gen_mod:opts()) -> any().
|
||||||
-callback import(binary(), binary(), [binary()]) -> ok.
|
-callback import(binary(), binary(), [binary()]) -> ok.
|
||||||
-callback store_room(binary(), binary(), binary(), list(), list()|undefined) -> {atomic, any()}.
|
-callback store_room(binary(), binary(), binary(), list(), list()|undefined) -> {atomic, any()}.
|
||||||
|
-callback store_changes(binary(), binary(), binary(), list()) -> {atomic, any()}.
|
||||||
-callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error.
|
-callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error.
|
||||||
-callback forget_room(binary(), binary(), binary()) -> {atomic, any()}.
|
-callback forget_room(binary(), binary(), binary()) -> {atomic, any()}.
|
||||||
-callback can_use_nick(binary(), binary(), jid(), binary()) -> boolean().
|
-callback can_use_nick(binary(), binary(), jid(), binary()) -> boolean().
|
||||||
@ -111,7 +113,8 @@
|
|||||||
-callback get_subscribed_rooms(binary(), binary(), jid()) ->
|
-callback get_subscribed_rooms(binary(), binary(), jid()) ->
|
||||||
{ok, [{jid(), binary(), [binary()]}]} | {error, db_failure}.
|
{ok, [{jid(), binary(), [binary()]}]} | {error, db_failure}.
|
||||||
|
|
||||||
-optional_callbacks([get_subscribed_rooms/3]).
|
-optional_callbacks([get_subscribed_rooms/3,
|
||||||
|
store_changes/4]).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
@ -313,6 +316,11 @@ store_room(ServerHost, Host, Name, Opts, ChangesHints) ->
|
|||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
Mod:store_room(LServer, Host, Name, Opts, ChangesHints).
|
Mod:store_room(LServer, Host, Name, Opts, ChangesHints).
|
||||||
|
|
||||||
|
store_changes(ServerHost, Host, Name, ChangesHints) ->
|
||||||
|
LServer = jid:nameprep(ServerHost),
|
||||||
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
|
Mod:store_changes(LServer, Host, Name, ChangesHints).
|
||||||
|
|
||||||
restore_room(ServerHost, Host, Name) ->
|
restore_room(ServerHost, Host, Name) ->
|
||||||
LServer = jid:nameprep(ServerHost),
|
LServer = jid:nameprep(ServerHost),
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
@ -570,7 +578,7 @@ unhibernate_room(ServerHost, Host, Room) ->
|
|||||||
case RMod:find_online_room(ServerHost, Room, Host) of
|
case RMod:find_online_room(ServerHost, Room, Host) of
|
||||||
error ->
|
error ->
|
||||||
Proc = procname(ServerHost, {Room, Host}),
|
Proc = procname(ServerHost, {Room, Host}),
|
||||||
case ?GEN_SERVER:call(Proc, {unhibernate, Room, Host}) of
|
case ?GEN_SERVER:call(Proc, {unhibernate, Room, Host}, 20000) of
|
||||||
{ok, _} = R -> R;
|
{ok, _} = R -> R;
|
||||||
_ -> error
|
_ -> error
|
||||||
end;
|
end;
|
||||||
|
@ -641,7 +641,7 @@ handle_event({service_message, Msg}, _StateName,
|
|||||||
MessagePkt = #message{type = groupchat, body = xmpp:mk_text(Msg)},
|
MessagePkt = #message{type = groupchat, body = xmpp:mk_text(Msg)},
|
||||||
send_wrapped_multiple(
|
send_wrapped_multiple(
|
||||||
StateData#state.jid,
|
StateData#state.jid,
|
||||||
get_users_and_subscribers(StateData),
|
get_users_and_subscribers_with_node(?NS_MUCSUB_NODES_MESSAGES, StateData),
|
||||||
MessagePkt,
|
MessagePkt,
|
||||||
?NS_MUCSUB_NODES_MESSAGES,
|
?NS_MUCSUB_NODES_MESSAGES,
|
||||||
StateData),
|
StateData),
|
||||||
@ -705,7 +705,7 @@ handle_sync_event({change_state, NewStateData}, _From,
|
|||||||
true ->
|
true ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
erlang:put(muc_subscribers, NewStateData#state.subscribers)
|
erlang:put(muc_subscribers, NewStateData#state.muc_subscribers#muc_subscribers.subscribers)
|
||||||
end,
|
end,
|
||||||
{reply, {ok, NewStateData}, StateName, NewStateData};
|
{reply, {ok, NewStateData}, StateName, NewStateData};
|
||||||
handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData) ->
|
handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData) ->
|
||||||
@ -717,8 +717,10 @@ handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData
|
|||||||
{reply, {ok, NSD}, StateName, NSD}
|
{reply, {ok, NSD}, StateName, NSD}
|
||||||
end;
|
end;
|
||||||
handle_sync_event(get_subscribers, _From, StateName, StateData) ->
|
handle_sync_event(get_subscribers, _From, StateName, StateData) ->
|
||||||
JIDs = lists:map(fun jid:make/1,
|
JIDs = muc_subscribers_fold(
|
||||||
maps:keys(StateData#state.subscribers)),
|
fun(_LBareJID, #subscriber{jid = JID}, Acc) ->
|
||||||
|
[JID | Acc]
|
||||||
|
end, [], StateData#state.muc_subscribers),
|
||||||
{reply, {ok, JIDs}, StateName, StateData};
|
{reply, {ok, JIDs}, StateName, StateData};
|
||||||
handle_sync_event({muc_subscribe, From, Nick, Nodes}, _From,
|
handle_sync_event({muc_subscribe, From, Nick, Nodes}, _From,
|
||||||
StateName, StateData) ->
|
StateName, StateData) ->
|
||||||
@ -762,7 +764,8 @@ handle_sync_event({muc_unsubscribe, From}, _From, StateName,
|
|||||||
{reply, {error, get_error_text(Err)}, StateName, StateData}
|
{reply, {error, get_error_text(Err)}, StateName, StateData}
|
||||||
end;
|
end;
|
||||||
handle_sync_event({is_subscribed, From}, _From, StateName, StateData) ->
|
handle_sync_event({is_subscribed, From}, _From, StateName, StateData) ->
|
||||||
IsSubs = try maps:get(jid:split(From), StateData#state.subscribers) of
|
IsSubs = try muc_subscribers_get(
|
||||||
|
jid:split(From), StateData#state.muc_subscribers) of
|
||||||
#subscriber{nick = Nick, nodes = Nodes} -> {true, Nick, Nodes}
|
#subscriber{nick = Nick, nodes = Nodes} -> {true, Nick, Nodes}
|
||||||
catch _:{badkey, _} -> false
|
catch _:{badkey, _} -> false
|
||||||
end,
|
end,
|
||||||
@ -899,7 +902,8 @@ terminate(Reason, _StateName,
|
|||||||
_ -> ok
|
_ -> ok
|
||||||
end,
|
end,
|
||||||
tab_remove_online_user(JID, StateData)
|
tab_remove_online_user(JID, StateData)
|
||||||
end, [], get_users_and_subscribers(StateData)),
|
end, [], get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_PARTICIPANTS, StateData)),
|
||||||
|
|
||||||
disable_hibernate_timer(StateData),
|
disable_hibernate_timer(StateData),
|
||||||
case StateData#state.hibernate_timer of
|
case StateData#state.hibernate_timer of
|
||||||
@ -991,7 +995,7 @@ process_groupchat_message(#message{from = From, lang = Lang} = Packet, StateData
|
|||||||
end,
|
end,
|
||||||
send_wrapped_multiple(
|
send_wrapped_multiple(
|
||||||
jid:replace_resource(StateData#state.jid, FromNick),
|
jid:replace_resource(StateData#state.jid, FromNick),
|
||||||
get_users_and_subscribers(StateData),
|
get_users_and_subscribers_with_node(Node, StateData),
|
||||||
NewPacket, Node, NewStateData1),
|
NewPacket, Node, NewStateData1),
|
||||||
NewStateData2 = case has_body_or_subject(NewPacket) of
|
NewStateData2 = case has_body_or_subject(NewPacket) of
|
||||||
true ->
|
true ->
|
||||||
@ -1197,8 +1201,8 @@ get_participant_data(From, StateData) ->
|
|||||||
#user{nick = FromNick, role = Role} ->
|
#user{nick = FromNick, role = Role} ->
|
||||||
{FromNick, Role}
|
{FromNick, Role}
|
||||||
catch _:{badkey, _} ->
|
catch _:{badkey, _} ->
|
||||||
try maps:get(jid:tolower(jid:remove_resource(From)),
|
try muc_subscribers_get(jid:tolower(jid:remove_resource(From)),
|
||||||
StateData#state.subscribers) of
|
StateData#state.muc_subscribers) of
|
||||||
#subscriber{nick = FromNick} ->
|
#subscriber{nick = FromNick} ->
|
||||||
{FromNick, none}
|
{FromNick, none}
|
||||||
catch _:{badkey, _} ->
|
catch _:{badkey, _} ->
|
||||||
@ -1329,7 +1333,7 @@ maybe_strip_status_from_presence(From, Packet, StateData) ->
|
|||||||
close_room_if_temporary_and_empty(StateData1) ->
|
close_room_if_temporary_and_empty(StateData1) ->
|
||||||
case not (StateData1#state.config)#config.persistent
|
case not (StateData1#state.config)#config.persistent
|
||||||
andalso maps:size(StateData1#state.users) == 0
|
andalso maps:size(StateData1#state.users) == 0
|
||||||
andalso maps:size(StateData1#state.subscribers) == 0 of
|
andalso muc_subscribers_size(StateData1#state.muc_subscribers) == 0 of
|
||||||
true ->
|
true ->
|
||||||
?INFO_MSG("Destroyed MUC room ~ts because it's temporary "
|
?INFO_MSG("Destroyed MUC room ~ts because it's temporary "
|
||||||
"and empty",
|
"and empty",
|
||||||
@ -1342,6 +1346,17 @@ close_room_if_temporary_and_empty(StateData1) ->
|
|||||||
|
|
||||||
-spec get_users_and_subscribers(state()) -> users().
|
-spec get_users_and_subscribers(state()) -> users().
|
||||||
get_users_and_subscribers(StateData) ->
|
get_users_and_subscribers(StateData) ->
|
||||||
|
get_users_and_subscribers_aux(
|
||||||
|
StateData#state.muc_subscribers#muc_subscribers.subscribers,
|
||||||
|
StateData).
|
||||||
|
|
||||||
|
-spec get_users_and_subscribers_with_node(binary(), state()) -> users().
|
||||||
|
get_users_and_subscribers_with_node(Node, StateData) ->
|
||||||
|
get_users_and_subscribers_aux(
|
||||||
|
muc_subscribers_get_by_node(Node, StateData#state.muc_subscribers),
|
||||||
|
StateData).
|
||||||
|
|
||||||
|
get_users_and_subscribers_aux(Subscribers, StateData) ->
|
||||||
OnlineSubscribers = maps:fold(
|
OnlineSubscribers = maps:fold(
|
||||||
fun(LJID, _, Acc) ->
|
fun(LJID, _, Acc) ->
|
||||||
LBareJID = jid:remove_resource(LJID),
|
LBareJID = jid:remove_resource(LJID),
|
||||||
@ -1365,7 +1380,7 @@ get_users_and_subscribers(StateData) ->
|
|||||||
true ->
|
true ->
|
||||||
Acc
|
Acc
|
||||||
end
|
end
|
||||||
end, StateData#state.users, StateData#state.subscribers).
|
end, StateData#state.users, Subscribers).
|
||||||
|
|
||||||
-spec is_user_online(jid(), state()) -> boolean().
|
-spec is_user_online(jid(), state()) -> boolean().
|
||||||
is_user_online(JID, StateData) ->
|
is_user_online(JID, StateData) ->
|
||||||
@ -1375,7 +1390,7 @@ is_user_online(JID, StateData) ->
|
|||||||
-spec is_subscriber(jid(), state()) -> boolean().
|
-spec is_subscriber(jid(), state()) -> boolean().
|
||||||
is_subscriber(JID, StateData) ->
|
is_subscriber(JID, StateData) ->
|
||||||
LJID = jid:tolower(jid:remove_resource(JID)),
|
LJID = jid:tolower(jid:remove_resource(JID)),
|
||||||
maps:is_key(LJID, StateData#state.subscribers).
|
muc_subscribers_is_key(LJID, StateData#state.muc_subscribers).
|
||||||
|
|
||||||
%% Check if the user is occupant of the room, or at least is an admin or owner.
|
%% Check if the user is occupant of the room, or at least is an admin or owner.
|
||||||
-spec is_occupant_or_admin(jid(), state()) -> boolean().
|
-spec is_occupant_or_admin(jid(), state()) -> boolean().
|
||||||
@ -1869,16 +1884,15 @@ set_subscriber(JID, Nick, Nodes,
|
|||||||
#state{room = Room, host = Host, server_host = ServerHost} = StateData) ->
|
#state{room = Room, host = Host, server_host = ServerHost} = StateData) ->
|
||||||
BareJID = jid:remove_resource(JID),
|
BareJID = jid:remove_resource(JID),
|
||||||
LBareJID = jid:tolower(BareJID),
|
LBareJID = jid:tolower(BareJID),
|
||||||
Subscribers = maps:put(LBareJID,
|
MUCSubscribers =
|
||||||
|
muc_subscribers_put(
|
||||||
#subscriber{jid = BareJID,
|
#subscriber{jid = BareJID,
|
||||||
nick = Nick,
|
nick = Nick,
|
||||||
nodes = Nodes},
|
nodes = Nodes},
|
||||||
StateData#state.subscribers),
|
StateData#state.muc_subscribers),
|
||||||
Nicks = maps:put(Nick, [LBareJID], StateData#state.subscriber_nicks),
|
NewStateData = StateData#state{muc_subscribers = MUCSubscribers},
|
||||||
NewStateData = StateData#state{subscribers = Subscribers,
|
|
||||||
subscriber_nicks = Nicks},
|
|
||||||
store_room(NewStateData, [{add_subscription, BareJID, Nick, Nodes}]),
|
store_room(NewStateData, [{add_subscription, BareJID, Nick, Nodes}]),
|
||||||
case not maps:is_key(LBareJID, StateData#state.subscribers) of
|
case not muc_subscribers_is_key(LBareJID, StateData#state.muc_subscribers) of
|
||||||
true ->
|
true ->
|
||||||
send_subscriptions_change_notifications(BareJID, Nick, subscribe, NewStateData),
|
send_subscriptions_change_notifications(BareJID, Nick, subscribe, NewStateData),
|
||||||
ejabberd_hooks:run(muc_subscribed, ServerHost, [ServerHost, Room, Host, BareJID]);
|
ejabberd_hooks:run(muc_subscribed, ServerHost, [ServerHost, Room, Host, BareJID]);
|
||||||
@ -1956,7 +1970,8 @@ add_user_presence_un(JID, Presence, StateData) ->
|
|||||||
-spec find_jids_by_nick(binary(), state()) -> [jid()].
|
-spec find_jids_by_nick(binary(), state()) -> [jid()].
|
||||||
find_jids_by_nick(Nick, StateData) ->
|
find_jids_by_nick(Nick, StateData) ->
|
||||||
Users = case maps:get(Nick, StateData#state.nicks, []) of
|
Users = case maps:get(Nick, StateData#state.nicks, []) of
|
||||||
[] -> maps:get(Nick, StateData#state.subscriber_nicks, []);
|
[] -> muc_subscribers_get_by_nick(
|
||||||
|
Nick, StateData#state.muc_subscribers);
|
||||||
Us -> Us
|
Us -> Us
|
||||||
end,
|
end,
|
||||||
[jid:make(LJID) || LJID <- Users].
|
[jid:make(LJID) || LJID <- Users].
|
||||||
@ -2020,9 +2035,9 @@ is_nick_change(JID, Nick, StateData) ->
|
|||||||
nick_collision(User, Nick, StateData) ->
|
nick_collision(User, Nick, StateData) ->
|
||||||
UserOfNick = case find_jid_by_nick(Nick, StateData) of
|
UserOfNick = case find_jid_by_nick(Nick, StateData) of
|
||||||
false ->
|
false ->
|
||||||
try maps:get(Nick, StateData#state.subscriber_nicks) of
|
case muc_subscribers_get_by_nick(Nick, StateData#state.muc_subscribers) of
|
||||||
[J] -> J
|
[J] -> J;
|
||||||
catch _:{badkey, _} -> false
|
[] -> false
|
||||||
end;
|
end;
|
||||||
J -> J
|
J -> J
|
||||||
end,
|
end,
|
||||||
@ -2433,6 +2448,11 @@ send_new_presence(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
|
|||||||
false -> {none, #presence{type = unavailable}}
|
false -> {none, #presence{type = unavailable}}
|
||||||
end,
|
end,
|
||||||
Affiliation = get_affiliation(LJID, StateData),
|
Affiliation = get_affiliation(LJID, StateData),
|
||||||
|
Node1 = case is_ra_changed(NJID, IsInitialPresence, StateData, OldStateData) of
|
||||||
|
true -> ?NS_MUCSUB_NODES_AFFILIATIONS;
|
||||||
|
false -> ?NS_MUCSUB_NODES_PRESENCE
|
||||||
|
end,
|
||||||
|
Node2 = ?NS_MUCSUB_NODES_PARTICIPANTS,
|
||||||
UserMap =
|
UserMap =
|
||||||
case is_room_overcrowded(StateData) orelse
|
case is_room_overcrowded(StateData) orelse
|
||||||
(not (presence_broadcast_allowed(NJID, StateData) orelse
|
(not (presence_broadcast_allowed(NJID, StateData) orelse
|
||||||
@ -2440,7 +2460,10 @@ send_new_presence(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
|
|||||||
true ->
|
true ->
|
||||||
#{LNJID => UserInfo};
|
#{LNJID => UserInfo};
|
||||||
false ->
|
false ->
|
||||||
get_users_and_subscribers(StateData)
|
%% TODO: optimize further
|
||||||
|
UM1 = get_users_and_subscribers_with_node(Node1, StateData),
|
||||||
|
UM2 = get_users_and_subscribers_with_node(Node2, StateData),
|
||||||
|
maps:merge(UM1, UM2)
|
||||||
end,
|
end,
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(LUJID, Info, _) ->
|
fun(LUJID, Info, _) ->
|
||||||
@ -2465,10 +2488,6 @@ send_new_presence(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
|
|||||||
Packet = xmpp:set_subtag(
|
Packet = xmpp:set_subtag(
|
||||||
Pres, #muc_user{items = [Item],
|
Pres, #muc_user{items = [Item],
|
||||||
status_codes = StatusCodes}),
|
status_codes = StatusCodes}),
|
||||||
Node1 = case is_ra_changed(NJID, IsInitialPresence, StateData, OldStateData) of
|
|
||||||
true -> ?NS_MUCSUB_NODES_AFFILIATIONS;
|
|
||||||
false -> ?NS_MUCSUB_NODES_PRESENCE
|
|
||||||
end,
|
|
||||||
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
|
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
|
||||||
Info#user.jid, Packet, Node1, StateData),
|
Info#user.jid, Packet, Node1, StateData),
|
||||||
Type = xmpp:get_type(Packet),
|
Type = xmpp:get_type(Packet),
|
||||||
@ -2476,7 +2495,6 @@ send_new_presence(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
|
|||||||
IsOccupant = Info#user.last_presence /= undefined,
|
IsOccupant = Info#user.last_presence /= undefined,
|
||||||
if (IsSubscriber and not IsOccupant) and
|
if (IsSubscriber and not IsOccupant) and
|
||||||
(IsInitialPresence or (Type == unavailable)) ->
|
(IsInitialPresence or (Type == unavailable)) ->
|
||||||
Node2 = ?NS_MUCSUB_NODES_PARTICIPANTS,
|
|
||||||
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
|
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
|
||||||
Info#user.jid, Packet, Node2, StateData);
|
Info#user.jid, Packet, Node2, StateData);
|
||||||
true ->
|
true ->
|
||||||
@ -2607,11 +2625,13 @@ send_nick_changing(JID, OldNick, StateData,
|
|||||||
end;
|
end;
|
||||||
(_, _, _) ->
|
(_, _, _) ->
|
||||||
ok
|
ok
|
||||||
end, ok, get_users_and_subscribers(StateData)).
|
end, ok, get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_PRESENCE, StateData)).
|
||||||
|
|
||||||
-spec maybe_send_affiliation(jid(), affiliation(), state()) -> ok.
|
-spec maybe_send_affiliation(jid(), affiliation(), state()) -> ok.
|
||||||
maybe_send_affiliation(JID, Affiliation, StateData) ->
|
maybe_send_affiliation(JID, Affiliation, StateData) ->
|
||||||
LJID = jid:tolower(JID),
|
LJID = jid:tolower(JID),
|
||||||
|
%% TODO: there should be a better way to check IsOccupant
|
||||||
Users = get_users_and_subscribers(StateData),
|
Users = get_users_and_subscribers(StateData),
|
||||||
IsOccupant = case LJID of
|
IsOccupant = case LJID of
|
||||||
{LUser, LServer, <<"">>} ->
|
{LUser, LServer, <<"">>} ->
|
||||||
@ -2637,7 +2657,8 @@ send_affiliation(JID, Affiliation, StateData) ->
|
|||||||
role = none},
|
role = none},
|
||||||
Message = #message{id = p1_rand:get_string(),
|
Message = #message{id = p1_rand:get_string(),
|
||||||
sub_els = [#muc_user{items = [Item]}]},
|
sub_els = [#muc_user{items = [Item]}]},
|
||||||
Users = get_users_and_subscribers(StateData),
|
Users = get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_AFFILIATIONS, StateData),
|
||||||
Recipients = case (StateData#state.config)#config.anonymous of
|
Recipients = case (StateData#state.config)#config.anonymous of
|
||||||
true ->
|
true ->
|
||||||
maps:filter(fun(_, #user{role = moderator}) ->
|
maps:filter(fun(_, #user{role = moderator}) ->
|
||||||
@ -3271,6 +3292,13 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
|
|||||||
StateData) ->
|
StateData) ->
|
||||||
#user{jid = RealJID, nick = Nick} = maps:get(jid:tolower(UJID), StateData#state.users),
|
#user{jid = RealJID, nick = Nick} = maps:get(jid:tolower(UJID), StateData#state.users),
|
||||||
ActorNick = get_actor_nick(MJID, StateData),
|
ActorNick = get_actor_nick(MJID, StateData),
|
||||||
|
%% TODO: optimize further
|
||||||
|
UserMap =
|
||||||
|
maps:merge(
|
||||||
|
get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_AFFILIATIONS, StateData),
|
||||||
|
get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_PARTICIPANTS, StateData)),
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(LJID, Info, _) ->
|
fun(LJID, Info, _) ->
|
||||||
IsSelfPresence = jid:tolower(UJID) == LJID,
|
IsSelfPresence = jid:tolower(UJID) == LJID,
|
||||||
@ -3304,7 +3332,7 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
|
|||||||
true ->
|
true ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end, ok, get_users_and_subscribers(StateData)).
|
end, ok, UserMap).
|
||||||
|
|
||||||
-spec get_actor_nick(undefined | jid(), state()) -> binary().
|
-spec get_actor_nick(undefined | jid(), state()) -> binary().
|
||||||
get_actor_nick(undefined, _StateData) ->
|
get_actor_nick(undefined, _StateData) ->
|
||||||
@ -3720,7 +3748,8 @@ send_config_change_info(New, #state{config = Old} = StateData) ->
|
|||||||
id = p1_rand:get_string(),
|
id = p1_rand:get_string(),
|
||||||
sub_els = [#muc_user{status_codes = Codes}]},
|
sub_els = [#muc_user{status_codes = Codes}]},
|
||||||
send_wrapped_multiple(StateData#state.jid,
|
send_wrapped_multiple(StateData#state.jid,
|
||||||
get_users_and_subscribers(StateData),
|
get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_CONFIG, StateData),
|
||||||
Message,
|
Message,
|
||||||
?NS_MUCSUB_NODES_CONFIG,
|
?NS_MUCSUB_NODES_CONFIG,
|
||||||
StateData);
|
StateData);
|
||||||
@ -3872,26 +3901,23 @@ set_opts([{Opt, Val} | Opts], StateData) ->
|
|||||||
StateData#state{config =
|
StateData#state{config =
|
||||||
(StateData#state.config)#config{lang = Val}};
|
(StateData#state.config)#config{lang = Val}};
|
||||||
subscribers ->
|
subscribers ->
|
||||||
{Subscribers, Nicks} =
|
MUCSubscribers =
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun({JID, Nick, Nodes}, {SubAcc, NickAcc}) ->
|
fun({JID, Nick, Nodes}, MUCSubs) ->
|
||||||
BareJID = case JID of
|
BareJID =
|
||||||
|
case JID of
|
||||||
#jid{} -> jid:remove_resource(JID);
|
#jid{} -> jid:remove_resource(JID);
|
||||||
_ ->
|
_ ->
|
||||||
?ERROR_MSG("Invalid subscriber JID in set_opts ~p", [JID]),
|
?ERROR_MSG("Invalid subscriber JID in set_opts ~p", [JID]),
|
||||||
jid:remove_resource(jid:make(JID))
|
jid:remove_resource(jid:make(JID))
|
||||||
end,
|
end,
|
||||||
LBareJID = jid:tolower(BareJID),
|
muc_subscribers_put(
|
||||||
{maps:put(
|
|
||||||
LBareJID,
|
|
||||||
#subscriber{jid = BareJID,
|
#subscriber{jid = BareJID,
|
||||||
nick = Nick,
|
nick = Nick,
|
||||||
nodes = Nodes},
|
nodes = Nodes},
|
||||||
SubAcc),
|
MUCSubs)
|
||||||
maps:put(Nick, [LBareJID], NickAcc)}
|
end, muc_subscribers_new(), Val),
|
||||||
end, {#{}, #{}}, Val),
|
StateData#state{muc_subscribers = MUCSubscribers};
|
||||||
StateData#state{subscribers = Subscribers,
|
|
||||||
subscriber_nicks = Nicks};
|
|
||||||
affiliations ->
|
affiliations ->
|
||||||
StateData#state{affiliations = maps:from_list(Val)};
|
StateData#state{affiliations = maps:from_list(Val)};
|
||||||
subject ->
|
subject ->
|
||||||
@ -3926,12 +3952,12 @@ set_vcard_xupdate(State) ->
|
|||||||
-spec make_opts(state()) -> [{atom(), any()}].
|
-spec make_opts(state()) -> [{atom(), any()}].
|
||||||
make_opts(StateData) ->
|
make_opts(StateData) ->
|
||||||
Config = StateData#state.config,
|
Config = StateData#state.config,
|
||||||
Subscribers = maps:fold(
|
Subscribers = muc_subscribers_fold(
|
||||||
fun(_LJID, Sub, Acc) ->
|
fun(_LJID, Sub, Acc) ->
|
||||||
[{Sub#subscriber.jid,
|
[{Sub#subscriber.jid,
|
||||||
Sub#subscriber.nick,
|
Sub#subscriber.nick,
|
||||||
Sub#subscriber.nodes}|Acc]
|
Sub#subscriber.nodes}|Acc]
|
||||||
end, [], StateData#state.subscribers),
|
end, [], StateData#state.muc_subscribers),
|
||||||
[?MAKE_CONFIG_OPT(#config.title), ?MAKE_CONFIG_OPT(#config.description),
|
[?MAKE_CONFIG_OPT(#config.title), ?MAKE_CONFIG_OPT(#config.description),
|
||||||
?MAKE_CONFIG_OPT(#config.allow_change_subj),
|
?MAKE_CONFIG_OPT(#config.allow_change_subj),
|
||||||
?MAKE_CONFIG_OPT(#config.allow_query_users),
|
?MAKE_CONFIG_OPT(#config.allow_query_users),
|
||||||
@ -4013,7 +4039,8 @@ destroy_room(DEl, StateData) ->
|
|||||||
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
|
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
|
||||||
Info#user.jid, Packet,
|
Info#user.jid, Packet,
|
||||||
?NS_MUCSUB_NODES_CONFIG, StateData)
|
?NS_MUCSUB_NODES_CONFIG, StateData)
|
||||||
end, ok, get_users_and_subscribers(StateData)),
|
end, ok, get_users_and_subscribers_with_node(
|
||||||
|
?NS_MUCSUB_NODES_CONFIG, StateData)),
|
||||||
forget_room(StateData),
|
forget_room(StateData),
|
||||||
{result, undefined, stop}.
|
{result, undefined, stop}.
|
||||||
|
|
||||||
@ -4248,29 +4275,34 @@ process_iq_mucsub(From,
|
|||||||
sub_els = [#muc_subscribe{nick = Nick}]} = Packet,
|
sub_els = [#muc_subscribe{nick = Nick}]} = Packet,
|
||||||
StateData) ->
|
StateData) ->
|
||||||
LBareJID = jid:tolower(jid:remove_resource(From)),
|
LBareJID = jid:tolower(jid:remove_resource(From)),
|
||||||
try maps:get(LBareJID, StateData#state.subscribers) of
|
try muc_subscribers_get(LBareJID, StateData#state.muc_subscribers) of
|
||||||
#subscriber{nick = Nick1} when Nick1 /= Nick ->
|
#subscriber{nick = Nick1} when Nick1 /= Nick ->
|
||||||
Nodes = get_subscription_nodes(Packet),
|
Nodes = get_subscription_nodes(Packet),
|
||||||
case {nick_collision(From, Nick, StateData),
|
case nick_collision(From, Nick, StateData) of
|
||||||
mod_muc:can_use_nick(StateData#state.server_host,
|
true ->
|
||||||
StateData#state.host,
|
|
||||||
From, Nick)} of
|
|
||||||
{true, _} ->
|
|
||||||
ErrText = ?T("That nickname is already in use by another occupant"),
|
ErrText = ?T("That nickname is already in use by another occupant"),
|
||||||
{error, xmpp:err_conflict(ErrText, Lang)};
|
{error, xmpp:err_conflict(ErrText, Lang)};
|
||||||
{_, false} ->
|
false ->
|
||||||
|
case mod_muc:can_use_nick(StateData#state.server_host,
|
||||||
|
StateData#state.host,
|
||||||
|
From, Nick) of
|
||||||
|
false ->
|
||||||
Err = case Nick of
|
Err = case Nick of
|
||||||
<<>> ->
|
<<>> ->
|
||||||
xmpp:err_jid_malformed(?T("Nickname can't be empty"),
|
xmpp:err_jid_malformed(
|
||||||
|
?T("Nickname can't be empty"),
|
||||||
Lang);
|
Lang);
|
||||||
_ ->
|
_ ->
|
||||||
xmpp:err_conflict(?T("That nickname is registered"
|
xmpp:err_conflict(
|
||||||
|
?T("That nickname is registered"
|
||||||
" by another person"), Lang)
|
" by another person"), Lang)
|
||||||
end,
|
end,
|
||||||
{error, Err};
|
{error, Err};
|
||||||
_ ->
|
true ->
|
||||||
NewStateData = set_subscriber(From, Nick, Nodes, StateData),
|
NewStateData =
|
||||||
|
set_subscriber(From, Nick, Nodes, StateData),
|
||||||
{result, subscribe_result(Packet), NewStateData}
|
{result, subscribe_result(Packet), NewStateData}
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
#subscriber{} ->
|
#subscriber{} ->
|
||||||
Nodes = get_subscription_nodes(Packet),
|
Nodes = get_subscription_nodes(Packet),
|
||||||
@ -4298,12 +4330,9 @@ process_iq_mucsub(From, #iq{type = set, sub_els = [#muc_unsubscribe{}]},
|
|||||||
#state{room = Room, host = Host, server_host = ServerHost} = StateData) ->
|
#state{room = Room, host = Host, server_host = ServerHost} = StateData) ->
|
||||||
BareJID = jid:remove_resource(From),
|
BareJID = jid:remove_resource(From),
|
||||||
LBareJID = jid:tolower(BareJID),
|
LBareJID = jid:tolower(BareJID),
|
||||||
try maps:get(LBareJID, StateData#state.subscribers) of
|
try muc_subscribers_remove_exn(LBareJID, StateData#state.muc_subscribers) of
|
||||||
#subscriber{nick = Nick} ->
|
{MUCSubscribers, #subscriber{nick = Nick}} ->
|
||||||
Nicks = maps:remove(Nick, StateData#state.subscriber_nicks),
|
NewStateData = StateData#state{muc_subscribers = MUCSubscribers},
|
||||||
Subscribers = maps:remove(LBareJID, StateData#state.subscribers),
|
|
||||||
NewStateData = StateData#state{subscribers = Subscribers,
|
|
||||||
subscriber_nicks = Nicks},
|
|
||||||
store_room(NewStateData, [{del_subscription, LBareJID}]),
|
store_room(NewStateData, [{del_subscription, LBareJID}]),
|
||||||
send_subscriptions_change_notifications(BareJID, Nick, unsubscribe, StateData),
|
send_subscriptions_change_notifications(BareJID, Nick, unsubscribe, StateData),
|
||||||
ejabberd_hooks:run(muc_unsubscribed, ServerHost, [ServerHost, Room, Host, BareJID]),
|
ejabberd_hooks:run(muc_unsubscribed, ServerHost, [ServerHost, Room, Host, BareJID]),
|
||||||
@ -4326,7 +4355,7 @@ process_iq_mucsub(From, #iq{type = get, lang = Lang,
|
|||||||
true ->
|
true ->
|
||||||
ShowJid = IsModerator orelse
|
ShowJid = IsModerator orelse
|
||||||
(StateData#state.config)#config.anonymous == false,
|
(StateData#state.config)#config.anonymous == false,
|
||||||
Subs = maps:fold(
|
Subs = muc_subscribers_fold(
|
||||||
fun(_, #subscriber{jid = J, nick = N, nodes = Nodes}, Acc) ->
|
fun(_, #subscriber{jid = J, nick = N, nodes = Nodes}, Acc) ->
|
||||||
case ShowJid of
|
case ShowJid of
|
||||||
true ->
|
true ->
|
||||||
@ -4334,7 +4363,7 @@ process_iq_mucsub(From, #iq{type = get, lang = Lang,
|
|||||||
_ ->
|
_ ->
|
||||||
[#muc_subscription{nick = N, events = Nodes}|Acc]
|
[#muc_subscription{nick = N, events = Nodes}|Acc]
|
||||||
end
|
end
|
||||||
end, [], StateData#state.subscribers),
|
end, [], StateData#state.muc_subscribers),
|
||||||
{result, #muc_subscriptions{list = Subs}, StateData};
|
{result, #muc_subscriptions{list = Subs}, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
Txt = ?T("Moderator privileges required"),
|
Txt = ?T("Moderator privileges required"),
|
||||||
@ -4347,8 +4376,7 @@ process_iq_mucsub(_From, #iq{type = get, lang = Lang}, _StateData) ->
|
|||||||
-spec remove_subscriptions(state()) -> state().
|
-spec remove_subscriptions(state()) -> state().
|
||||||
remove_subscriptions(StateData) ->
|
remove_subscriptions(StateData) ->
|
||||||
if not (StateData#state.config)#config.allow_subscription ->
|
if not (StateData#state.config)#config.allow_subscription ->
|
||||||
StateData#state{subscribers = #{},
|
StateData#state{muc_subscribers = muc_subscribers_new()};
|
||||||
subscriber_nicks = #{}};
|
|
||||||
true ->
|
true ->
|
||||||
StateData
|
StateData
|
||||||
end.
|
end.
|
||||||
@ -4597,7 +4625,7 @@ store_room(StateData, ChangesHints) ->
|
|||||||
true ->
|
true ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
erlang:put(muc_subscribers, StateData#state.subscribers)
|
erlang:put(muc_subscribers, StateData#state.muc_subscribers#muc_subscribers.subscribers)
|
||||||
end,
|
end,
|
||||||
ShouldStore = case (StateData#state.config)#config.persistent of
|
ShouldStore = case (StateData#state.config)#config.persistent of
|
||||||
true ->
|
true ->
|
||||||
@ -4611,7 +4639,15 @@ store_room(StateData, ChangesHints) ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
if ShouldStore ->
|
if ShouldStore ->
|
||||||
store_room_no_checks(StateData, ChangesHints);
|
case erlang:function_exported(Mod, store_changes, 4) of
|
||||||
|
true when ChangesHints /= [] ->
|
||||||
|
mod_muc:store_changes(
|
||||||
|
StateData#state.server_host,
|
||||||
|
StateData#state.host, StateData#state.room,
|
||||||
|
ChangesHints);
|
||||||
|
_ ->
|
||||||
|
store_room_no_checks(StateData, ChangesHints)
|
||||||
|
end;
|
||||||
true ->
|
true ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
@ -4626,9 +4662,7 @@ store_room_no_checks(StateData, ChangesHints) ->
|
|||||||
send_subscriptions_change_notifications(From, Nick, Type, State) ->
|
send_subscriptions_change_notifications(From, Nick, Type, State) ->
|
||||||
{WJ, WN} =
|
{WJ, WN} =
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(_, #subscriber{nodes = Nodes, jid = JID}, {WithJid, WithNick} = Res) ->
|
fun(_, #subscriber{jid = JID}, {WithJid, WithNick}) ->
|
||||||
case lists:member(?NS_MUCSUB_NODES_SUBSCRIBERS, Nodes) of
|
|
||||||
true ->
|
|
||||||
case (State#state.config)#config.anonymous == false orelse
|
case (State#state.config)#config.anonymous == false orelse
|
||||||
get_role(JID, State) == moderator orelse
|
get_role(JID, State) == moderator orelse
|
||||||
get_default_role(get_affiliation(JID, State), State) == moderator of
|
get_default_role(get_affiliation(JID, State), State) == moderator of
|
||||||
@ -4636,11 +4670,10 @@ send_subscriptions_change_notifications(From, Nick, Type, State) ->
|
|||||||
{[JID | WithJid], WithNick};
|
{[JID | WithJid], WithNick};
|
||||||
_ ->
|
_ ->
|
||||||
{WithJid, [JID | WithNick]}
|
{WithJid, [JID | WithNick]}
|
||||||
end;
|
|
||||||
false ->
|
|
||||||
Res
|
|
||||||
end
|
end
|
||||||
end, {[], []}, State#state.subscribers),
|
end, {[], []},
|
||||||
|
muc_subscribers_get_by_node(?NS_MUCSUB_NODES_SUBSCRIBERS,
|
||||||
|
State#state.muc_subscribers)),
|
||||||
if WJ /= [] ->
|
if WJ /= [] ->
|
||||||
Payload1 = case Type of
|
Payload1 = case Type of
|
||||||
subscribe -> #muc_subscribe{jid = From, nick = Nick};
|
subscribe -> #muc_subscribe{jid = From, nick = Nick};
|
||||||
@ -4684,7 +4717,7 @@ send_wrapped(From, To, Packet, Node, State) ->
|
|||||||
_ -> false
|
_ -> false
|
||||||
end,
|
end,
|
||||||
if IsOffline ->
|
if IsOffline ->
|
||||||
try maps:get(LBareTo, State#state.subscribers) of
|
try muc_subscribers_get(LBareTo, State#state.muc_subscribers) of
|
||||||
#subscriber{nodes = Nodes, jid = JID} ->
|
#subscriber{nodes = Nodes, jid = JID} ->
|
||||||
case lists:member(Node, Nodes) of
|
case lists:member(Node, Nodes) of
|
||||||
true ->
|
true ->
|
||||||
@ -4751,12 +4784,13 @@ send_wrapped_multiple(From, Users, Packet, Node, State) ->
|
|||||||
IsOffline = LP == undefined,
|
IsOffline = LP == undefined,
|
||||||
if IsOffline ->
|
if IsOffline ->
|
||||||
LBareTo = jid:tolower(jid:remove_resource(To)),
|
LBareTo = jid:tolower(jid:remove_resource(To)),
|
||||||
case maps:find(LBareTo, State#state.subscribers) of
|
case muc_subscribers_find(LBareTo, State#state.muc_subscribers) of
|
||||||
{ok, #subscriber{nodes = Nodes}} ->
|
{ok, #subscriber{nodes = Nodes}} ->
|
||||||
case lists:member(Node, Nodes) of
|
case lists:member(Node, Nodes) of
|
||||||
true ->
|
true ->
|
||||||
{Direct, [To | Wrapped]};
|
{Direct, [To | Wrapped]};
|
||||||
_ ->
|
_ ->
|
||||||
|
%% TODO: check that this branch is never called
|
||||||
Res
|
Res
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
@ -4810,6 +4844,90 @@ send_wrapped_multiple(From, Users, Packet, Node, State) ->
|
|||||||
Wra, NewPacket2, true)
|
Wra, NewPacket2, true)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% #muc_subscribers API
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-spec muc_subscribers_new() -> #muc_subscribers{}.
|
||||||
|
muc_subscribers_new() ->
|
||||||
|
#muc_subscribers{}.
|
||||||
|
|
||||||
|
-spec muc_subscribers_get(ljid(), #muc_subscribers{}) -> #subscriber{}.
|
||||||
|
muc_subscribers_get({_, _, _} = LJID, MUCSubscribers) ->
|
||||||
|
maps:get(LJID, MUCSubscribers#muc_subscribers.subscribers).
|
||||||
|
|
||||||
|
-spec muc_subscribers_find(ljid(), #muc_subscribers{}) ->
|
||||||
|
{ok, #subscriber{}} | error.
|
||||||
|
muc_subscribers_find({_, _, _} = LJID, MUCSubscribers) ->
|
||||||
|
maps:find(LJID, MUCSubscribers#muc_subscribers.subscribers).
|
||||||
|
|
||||||
|
-spec muc_subscribers_is_key(ljid(), #muc_subscribers{}) -> boolean().
|
||||||
|
muc_subscribers_is_key({_, _, _} = LJID, MUCSubscribers) ->
|
||||||
|
maps:is_key(LJID, MUCSubscribers#muc_subscribers.subscribers).
|
||||||
|
|
||||||
|
-spec muc_subscribers_size(#muc_subscribers{}) -> integer().
|
||||||
|
muc_subscribers_size(MUCSubscribers) ->
|
||||||
|
maps:size(MUCSubscribers#muc_subscribers.subscribers).
|
||||||
|
|
||||||
|
-spec muc_subscribers_fold(Fun, Acc, #muc_subscribers{}) -> Acc when
|
||||||
|
Fun :: fun((ljid(), #subscriber{}, Acc) -> Acc).
|
||||||
|
muc_subscribers_fold(Fun, Init, MUCSubscribers) ->
|
||||||
|
maps:fold(Fun, Init, MUCSubscribers#muc_subscribers.subscribers).
|
||||||
|
|
||||||
|
-spec muc_subscribers_get_by_nick(binary(), #muc_subscribers{}) -> [#subscriber{}].
|
||||||
|
muc_subscribers_get_by_nick(Nick, MUCSubscribers) ->
|
||||||
|
maps:get(Nick, MUCSubscribers#muc_subscribers.subscriber_nicks, []).
|
||||||
|
|
||||||
|
-spec muc_subscribers_get_by_node(binary(), #muc_subscribers{}) -> subscribers().
|
||||||
|
muc_subscribers_get_by_node(Node, MUCSubscribers) ->
|
||||||
|
maps:get(Node, MUCSubscribers#muc_subscribers.subscriber_nodes, #{}).
|
||||||
|
|
||||||
|
-spec muc_subscribers_remove_exn(ljid(), #muc_subscribers{}) ->
|
||||||
|
{#muc_subscribers{}, #subscriber{}}.
|
||||||
|
muc_subscribers_remove_exn({_, _, _} = LJID, MUCSubscribers) ->
|
||||||
|
#muc_subscribers{subscribers = Subs,
|
||||||
|
subscriber_nicks = SubNicks,
|
||||||
|
subscriber_nodes = SubNodes} = MUCSubscribers,
|
||||||
|
Subscriber = maps:get(LJID, Subs),
|
||||||
|
#subscriber{nick = Nick, nodes = Nodes} = Subscriber,
|
||||||
|
NewSubNicks = maps:remove(Nick, SubNicks),
|
||||||
|
NewSubs = maps:remove(LJID, Subs),
|
||||||
|
NewSubNodes =
|
||||||
|
lists:foldl(
|
||||||
|
fun(Node, Acc) ->
|
||||||
|
NodeSubs = maps:get(Node, Acc, #{}),
|
||||||
|
NodeSubs2 = maps:remove(LJID, NodeSubs),
|
||||||
|
maps:put(Node, NodeSubs2, Acc)
|
||||||
|
end, SubNodes, Nodes),
|
||||||
|
{#muc_subscribers{subscribers = NewSubs,
|
||||||
|
subscriber_nicks = NewSubNicks,
|
||||||
|
subscriber_nodes = NewSubNodes}, Subscriber}.
|
||||||
|
|
||||||
|
-spec muc_subscribers_put(#subscriber{}, #muc_subscribers{}) ->
|
||||||
|
#muc_subscribers{}.
|
||||||
|
muc_subscribers_put(Subscriber, MUCSubscribers) ->
|
||||||
|
#subscriber{jid = JID,
|
||||||
|
nick = Nick,
|
||||||
|
nodes = Nodes} = Subscriber,
|
||||||
|
#muc_subscribers{subscribers = Subs,
|
||||||
|
subscriber_nicks = SubNicks,
|
||||||
|
subscriber_nodes = SubNodes} = MUCSubscribers,
|
||||||
|
LJID = jid:tolower(JID),
|
||||||
|
NewSubs = maps:put(LJID, Subscriber, Subs),
|
||||||
|
NewSubNicks = maps:put(Nick, [LJID], SubNicks),
|
||||||
|
NewSubNodes =
|
||||||
|
lists:foldl(
|
||||||
|
fun(Node, Acc) ->
|
||||||
|
NodeSubs = maps:get(Node, Acc, #{}),
|
||||||
|
NodeSubs2 = maps:put(LJID, Subscriber, NodeSubs),
|
||||||
|
maps:put(Node, NodeSubs2, Acc)
|
||||||
|
end, SubNodes, Nodes),
|
||||||
|
#muc_subscribers{subscribers = NewSubs,
|
||||||
|
subscriber_nicks = NewSubNicks,
|
||||||
|
subscriber_nodes = NewSubNodes}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% Detect messange stanzas that don't have meaningful content
|
%% Detect messange stanzas that don't have meaningful content
|
||||||
-spec has_body_or_subject(message()) -> boolean().
|
-spec has_body_or_subject(message()) -> boolean().
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
-behaviour(mod_muc_room).
|
-behaviour(mod_muc_room).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([init/2, store_room/5, restore_room/3, forget_room/3,
|
-export([init/2, store_room/5, store_changes/4,
|
||||||
|
restore_room/3, forget_room/3,
|
||||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
|
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
|
||||||
import/3, export/1]).
|
import/3, export/1]).
|
||||||
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
|
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
|
||||||
@ -83,6 +84,12 @@ store_room(LServer, Host, Name, Opts, ChangesHints) ->
|
|||||||
end,
|
end,
|
||||||
ejabberd_sql:sql_transaction(LServer, F).
|
ejabberd_sql:sql_transaction(LServer, F).
|
||||||
|
|
||||||
|
store_changes(LServer, Host, Name, Changes) ->
|
||||||
|
F = fun () ->
|
||||||
|
[change_room(Host, Name, Change) || Change <- Changes]
|
||||||
|
end,
|
||||||
|
ejabberd_sql:sql_transaction(LServer, F).
|
||||||
|
|
||||||
change_room(Host, Room, {add_subscription, JID, Nick, Nodes}) ->
|
change_room(Host, Room, {add_subscription, JID, Nick, Nodes}) ->
|
||||||
SJID = jid:encode(JID),
|
SJID = jid:encode(JID),
|
||||||
SNodes = misc:term_to_expr(Nodes),
|
SNodes = misc:term_to_expr(Nodes),
|
||||||
@ -185,13 +192,20 @@ get_rooms(LServer, Host) ->
|
|||||||
{selected, Subs} ->
|
{selected, Subs} ->
|
||||||
SubsD = lists:foldl(
|
SubsD = lists:foldl(
|
||||||
fun({Room, Jid, Nick, Nodes}, Dict) ->
|
fun({Room, Jid, Nick, Nodes}, Dict) ->
|
||||||
dict:append(Room, {jid:decode(Jid),
|
Sub = {jid:decode(Jid),
|
||||||
Nick, ejabberd_sql:decode_term(Nodes)}, Dict)
|
Nick, ejabberd_sql:decode_term(Nodes)},
|
||||||
end, dict:new(), Subs),
|
maps:update_with(
|
||||||
|
Room,
|
||||||
|
fun(SubAcc) ->
|
||||||
|
[Sub | SubAcc]
|
||||||
|
end,
|
||||||
|
[Sub],
|
||||||
|
Dict)
|
||||||
|
end, maps:new(), Subs),
|
||||||
lists:map(
|
lists:map(
|
||||||
fun({Room, Opts}) ->
|
fun({Room, Opts}) ->
|
||||||
OptsD = ejabberd_sql:decode_term(Opts),
|
OptsD = ejabberd_sql:decode_term(Opts),
|
||||||
OptsD2 = case {dict:find(Room, SubsD), lists:keymember(subscribers, 1, OptsD)} of
|
OptsD2 = case {maps:find(Room, SubsD), lists:keymember(subscribers, 1, OptsD)} of
|
||||||
{_, true} ->
|
{_, true} ->
|
||||||
store_room(LServer, Host, Room, mod_muc:opts_to_binary(OptsD), undefined),
|
store_room(LServer, Host, Room, mod_muc:opts_to_binary(OptsD), undefined),
|
||||||
OptsD;
|
OptsD;
|
||||||
|
Loading…
Reference in New Issue
Block a user