diff --git a/src/mod_muc.erl b/src/mod_muc.erl index b256c726d..80fb7d9e3 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -42,6 +42,7 @@ store_room/5, restore_room/3, forget_room/3, + create_room/3, create_room/5, shutdown_rooms/1, process_disco_info/1, @@ -99,6 +100,7 @@ -callback register_online_room(binary(), binary(), binary(), pid()) -> any(). -callback unregister_online_room(binary(), binary(), binary(), pid()) -> any(). -callback find_online_room(binary(), binary(), binary()) -> {ok, pid()} | error. +-callback find_online_room_by_pid(binary(), pid()) -> {ok, binary(), binary()} | error. -callback get_online_rooms(binary(), binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}]. -callback count_online_rooms(binary(), binary()) -> non_neg_integer(). -callback rsm_supported() -> boolean(). @@ -295,6 +297,14 @@ create_room(Host, Name, From, Nick, Opts) -> Proc = procname(ServerHost, {Name, Host}), ?GEN_SERVER:call(Proc, {create, Name, Host, From, Nick, Opts}). +%% @doc Create a room. +%% If Opts = default, the default room options are used. +%% Else use the passed options as defined in mod_muc_room. +create_room(Host, Name, Opts) -> + ServerHost = ejabberd_router:host_of_route(Host), + Proc = procname(ServerHost, {Name, Host}), + ?GEN_SERVER:call(Proc, {create, Name, Host, Opts}). + store_room(ServerHost, Host, Name, Opts) -> store_room(ServerHost, Host, Name, Opts, undefined). @@ -379,6 +389,25 @@ init([Host, Worker]) -> {stop, normal, ok, state()}. handle_call(stop, _From, State) -> {stop, normal, ok, State}; +handle_call({unhibernate, Room, Host}, _From, + #{server_host := ServerHost} = State) -> + RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), + {reply, load_room(RMod, Host, ServerHost, Room), State}; +handle_call({create, Room, Host, Opts}, _From, + #{server_host := ServerHost} = State) -> + ?DEBUG("MUC: create new room '~ts'~n", [Room]), + NewOpts = case Opts of + default -> mod_muc_opt:default_room_options(ServerHost); + _ -> Opts + end, + RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), + case start_room(RMod, Host, ServerHost, Room, NewOpts) of + {ok, _} -> + ejabberd_hooks:run(create_room, ServerHost, [ServerHost, Room, Host]), + {reply, ok, State}; + Err -> + {reply, Err, State} + end; handle_call({create, Room, Host, From, Nick, Opts}, _From, #{server_host := ServerHost} = State) -> ?DEBUG("MUC: create new room '~ts'~n", [Room]), @@ -437,6 +466,15 @@ handle_info({route, Packet}, #{server_host := ServerHost} = State) -> handle_info({room_destroyed, {Room, Host}, Pid}, State) -> %% For backward compat handle_cast({room_destroyed, {Room, Host}, Pid}, State); +handle_info({'DOWN', _Ref, process, Pid, _Reason}, + #{server_host := ServerHost} = State) -> + RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), + case RMod:find_online_room_by_pid(ServerHost, Pid) of + {ok, Room, Host} -> + handle_cast({room_destroyed, {Room, Host}, Pid}, State); + _ -> + {noreply, State} + end; handle_info(Info, State) -> ?ERROR_MSG("Unexpected info: ~p", [Info]), {noreply, State}. @@ -531,7 +569,8 @@ unhibernate_room(ServerHost, Host, Room) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), case RMod:find_online_room(ServerHost, Room, Host) of error -> - case load_room(RMod, Host, ServerHost, Room) of + Proc = procname(ServerHost, {Room, Host}), + case ?GEN_SERVER:call(Proc, {unhibernate, Room, Host}) of {ok, _} = R -> R; _ -> error end; @@ -791,27 +830,15 @@ get_rooms(ServerHost, Host) -> load_permanent_rooms(Hosts, ServerHost, Opts) -> case mod_muc_opt:preload_rooms(Opts) of true -> - Access = get_access(Opts), - HistorySize = mod_muc_opt:history_size(Opts), - QueueType = mod_muc_opt:queue_type(Opts), - RoomShaper = mod_muc_opt:room_shaper(Opts), - RMod = gen_mod:ram_db_mod(Opts, ?MODULE), lists:foreach( - fun(Host) -> - ?DEBUG("Loading rooms at ~ts", [Host]), - lists:foreach( + fun(Host) -> + ?DEBUG("Loading rooms at ~ts", [Host]), + lists:foreach( fun(R) -> - {Room, _} = R#muc_room.name_host, - case RMod:find_online_room(ServerHost, Room, Host) of - error -> - start_room(RMod, Host, ServerHost, Access, - Room, HistorySize, RoomShaper, - R#muc_room.opts, QueueType); - {ok, _} -> - ok - end + {Room, _} = R#muc_room.name_host, + unhibernate_room(ServerHost, Host, Room) end, get_rooms(ServerHost, Host)) - end, Hosts); + end, Hosts); false -> ok end. @@ -877,6 +904,7 @@ start_room(Mod, Host, ServerHost, Access, Room, case mod_muc_room:start(Host, ServerHost, Access, Room, HistorySize, RoomShaper, DefOpts, QueueType) of {ok, Pid} -> + erlang:monitor(process, Pid), Mod:register_online_room(ServerHost, Room, Host, Pid), {ok, Pid}; Err -> @@ -889,6 +917,7 @@ start_room(Mod, Host, ServerHost, Access, Room, HistorySize, HistorySize, RoomShaper, Creator, Nick, DefOpts, QueueType) of {ok, Pid} -> + erlang:monitor(process, Pid), Mod:register_online_room(ServerHost, Room, Host, Pid), {ok, Pid}; Err -> diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 939a1d206..9d3d4e765 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -653,47 +653,21 @@ create_room_with_opts(Name1, Host1, ServerHost1, CustomRoomOpts) -> {_, _, error} -> throw({error, "Invalid 'serverhost'"}); {Name, Host, ServerHost} -> - %% Get the default room options from the muc configuration - DefRoomOpts = mod_muc_opt:default_room_options(ServerHost), - %% Change default room options as required - FormattedRoomOpts = [format_room_option(Opt, Val) || {Opt, Val}<-CustomRoomOpts], - RoomOpts = lists:ukeymerge(1, - lists:keysort(1, FormattedRoomOpts), - lists:keysort(1, DefRoomOpts)), - - - %% Get all remaining mod_muc parameters that might be utilized - Access = mod_muc_opt:access(ServerHost), - AcCreate = mod_muc_opt:access_create(ServerHost), - AcAdmin = mod_muc_opt:access_admin(ServerHost), - AcPer = mod_muc_opt:access_persistent(ServerHost), - AcMam = mod_muc_opt:access_mam(ServerHost), - HistorySize = mod_muc_opt:history_size(ServerHost), - RoomShaper = mod_muc_opt:room_shaper(ServerHost), - QueueType = mod_muc_opt:queue_type(ServerHost), - - %% If the room does not exist yet in the muc_online_room case get_room_pid(Name, Host) of room_not_found -> - %% Store the room on the server, it is not started yet though at this point - case lists:keyfind(persistent, 1, RoomOpts) of - {persistent, true} -> - mod_muc:store_room(ServerHost, Host, Name, RoomOpts); - _ -> - ok - end, - %% Start the room - {ok, Pid} = mod_muc_room:start( - Host, - ServerHost, - {Access, AcCreate, AcAdmin, AcPer, AcMam}, - Name, - HistorySize, - RoomShaper, - RoomOpts, - QueueType), - mod_muc:register_online_room(Name, Host, Pid), - ok; + %% Get the default room options from the muc configuration + DefRoomOpts = mod_muc_opt:default_room_options(ServerHost), + %% Change default room options as required + FormattedRoomOpts = [format_room_option(Opt, Val) || {Opt, Val}<-CustomRoomOpts], + RoomOpts = lists:ukeymerge(1, + lists:keysort(1, FormattedRoomOpts), + lists:keysort(1, DefRoomOpts)), + case mod_muc:create_room(Host, Name, RoomOpts) of + ok -> + ok; + {error, _} -> + throw({error, "Unable to start room"}) + end; _ -> throw({error, "Room already exists"}) end diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl index 8d64df714..c822acc68 100644 --- a/src/mod_muc_mnesia.erl +++ b/src/mod_muc_mnesia.erl @@ -33,7 +33,8 @@ -export([register_online_room/4, unregister_online_room/4, find_online_room/3, get_online_rooms/3, count_online_rooms/2, rsm_supported/0, register_online_user/4, unregister_online_user/4, - count_online_rooms_by_user/3, get_online_rooms_by_user/3]). + count_online_rooms_by_user/3, get_online_rooms_by_user/3, + find_online_room_by_pid/2]). -export([set_affiliation/6, set_affiliations/4, get_affiliation/5, get_affiliations/3, search_affiliation/4]). %% gen_server callbacks @@ -181,6 +182,19 @@ find_online_room(Room, Host) -> [#muc_online_room{pid = Pid}] -> {ok, Pid} end. +find_online_room_by_pid(_ServerHost, Pid) -> + Res = + mnesia:dirty_select( + muc_online_room, + ets:fun2ms( + fun(#muc_online_room{name_host = {Name, Host}, pid = PidS}) + when PidS == Pid -> {Name, Host} + end)), + case Res of + [{Name, Host}] -> {ok, Name, Host}; + _ -> error + end. + count_online_rooms(_ServerHost, Host) -> ets:select_count( muc_online_room, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 3e06e2846..50ad9dd1a 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -913,11 +913,9 @@ terminate(Reason, _StateName, _ -> ok end - end, - mod_muc:room_destroyed(Host, Room, self(), LServer) + end catch ?EX_RULE(E, R, St) -> StackTrace = ?EX_STACK(St), - mod_muc:room_destroyed(Host, Room, self(), LServer), ?ERROR_MSG("Got exception on room termination:~n** ~ts", [misc:format_exception(2, E, R, StackTrace)]) end. diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index c91154921..569cfac49 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -36,7 +36,8 @@ get_online_rooms/3, count_online_rooms/2, rsm_supported/0, register_online_user/4, unregister_online_user/4, count_online_rooms_by_user/3, get_online_rooms_by_user/3, - get_subscribed_rooms/3, get_rooms_without_subscribers/2]). + get_subscribed_rooms/3, get_rooms_without_subscribers/2, + find_online_room_by_pid/2]). -export([set_affiliation/6, set_affiliations/4, get_affiliation/5, get_affiliations/3, search_affiliation/4]). @@ -306,6 +307,21 @@ find_online_room(ServerHost, Room, Host) -> error end. +find_online_room_by_pid(ServerHost, Pid) -> + PidS = misc:encode_pid(Pid), + NodeS = erlang:atom_to_binary(node(Pid), latin1), + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("select @(name)s, @(host)s from muc_online_room where " + "node=%(NodeS)s and pid=%(PidS)s")) of + {selected, [{Room, Host}]} -> + {ok, Room, Host}; + {selected, []} -> + error; + _Err -> + error + end. + count_online_rooms(ServerHost, Host) -> case ejabberd_sql:sql_query( ServerHost,