From 12e01a51196a656955d79869a05ec3db1fc2f9bb Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 29 Mar 2017 12:58:01 +0300 Subject: [PATCH] Add SQL as mod_muc RAM backend --- sql/lite.sql | 21 +++ sql/mssql.sql | 24 ++++ sql/mysql.sql | 21 +++ sql/pg.sql | 21 +++ src/mod_muc.erl | 48 +++---- src/mod_muc_mnesia.erl | 35 ++--- src/mod_muc_riak.erl | 26 ++-- src/mod_muc_sql.erl | 193 ++++++++++++++++++++++---- test/ejabberd_SUITE_data/ejabberd.yml | 3 + test/muc_tests.erl | 2 +- 10 files changed, 316 insertions(+), 78 deletions(-) diff --git a/sql/lite.sql b/sql/lite.sql index c17d80ec5..8b59ef0a1 100644 --- a/sql/lite.sql +++ b/sql/lite.sql @@ -275,6 +275,27 @@ CREATE TABLE muc_registered ( CREATE INDEX i_muc_registered_nick ON muc_registered (nick); CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered (jid, host); +CREATE TABLE muc_online_room ( + name text NOT NULL, + host text NOT NULL, + node text NOT NULL, + pid text NOT NULL +); + +CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room (name, host); + +CREATE TABLE muc_online_users ( + username text NOT NULL, + server text NOT NULL, + resource text NOT NULL, + name text NOT NULL, + host text NOT NULL, + node text NOT NULL +); + +CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users (username, server, resource, name, host); +CREATE INDEX i_muc_online_users_us ON muc_online_users (username, server); + CREATE TABLE irc_custom ( jid text NOT NULL, host text NOT NULL, diff --git a/sql/mssql.sql b/sql/mssql.sql index 7535da5ac..59c192b98 100644 --- a/sql/mssql.sql +++ b/sql/mssql.sql @@ -125,6 +125,30 @@ CREATE TABLE [dbo].[muc_room] ( CREATE UNIQUE CLUSTERED INDEX [muc_room_name_host] ON [muc_room] (name, host) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); +CREATE TABLE [dbo].[muc_online_room] ( + [name] [varchar] (250) NOT NULL, + [host] [varchar] (250) NOT NULL, + [node] [text] NOT NULL, + [pid] [text] NOT NULL +); + +CREATE UNIQUE CLUSTERED INDEX [muc_online_room_name_host] ON [muc_online_room] (name, host) +WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); + +CREATE TABLE [dbo].[muc_online_users] ( + [username] [varchar] (250) NOT NULL, + [server] [varchar] (250) NOT NULL, + [resource] [varchar] (250) NOT NULL, + [name] [varchar] (250) NOT NULL, + [host] [varchar] (250) NOT NULL, + node text NOT NULL +); + +CREATE UNIQUE CLUSTERED INDEX [muc_online_users_i] ON [muc_online_users] (username, server, resource, name, host) +WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); +CREATE UNIQUE CLUSTERED INDEX [muc_online_users_us] ON [muc_online_users] (username, server); +WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); + CREATE TABLE [dbo].[privacy_default_list] ( [username] [varchar] (250) NOT NULL, [name] [varchar] (250) NOT NULL, diff --git a/sql/mysql.sql b/sql/mysql.sql index 982df7ff5..edd205f0d 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -291,6 +291,27 @@ CREATE TABLE muc_registered ( CREATE INDEX i_muc_registered_nick USING BTREE ON muc_registered(nick(75)); CREATE UNIQUE INDEX i_muc_registered_jid_host USING BTREE ON muc_registered(jid(75), host(75)); +CREATE TABLE muc_online_room ( + name text NOT NULL, + host text NOT NULL, + node text NOT NULL, + pid text NOT NULL +) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE UNIQUE INDEX i_muc_online_room_name_host USING BTREE ON muc_online_room(name(75), host(75)); + +CREATE TABLE muc_online_users ( + username text NOT NULL, + server text NOT NULL, + resource text NOT NULL, + name text NOT NULL, + host text NOT NULL, + node text NOT NULL +) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75)); +CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75)); + CREATE TABLE irc_custom ( jid text NOT NULL, host text NOT NULL, diff --git a/sql/pg.sql b/sql/pg.sql index 8a8b77b1f..6c099fc6b 100644 --- a/sql/pg.sql +++ b/sql/pg.sql @@ -293,6 +293,27 @@ CREATE TABLE muc_registered ( CREATE INDEX i_muc_registered_nick ON muc_registered USING btree (nick); CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered USING btree (jid, host); +CREATE TABLE muc_online_room ( + name text NOT NULL, + host text NOT NULL, + node text NOT NULL, + pid text NOT NULL +); + +CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room USING btree (name, host); + +CREATE TABLE muc_online_users ( + username text NOT NULL, + server text NOT NULL, + resource text NOT NULL, + name text NOT NULL, + host text NOT NULL, + node text NOT NULL +); + +CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host); +CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server); + CREATE TABLE irc_custom ( jid text NOT NULL, host text NOT NULL, diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 8bb9c4b8c..9c8316e2e 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -94,16 +94,16 @@ -callback get_rooms(binary(), binary()) -> [#muc_room{}]. -callback get_nick(binary(), binary(), jid()) -> binary() | error. -callback set_nick(binary(), binary(), jid(), binary()) -> {atomic, ok | false}. --callback register_online_room(binary(), binary(), pid()) -> any(). --callback unregister_online_room(binary(), binary(), pid()) -> any(). --callback find_online_room(binary(), binary()) -> {ok, pid()} | error. --callback get_online_rooms(binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}]. --callback count_online_rooms(binary()) -> non_neg_integer(). +-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 get_online_rooms(binary(), binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}]. +-callback count_online_rooms(binary(), binary()) -> non_neg_integer(). -callback rsm_supported() -> boolean(). --callback register_online_user(ljid(), binary(), binary()) -> any(). --callback unregister_online_user(ljid(), binary(), binary()) -> any(). --callback count_online_rooms_by_user(binary(), binary()) -> non_neg_integer(). --callback get_online_rooms_by_user(binary(), binary()) -> [{binary(), binary()}]. +-callback register_online_user(binary(), ljid(), binary(), binary()) -> any(). +-callback unregister_online_user(binary(), ljid(), binary(), binary()) -> any(). +-callback count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer(). +-callback get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}]. %%==================================================================== %% API @@ -127,7 +127,7 @@ shutdown_rooms(Host) -> RMod = gen_mod:ram_db_mod(Host, ?MODULE), MyHost = gen_mod:get_module_opt_host(Host, mod_muc, <<"conference.@HOST@">>), - Rooms = RMod:get_online_rooms(MyHost, undefined), + Rooms = RMod:get_online_rooms(Host, MyHost, undefined), lists:flatmap( fun({_, _, Pid}) when node(Pid) == node() -> Pid ! shutdown, @@ -180,13 +180,13 @@ can_use_nick(ServerHost, Host, JID, Nick) -> find_online_room(Room, Host) -> ServerHost = ejabberd_router:host_of_route(Host), RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:find_online_room(Room, Host). + RMod:find_online_room(ServerHost, Room, Host). -spec register_online_room(binary(), binary(), pid()) -> any(). register_online_room(Room, Host, Pid) -> ServerHost = ejabberd_router:host_of_route(Host), RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:register_online_room(Room, Host, Pid). + RMod:register_online_room(ServerHost, Room, Host, Pid). -spec get_online_rooms(binary()) -> [{binary(), binary(), pid()}]. get_online_rooms(Host) -> @@ -201,22 +201,22 @@ count_online_rooms(Host) -> -spec register_online_user(binary(), ljid(), binary(), binary()) -> any(). register_online_user(ServerHost, LJID, Name, Host) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:register_online_user(LJID, Name, Host). + RMod:register_online_user(ServerHost, LJID, Name, Host). -spec unregister_online_user(binary(), ljid(), binary(), binary()) -> any(). unregister_online_user(ServerHost, LJID, Name, Host) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:unregister_online_user(LJID, Name, Host). + RMod:unregister_online_user(ServerHost, LJID, Name, Host). -spec count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer(). count_online_rooms_by_user(ServerHost, LUser, LServer) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:count_online_rooms_by_user(LUser, LServer). + RMod:count_online_rooms_by_user(ServerHost, LUser, LServer). -spec get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}]. get_online_rooms_by_user(ServerHost, LUser, LServer) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:get_online_rooms_by_user(LUser, LServer). + RMod:get_online_rooms_by_user(ServerHost, LUser, LServer). %%==================================================================== %% gen_server callbacks @@ -256,7 +256,7 @@ handle_call({create, Room, From, Nick, Opts}, _From, RoomShaper, From, Nick, NewOpts, QueueType), RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:register_online_room(Room, Host, Pid), + RMod:register_online_room(ServerHost, Room, Host, Pid), {reply, ok, State}. handle_cast({reload, ServerHost, NewOpts, OldOpts}, #state{host = OldHost}) -> @@ -318,7 +318,7 @@ handle_info({route, Packet}, handle_info({room_destroyed, {Room, Host}, Pid}, State) -> ServerHost = State#state.server_host, RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:unregister_online_room(Room, Host, Pid), + RMod:unregister_online_room(ServerHost, Room, Host, Pid), {noreply, State}; handle_info(Info, State) -> ?ERROR_MSG("unexpected info: ~p", [Info]), @@ -491,7 +491,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, {_AccessRoute, AccessCreate, _AccessAdmin, _AccessPersistent} = Access, {Room, _, Nick} = jid:tolower(To), RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - case RMod:find_online_room(Room, Host) of + case RMod:find_online_room(ServerHost, Room, Host) of error -> case is_create_request(Packet) of true -> @@ -504,7 +504,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, Room, HistorySize, RoomShaper, From, Nick, DefRoomOpts, QueueType), - RMod:register_online_room(Room, Host, Pid), + RMod:register_online_room(ServerHost, Room, Host, Pid), mod_muc_room:route(Pid, Packet), ok; false -> @@ -675,13 +675,13 @@ load_permanent_rooms(Host, ServerHost, Access, lists:foreach( fun(R) -> {Room, Host} = R#muc_room.name_host, - case RMod:find_online_room(Room, Host) of + case RMod:find_online_room(ServerHost, Room, Host) of error -> {ok, Pid} = mod_muc_room:start(Host, ServerHost, Access, Room, HistorySize, RoomShaper, R#muc_room.opts, QueueType), - RMod:register_online_room(Room, Host, Pid); + RMod:register_online_room(ServerHost, Room, Host, Pid); {ok, _} -> ok end @@ -856,12 +856,12 @@ get_online_rooms(ServerHost, Host) -> [{binary(), binary(), pid()}]. get_online_rooms(ServerHost, Host, RSM) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:get_online_rooms(Host, RSM). + RMod:get_online_rooms(ServerHost, Host, RSM). -spec count_online_rooms(binary(), binary()) -> non_neg_integer(). count_online_rooms(ServerHost, Host) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - RMod:count_online_rooms(Host). + RMod:count_online_rooms(ServerHost, Host). opts_to_binary(Opts) -> lists:map( diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl index eaf8da6c3..a87761665 100644 --- a/src/mod_muc_mnesia.erl +++ b/src/mod_muc_mnesia.erl @@ -30,10 +30,10 @@ %% API -export([init/2, import/3, store_room/4, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]). --export([register_online_room/3, unregister_online_room/3, find_online_room/2, - get_online_rooms/2, count_online_rooms/1, rsm_supported/0, - register_online_user/3, unregister_online_user/3, - count_online_rooms_by_user/2, get_online_rooms_by_user/2]). +-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]). -export([set_affiliation/6, set_affiliations/4, get_affiliation/5, get_affiliations/3, search_affiliation/4]). %% gen_server callbacks @@ -157,27 +157,30 @@ get_affiliations(_ServerHost, _Room, _Host) -> search_affiliation(_ServerHost, _Room, _Host, _Affiliation) -> {error, not_implemented}. -register_online_room(Room, Host, Pid) -> +register_online_room(_ServerHost, Room, Host, Pid) -> F = fun() -> mnesia:write( #muc_online_room{name_host = {Room, Host}, pid = Pid}) end, mnesia:transaction(F). -unregister_online_room(Room, Host, Pid) -> +unregister_online_room(_ServerHost, Room, Host, Pid) -> F = fun () -> mnesia:delete_object( #muc_online_room{name_host = {Room, Host}, pid = Pid}) end, mnesia:transaction(F). +find_online_room(_ServerHost, Room, Host) -> + find_online_room(Room, Host). + find_online_room(Room, Host) -> case mnesia:dirty_read(muc_online_room, {Room, Host}) of [] -> error; [#muc_online_room{pid = Pid}] -> {ok, Pid} end. -count_online_rooms(Host) -> +count_online_rooms(_ServerHost, Host) -> ets:select_count( muc_online_room, ets:fun2ms( @@ -185,20 +188,20 @@ count_online_rooms(Host) -> H == Host end)). -get_online_rooms(Host, +get_online_rooms(_ServerHost, Host, #rsm_set{max = Max, 'after' = After, before = undefined}) when is_binary(After), After /= <<"">> -> lists:reverse(get_online_rooms(next, {After, Host}, Host, 0, Max, [])); -get_online_rooms(Host, +get_online_rooms(_ServerHost, Host, #rsm_set{max = Max, 'after' = undefined, before = Before}) when is_binary(Before), Before /= <<"">> -> get_online_rooms(prev, {Before, Host}, Host, 0, Max, []); -get_online_rooms(Host, +get_online_rooms(_ServerHost, Host, #rsm_set{max = Max, 'after' = undefined, before = <<"">>}) -> get_online_rooms(last, {<<"">>, Host}, Host, 0, Max, []); -get_online_rooms(Host, #rsm_set{max = Max}) -> +get_online_rooms(_ServerHost, Host, #rsm_set{max = Max}) -> lists:reverse(get_online_rooms(first, {<<"">>, Host}, Host, 0, Max, [])); -get_online_rooms(Host, undefined) -> +get_online_rooms(_ServerHost, Host, undefined) -> mnesia:dirty_select( muc_online_room, ets:fun2ms( @@ -248,17 +251,17 @@ get_online_rooms(Action, Key, Host, Count, Max, Items) -> rsm_supported() -> true. -register_online_user({U, S, R}, Room, Host) -> +register_online_user(_ServerHost, {U, S, R}, Room, Host) -> ets:insert(muc_online_users, #muc_online_users{us = {U, S}, resource = R, room = Room, host = Host}). -unregister_online_user({U, S, R}, Room, Host) -> +unregister_online_user(_ServerHost, {U, S, R}, Room, Host) -> ets:delete_object(muc_online_users, #muc_online_users{us = {U, S}, resource = R, room = Room, host = Host}). -count_online_rooms_by_user(U, S) -> +count_online_rooms_by_user(_ServerHost, U, S) -> ets:select_count( muc_online_users, ets:fun2ms( @@ -266,7 +269,7 @@ count_online_rooms_by_user(U, S) -> U == U1 andalso S == S1 end)). -get_online_rooms_by_user(U, S) -> +get_online_rooms_by_user(_ServerHost, U, S) -> ets:select( muc_online_users, ets:fun2ms( diff --git a/src/mod_muc_riak.erl b/src/mod_muc_riak.erl index 0577ef60b..8dd1eddf8 100644 --- a/src/mod_muc_riak.erl +++ b/src/mod_muc_riak.erl @@ -30,10 +30,10 @@ %% API -export([init/2, import/3, store_room/4, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]). --export([register_online_room/3, unregister_online_room/3, find_online_room/2, - get_online_rooms/2, count_online_rooms/1, rsm_supported/0, - register_online_user/3, unregister_online_user/3, - count_online_rooms_by_user/2, get_online_rooms_by_user/2]). +-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]). -export([set_affiliation/6, set_affiliations/4, get_affiliation/5, get_affiliations/3, search_affiliation/4]). @@ -140,34 +140,34 @@ get_affiliations(_ServerHost, _Room, _Host) -> search_affiliation(_ServerHost, _Room, _Host, _Affiliation) -> {error, not_implemented}. -register_online_room(_, _, _) -> +register_online_room(_, _, _, _) -> erlang:error(not_implemented). -unregister_online_room(_, _, _) -> +unregister_online_room(_, _, _, _) -> erlang:error(not_implemented). -find_online_room(_, _) -> +find_online_room(_, _, _) -> erlang:error(not_implemented). -count_online_rooms(_) -> +count_online_rooms(_, _) -> erlang:error(not_implemented). -get_online_rooms(_, _) -> +get_online_rooms(_, _, _) -> erlang:error(not_implemented). rsm_supported() -> false. -register_online_user(_, _, _) -> +register_online_user(_, _, _, _) -> erlang:error(not_implemented). -unregister_online_user(_, _, _) -> +unregister_online_user(_, _, _, _) -> erlang:error(not_implemented). -count_online_rooms_by_user(_, _) -> +count_online_rooms_by_user(_, _, _) -> erlang:error(not_implemented). -get_online_rooms_by_user(_, _) -> +get_online_rooms_by_user(_, _, _) -> erlang:error(not_implemented). import(_LServer, <<"muc_room">>, diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index df1319ce3..14ff12484 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -33,10 +33,10 @@ -export([init/2, store_room/4, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4, import/3, export/1]). --export([register_online_room/3, unregister_online_room/3, find_online_room/2, - get_online_rooms/2, count_online_rooms/1, rsm_supported/0, - register_online_user/3, unregister_online_user/3, - count_online_rooms_by_user/2, get_online_rooms_by_user/2]). +-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]). -export([set_affiliation/6, set_affiliations/4, get_affiliation/5, get_affiliations/3, search_affiliation/4]). @@ -48,8 +48,13 @@ %%%=================================================================== %%% API %%%=================================================================== -init(_Host, _Opts) -> - ok. +init(Host, Opts) -> + case gen_mod:ram_db_mod(Host, Opts, mod_muc) of + ?MODULE -> + clean_tables(Host); + _ -> + ok + end. store_room(LServer, Host, Name, Opts) -> SOpts = jlib:term_to_expr(Opts), @@ -165,35 +170,126 @@ get_affiliations(_ServerHost, _Room, _Host) -> search_affiliation(_ServerHost, _Room, _Host, _Affiliation) -> {error, not_implemented}. -register_online_room(_, _, _) -> - erlang:error(not_implemented). +register_online_room(ServerHost, Room, Host, Pid) -> + PidS = enc_pid(Pid), + NodeS = erlang:atom_to_binary(node(Pid), latin1), + case ?SQL_UPSERT(ServerHost, + "muc_online_room", + ["!name=%(Room)s", + "!host=%(Host)s", + "node=%(NodeS)s", + "pid=%(PidS)s"]) of + ok -> + ok; + Err -> + ?ERROR_MSG("failed to update 'muc_online_room': ~p", [Err]), + Err + end. -unregister_online_room(_, _, _) -> - erlang:error(not_implemented). +unregister_online_room(ServerHost, Room, Host, Pid) -> + %% TODO: report errors + PidS = enc_pid(Pid), + NodeS = erlang:atom_to_binary(node(Pid), latin1), + ejabberd_sql:sql_query( + ServerHost, + ?SQL("delete from muc_online_room where name=%(Room)s and " + "host=%(Host)s and node=%(NodeS)s and pid=%(PidS)s")). -find_online_room(_, _) -> - erlang:error(not_implemented). +find_online_room(ServerHost, Room, Host) -> + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("select @(pid)s, @(node)s from muc_online_room where " + "name=%(Room)s and host=%(Host)s")) of + {selected, [{PidS, NodeS}]} -> + try {ok, dec_pid(PidS, NodeS)} + catch _:{node_down, _} -> error + end; + {selected, []} -> + error; + Err -> + ?ERROR_MSG("failed to select 'muc_online_room': ~p", [Err]), + error + end. -count_online_rooms(_) -> - erlang:error(not_implemented). +count_online_rooms(ServerHost, Host) -> + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("select @(count(*))d from muc_online_room " + "where host=%(Host)s")) of + {selected, [{Num}]} -> + Num; + Err -> + ?ERROR_MSG("failed to select 'muc_online_room': ~p", [Err]), + 0 + end. -get_online_rooms(_, _) -> - erlang:error(not_implemented). +get_online_rooms(ServerHost, Host, _RSM) -> + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("select @(name)s, @(pid)s, @(node)s from muc_online_room " + "where host=%(Host)s")) of + {selected, Rows} -> + lists:flatmap( + fun({Room, PidS, NodeS}) -> + try [{Room, Host, dec_pid(PidS, NodeS)}] + catch _:{node_down, _} -> [] + end + end, Rows); + Err -> + ?ERROR_MSG("failed to select 'muc_online_room': ~p", [Err]), + 0 + end. rsm_supported() -> false. -register_online_user(_, _, _) -> - erlang:error(not_implemented). +register_online_user(ServerHost, {U, S, R}, Room, Host) -> + NodeS = erlang:atom_to_binary(node(), latin1), + case ?SQL_UPSERT(ServerHost, "muc_online_users", + ["!username=%(U)s", + "!server=%(S)s", + "!resource=%(R)s", + "!name=%(Room)s", + "!host=%(Host)s", + "node=%(NodeS)s"]) of + ok -> + ok; + Err -> + ?ERROR_MSG("failed to update 'muc_online_users': ~p", [Err]), + Err + end. -unregister_online_user(_, _, _) -> - erlang:error(not_implemented). +unregister_online_user(ServerHost, {U, S, R}, Room, Host) -> + %% TODO: report errors + ejabberd_sql:sql_query( + ServerHost, + ?SQL("delete from muc_online_users where username=%(U)s and " + "server=%(S)s and resource=%(R)s and name=%(Room)s and " + "host=%(Host)s")). -count_online_rooms_by_user(_, _) -> - erlang:error(not_implemented). +count_online_rooms_by_user(ServerHost, U, S) -> + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("select @(count(*))d from muc_online_users where " + "username=%(U)s and server=%(S)s")) of + {selected, [{Num}]} -> + Num; + Err -> + ?ERROR_MSG("failed to select 'muc_online_users': ~p", [Err]), + 0 + end. -get_online_rooms_by_user(_, _) -> - erlang:error(not_implemented). +get_online_rooms_by_user(ServerHost, U, S) -> + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("select @(name)s, @(host)s from muc_online_users where " + "username=%(U)s and server=%(S)s")) of + {selected, Rows} -> + Rows; + Err -> + ?ERROR_MSG("failed to select 'muc_online_users': ~p", [Err]), + [] + end. export(_Server) -> [{muc_room, @@ -232,3 +328,52 @@ import(_, _, _) -> %%%=================================================================== %%% Internal functions %%%=================================================================== +-spec enc_pid(pid()) -> binary(). +enc_pid(Pid) -> + list_to_binary(erlang:pid_to_list(Pid)). + +-spec dec_pid(binary(), binary()) -> pid(). +dec_pid(PidBin, NodeBin) -> + PidStr = binary_to_list(PidBin), + Pid = erlang:list_to_pid(PidStr), + case erlang:binary_to_atom(NodeBin, latin1) of + Node when Node == node() -> + Pid; + Node -> + try set_node_id(PidStr, NodeBin) + catch _:badarg -> + erlang:error({node_down, Node}) + end + end. + +-spec set_node_id(string(), binary()) -> pid(). +set_node_id(PidStr, NodeBin) -> + ExtPidStr = erlang:pid_to_list( + binary_to_term( + <<131,103,100,(size(NodeBin)):16,NodeBin/binary,0:72>>)), + [H|_] = string:tokens(ExtPidStr, "."), + [_|T] = string:tokens(PidStr, "."), + erlang:list_to_pid(string:join([H|T], ".")). + +clean_tables(ServerHost) -> + NodeS = erlang:atom_to_binary(node(), latin1), + ?INFO_MSG("Cleaning SQL muc_online_room table...", []), + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("delete from muc_online_room where node=%(NodeS)s")) of + {updated, _} -> + ok; + Err1 -> + ?ERROR_MSG("failed to clean 'muc_online_room' table: ~p", [Err1]), + Err1 + end, + ?INFO_MSG("Cleaning SQL muc_online_users table...", []), + case ejabberd_sql:sql_query( + ServerHost, + ?SQL("delete from muc_online_users where node=%(NodeS)s")) of + {updated, _} -> + ok; + Err2 -> + ?ERROR_MSG("failed to clean 'muc_online_users' table: ~p", [Err2]), + Err2 + end. diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index efecf6df8..41bf24ab2 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -20,6 +20,7 @@ host_config: db_type: sql mod_muc: db_type: sql + ram_db_type: sql mod_offline: db_type: sql mod_privacy: @@ -77,6 +78,7 @@ Welcome to this XMPP server." db_type: sql mod_muc: db_type: sql + ram_db_type: sql mod_offline: db_type: sql mod_privacy: @@ -139,6 +141,7 @@ Welcome to this XMPP server." db_type: sql mod_muc: db_type: sql + ram_db_type: sql mod_offline: db_type: sql mod_privacy: diff --git a/test/muc_tests.erl b/test/muc_tests.erl index 754d767a9..eb869cad6 100644 --- a/test/muc_tests.erl +++ b/test/muc_tests.erl @@ -152,7 +152,7 @@ service_features(Config) -> end, RequiredFeatures = sets:from_list( [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, - ?NS_REGISTER, ?NS_MUC, ?NS_RSM, + ?NS_REGISTER, ?NS_MUC, ?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE | MAMFeatures]), ct:comment("Checking if all needed disco features are set"),