From 9cbc0685db892cc22c090b28e357d1fa83a370a0 Mon Sep 17 00:00:00 2001 From: Evgeny Khramtsov Date: Tue, 9 Jul 2019 00:47:54 +0300 Subject: [PATCH] Don't expose internal FSM API of mod_muc_room --- src/mod_muc.erl | 43 ++++++-------- src/mod_muc_admin.erl | 29 ++++------ src/mod_muc_log.erl | 5 +- src/mod_muc_room.erl | 132 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 159 insertions(+), 50 deletions(-) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 34b8a7ba1..8ecdda0e8 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -164,7 +164,7 @@ reload(ServerHost, NewOpts, OldOpts) -> fun(Host) -> lists:foreach( fun({_, _, Pid}) when node(Pid) == node() -> - Pid ! config_reloaded; + mod_muc_room:config_reloaded(Pid); (_) -> ok end, get_online_rooms(ServerHost, Host)) @@ -271,7 +271,7 @@ shutdown_rooms(ServerHost, Hosts, RMod) -> || Host <- Hosts], lists:flatmap( fun({_, _, Pid}) when node(Pid) == node() -> - Pid ! shutdown, + mod_muc_room:shutdown(Pid), [Pid]; (_) -> [] @@ -840,13 +840,13 @@ iq_disco_items(ServerHost, Host, From, Lang, MaxRoomsDiscoItems, Node, RSM) when Node == <<"">>; Node == <<"nonemptyrooms">>; Node == <<"emptyrooms">> -> Count = count_online_rooms(ServerHost, Host), Query = if Node == <<"">>, RSM == undefined, Count > MaxRoomsDiscoItems -> - {get_disco_item, only_non_empty, From, Lang}; + {only_non_empty, From, Lang}; Node == <<"nonemptyrooms">> -> - {get_disco_item, only_non_empty, From, Lang}; + {only_non_empty, From, Lang}; Node == <<"emptyrooms">> -> - {get_disco_item, 0, From, Lang}; + {0, From, Lang}; true -> - {get_disco_item, all, From, Lang} + {all, From, Lang} end, MaxItems = case RSM of undefined -> @@ -884,23 +884,16 @@ iq_disco_items(_ServerHost, _Host, _From, Lang, _MaxRoomsDiscoItems, _Node, _RSM {error, xmpp:err_item_not_found(?T("Node not found"), Lang)}. -spec get_room_disco_item({binary(), binary(), pid()}, - term()) -> {ok, disco_item()} | - {error, timeout | notfound}. -get_room_disco_item({Name, Host, Pid}, - {get_disco_item, Filter, JID, Lang}) -> - RoomJID = jid:make(Name, Host), - Timeout = 100, - Time = erlang:system_time(millisecond), - Query1 = {get_disco_item, Filter, JID, Lang, Time+Timeout}, - try p1_fsm:sync_send_all_state_event(Pid, Query1, Timeout) of - {item, Desc} -> + {mod_muc_room:disco_item_filter(), + jid(), binary()}) -> {ok, disco_item()} | + {error, timeout | notfound}. +get_room_disco_item({Name, Host, Pid}, {Filter, JID, Lang}) -> + case mod_muc_room:get_disco_item(Pid, Filter, JID, Lang) of + {ok, Desc} -> + RoomJID = jid:make(Name, Host), {ok, #disco_item{jid = RoomJID, name = Desc}}; - false -> - {error, notfound} - catch _:{timeout, {p1_fsm, _, _}} -> - {error, timeout}; - _:{_, {p1_fsm, _, _}} -> - {error, notfound} + {error, _} = Err -> + Err end. -spec get_subscribed_rooms(binary(), jid()) -> {ok, [{jid(), [binary()]}]} | {error, any()}. @@ -931,8 +924,7 @@ get_subscribed_rooms(ServerHost, Host, From) -> [] end; ({Name, _, Pid}) -> - case p1_fsm:sync_send_all_state_event( - Pid, {is_subscribed, BareFrom}) of + case mod_muc_room:is_subscribed(Pid, BareFrom) of {true, Nodes} -> [{jid:make(Name, Host), Nodes}]; false -> [] @@ -1017,8 +1009,7 @@ process_iq_register_set(ServerHost, Host, From, broadcast_service_message(ServerHost, Host, Msg) -> lists:foreach( fun({_, _, Pid}) -> - p1_fsm:send_all_state_event( - Pid, {service_message, Msg}) + mod_muc_room:service_message(Pid, Msg) end, get_online_rooms(ServerHost, Host)). -spec get_online_rooms(binary(), binary()) -> [{binary(), binary(), pid()}]. diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 422dc075b..beef3bc04 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -673,8 +673,7 @@ muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) -> destroy_room(Name, Service) -> case mod_muc:find_online_room(Name, Service) of {ok, Pid} -> - p1_fsm:send_all_state_event(Pid, destroy), - ok; + mod_muc_room:destroy(Pid); error -> error end. @@ -793,11 +792,11 @@ get_rooms(ServerHost) -> end, Hosts). get_room_config(Room_pid) -> - {ok, R} = p1_fsm:sync_send_all_state_event(Room_pid, get_config), + {ok, R} = mod_muc_room:get_config(Room_pid), R. get_room_state(Room_pid) -> - {ok, R} = p1_fsm:sync_send_all_state_event(Room_pid, get_state), + {ok, R} = mod_muc_room:get_state(Room_pid), R. %%--------------- @@ -882,8 +881,7 @@ find_serverhost(Host, ServerHosts) -> act_on_room(Method, destroy, {N, H, Pid}, SH) -> Message = iolist_to_binary(io_lib:format( <<"Room destroyed by rooms_~s_destroy.">>, [Method])), - p1_fsm:send_all_state_event( - Pid, {destroy, Message}), + mod_muc_room:destroy(Pid, Message), mod_muc:room_destroyed(H, N, Pid, SH), mod_muc:forget_room(SH, H, N); @@ -991,7 +989,7 @@ change_room_option(Name, Service, OptionString, ValueString) -> {Option, Value} = format_room_option(OptionString, ValueString), Config = get_room_config(Pid), Config2 = change_option(Option, Value, Config), - {ok, _} = p1_fsm:sync_send_all_state_event(Pid, {change_config, Config2}), + {ok, _} = mod_muc_room:set_config(Pid, Config2), ok end. @@ -1093,7 +1091,7 @@ get_room_affiliations(Name, Service) -> case mod_muc:find_online_room(Name, Service) of {ok, Pid} -> %% Get the PID of the online room, then request its state - {ok, StateData} = p1_fsm:sync_send_all_state_event(Pid, get_state), + {ok, StateData} = mod_muc_room:get_state(Pid), Affiliations = maps:to_list(StateData#state.affiliations), lists:map( fun({{Uname, Domain, _Res}, {Aff, Reason}}) when is_atom(Aff)-> @@ -1117,7 +1115,7 @@ get_room_affiliation(Name, Service, JID) -> case mod_muc:find_online_room(Name, Service) of {ok, Pid} -> %% Get the PID of the online room, then request its state - {ok, StateData} = p1_fsm:sync_send_all_state_event(Pid, get_state), + {ok, StateData} = mod_muc_room:get_state(Pid), UserJID = jid:decode(JID), mod_muc_room:get_affiliation(UserJID, StateData); error -> @@ -1141,7 +1139,7 @@ set_room_affiliation(Name, Service, JID, AffiliationString) -> case mod_muc:find_online_room(Name, Service) of {ok, Pid} -> %% Get the PID for the online room so we can get the state of the room - {ok, StateData} = p1_fsm:sync_send_all_state_event(Pid, {process_item_change, {jid:decode(JID), affiliation, Affiliation, <<"">>}, undefined}), + {ok, StateData} = mod_muc_room:change_item(Pid, jid:decode(JID), affiliation, Affiliation, <<"">>), mod_muc:store_room(StateData#state.server_host, StateData#state.host, StateData#state.room, make_opts(StateData)), ok; error -> @@ -1163,9 +1161,8 @@ subscribe_room(User, Nick, Room, Nodes) -> UserJID = jid:replace_resource(UserJID1, <<"modmucadmin">>), case get_room_pid(Name, Host) of Pid when is_pid(Pid) -> - case p1_fsm:sync_send_all_state_event( - Pid, - {muc_subscribe, UserJID, Nick, NodeList}) of + case mod_muc_room:subscribe( + Pid, UserJID, Nick, NodeList) of {ok, SubscribedNodes} -> SubscribedNodes; {error, Reason} -> @@ -1190,9 +1187,7 @@ unsubscribe_room(User, Room) -> UserJID -> case get_room_pid(Name, Host) of Pid when is_pid(Pid) -> - case p1_fsm:sync_send_all_state_event( - Pid, - {muc_unsubscribe, UserJID}) of + case mod_muc_room:unsubscribe(Pid, UserJID) of ok -> ok; {error, Reason} -> @@ -1213,7 +1208,7 @@ unsubscribe_room(User, Room) -> get_subscribers(Name, Host) -> case get_room_pid(Name, Host) of Pid when is_pid(Pid) -> - {ok, JIDList} = p1_fsm:sync_send_all_state_event(Pid, get_subscribers), + {ok, JIDList} = mod_muc_room:get_subscribers(Pid), [jid:encode(jid:remove_resource(J)) || J <- JIDList]; _ -> throw({error, "The room does not exist"}) diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index 79d31c360..8c5af42c3 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -896,8 +896,9 @@ get_room_state(RoomName, MucService) -> -spec get_room_state(pid()) -> {ok, mod_muc_room:state()} | error. get_room_state(RoomPid) -> - try p1_fsm:sync_send_all_state_event(RoomPid, get_state) - catch _:_ -> error + case mod_muc_room:get_state(RoomPid) of + {ok, State} -> {ok, State}; + {error, _} -> error end. get_proc_name(Host) -> diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index f83210606..718038470 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -39,7 +39,21 @@ is_occupant_or_admin/2, route/2, expand_opts/1, - config_fields/0]). + config_fields/0, + destroy/1, + destroy/2, + shutdown/1, + get_config/1, + set_config/2, + get_state/1, + change_item/5, + config_reloaded/1, + subscribe/4, + unsubscribe/2, + is_subscribed/2, + get_subscribers/1, + service_message/2, + get_disco_item/4]). %% gen_fsm callbacks -export([init/1, @@ -77,8 +91,8 @@ -type fsm_stop() :: {stop, normal, state()}. -type fsm_next() :: {next_state, normal_state, state()}. -type fsm_transition() :: fsm_stop() | fsm_next(). - --export_type([state/0]). +-type disco_item_filter() :: only_non_empty | all | non_neg_integer(). +-export_type([state/0, disco_item_filter/0]). -callback set_affiliation(binary(), binary(), binary(), jid(), affiliation(), binary()) -> ok | {error, any()}. @@ -127,6 +141,114 @@ start_link(Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts, QueueT RoomShaper, Opts, QueueType], ?FSMOPTS). +-spec destroy(pid()) -> ok. +destroy(Pid) -> + p1_fsm:send_all_state_event(Pid, destroy). + +-spec destroy(pid(), binary()) -> ok. +destroy(Pid, Reason) -> + p1_fsm:send_all_state_event(Pid, {destroy, Reason}). + +-spec shutdown(pid()) -> boolean(). +shutdown(Pid) -> + ejabberd_cluster:send(Pid, shutdown). + +-spec config_reloaded(pid()) -> boolean(). +config_reloaded(Pid) -> + ejabberd_cluster:send(Pid, config_reloaded). + +-spec get_config(pid()) -> {ok, config()} | {error, notfound | timeout}. +get_config(Pid) -> + try p1_fsm:sync_send_all_state_event(Pid, get_config) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, timeout}; + _:{_, {p1_fsm, _, _}} -> + {error, notfound} + end. + +-spec set_config(pid(), config()) -> {ok, config()} | {error, notfound | timeout}. +set_config(Pid, Config) -> + try p1_fsm:sync_send_all_state_event(Pid, {change_config, Config}) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, timeout}; + _:{_, {p1_fsm, _, _}} -> + {error, notfound} + end. + +-spec change_item(pid(), jid(), affiliation | role, affiliation() | role(), binary()) -> + {ok, state()} | {error, notfound | timeout}. +change_item(Pid, JID, Type, AffiliationOrRole, Reason) -> + try p1_fsm:sync_send_all_state_event( + Pid, {process_item_change, {JID, Type, AffiliationOrRole, Reason}, undefined}) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, timeout}; + _:{_, {p1_fsm, _, _}} -> + {error, notfound} + end. + +-spec get_state(pid()) -> {ok, state()} | {error, notfound | timeout}. +get_state(Pid) -> + try p1_fsm:sync_send_all_state_event(Pid, get_state) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, timeout}; + _:{_, {p1_fsm, _, _}} -> + {error, notfound} + end. + +-spec subscribe(pid(), jid(), binary(), [binary()]) -> {ok, [binary()]} | {error, binary()}. +subscribe(Pid, JID, Nick, Nodes) -> + try p1_fsm:sync_send_all_state_event(Pid, {muc_subscribe, JID, Nick, Nodes}) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, ?T("Request has timed out")}; + _:{_, {p1_fsm, _, _}} -> + {error, ?T("Conference room does not exist")} + end. + +-spec unsubscribe(pid(), jid()) -> ok | {error, binary()}. +unsubscribe(Pid, JID) -> + try p1_fsm:sync_send_all_state_event(Pid, {muc_unsubscribe, JID}) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, ?T("Request has timed out")}; + _:{_, {p1_fsm, _, _}} -> + {error, ?T("Conference room does not exist")} + end. + +-spec is_subscribed(pid(), jid()) -> {true, [binary()]} | false. +is_subscribed(Pid, JID) -> + try p1_fsm:sync_send_all_state_event(Pid, {is_subscribed, JID}) + catch _:{_, {p1_fsm, _, _}} -> false + end. + +-spec get_subscribers(pid()) -> {ok, [jid()]} | {error, notfound | timeout}. +get_subscribers(Pid) -> + try p1_fsm:sync_send_all_state_event(Pid, get_subscribers) + catch _:{timeout, {p1_fsm, _, _}} -> + {error, timeout}; + _:{_, {p1_fsm, _, _}} -> + {error, notfound} + end. + +-spec service_message(pid(), binary()) -> ok. +service_message(Pid, Text) -> + p1_fsm:send_all_state_event(Pid, {service_message, Text}). + +-spec get_disco_item(pid(), disco_item_filter(), jid(), binary()) -> + {ok, binary()} | {error, notfound | timeout}. +get_disco_item(Pid, Filter, JID, Lang) -> + Timeout = 100, + Time = erlang:system_time(millisecond), + Query = {get_disco_item, Filter, JID, Lang, Time+Timeout}, + try p1_fsm:sync_send_all_state_event(Pid, Query, Timeout) of + {item, Desc} -> + {ok, Desc}; + false -> + {error, notfound} + catch _:{timeout, {p1_fsm, _, _}} -> + {error, timeout}; + _:{_, {p1_fsm, _, _}} -> + {error, notfound} + end. + %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -593,7 +715,7 @@ handle_sync_event({muc_subscribe, From, Nick, Nodes}, _From, NewConfig = (NewState#state.config)#config{ captcha_protected = CaptchaRequired, password_protected = PasswordProtected}, - {reply, {error, <<"Request is ignored">>}, + {reply, {error, ?T("Request is ignored")}, NewState#state{config = NewConfig}}; {error, Err} -> {reply, {error, get_error_text(Err)}, StateName, StateData} @@ -605,7 +727,7 @@ handle_sync_event({muc_unsubscribe, From}, _From, StateName, StateData) -> {result, _, NewState} -> {reply, ok, StateName, NewState}; {ignore, NewState} -> - {reply, {error, <<"Request is ignored">>}, NewState}; + {reply, {error, ?T("Request is ignored")}, NewState}; {error, Err} -> {reply, {error, get_error_text(Err)}, StateName, StateData} end;