From 0b439a7d5b28a5de8d4c2e108333ad20189b580e Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 13 Apr 2016 21:07:32 +0300 Subject: [PATCH] Clean mod_muc.erl from DB specific code --- src/mod_muc.erl | 447 ++++------------------------------------- src/mod_muc_mnesia.erl | 163 +++++++++++++++ src/mod_muc_riak.erl | 117 +++++++++++ src/mod_muc_sql.erl | 202 +++++++++++++++++++ 4 files changed, 519 insertions(+), 410 deletions(-) create mode 100644 src/mod_muc_mnesia.erl create mode 100644 src/mod_muc_riak.erl create mode 100644 src/mod_muc_sql.erl diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 9d4b4985c..95631e25c 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -48,6 +48,7 @@ export/1, import/1, import/3, + opts_to_binary/1, can_use_nick/4]). -export([init/1, handle_call/3, handle_cast/2, @@ -72,6 +73,17 @@ -define(MAX_ROOMS_DISCOITEMS, 100). +-type muc_room_opts() :: [{atom(), any()}]. +-callback init(binary(), gen_mod:opts()) -> any(). +-callback import(binary(), #muc_room{} | #muc_registered{}) -> ok | pass. +-callback store_room(binary(), binary(), binary(), list()) -> {atomic, any()}. +-callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error. +-callback forget_room(binary(), binary(), binary()) -> {atomic, any()}. +-callback can_use_nick(binary(), binary(), jid(), binary()) -> boolean(). +-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}. + %%==================================================================== %% API %%==================================================================== @@ -125,83 +137,19 @@ create_room(Host, Name, From, Nick, Opts) -> store_room(ServerHost, Host, Name, Opts) -> LServer = jid:nameprep(ServerHost), - store_room(LServer, Host, Name, Opts, - gen_mod:db_type(LServer, ?MODULE)). - -store_room(_LServer, Host, Name, Opts, mnesia) -> - F = fun () -> - mnesia:write(#muc_room{name_host = {Name, Host}, - opts = Opts}) - end, - mnesia:transaction(F); -store_room(_LServer, Host, Name, Opts, riak) -> - {atomic, ejabberd_riak:put(#muc_room{name_host = {Name, Host}, - opts = Opts}, - muc_room_schema())}; -store_room(LServer, Host, Name, Opts, odbc) -> - SName = ejabberd_odbc:escape(Name), - SHost = ejabberd_odbc:escape(Host), - SOpts = ejabberd_odbc:encode_term(Opts), - F = fun () -> - odbc_queries:update_t(<<"muc_room">>, - [<<"name">>, <<"host">>, <<"opts">>], - [SName, SHost, SOpts], - [<<"name='">>, SName, <<"' and host='">>, - SHost, <<"'">>]) - end, - ejabberd_odbc:sql_transaction(LServer, F). + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:store_room(LServer, Host, Name, Opts). restore_room(ServerHost, Host, Name) -> LServer = jid:nameprep(ServerHost), - restore_room(LServer, Host, Name, - gen_mod:db_type(LServer, ?MODULE)). - -restore_room(_LServer, Host, Name, mnesia) -> - case catch mnesia:dirty_read(muc_room, {Name, Host}) of - [#muc_room{opts = Opts}] -> Opts; - _ -> error - end; -restore_room(_LServer, Host, Name, riak) -> - case ejabberd_riak:get(muc_room, muc_room_schema(), {Name, Host}) of - {ok, #muc_room{opts = Opts}} -> Opts; - _ -> error - end; -restore_room(LServer, Host, Name, odbc) -> - SName = ejabberd_odbc:escape(Name), - SHost = ejabberd_odbc:escape(Host), - case catch ejabberd_odbc:sql_query(LServer, - [<<"select opts from muc_room where name='">>, - SName, <<"' and host='">>, SHost, - <<"';">>]) - of - {selected, [<<"opts">>], [[Opts]]} -> - opts_to_binary(ejabberd_odbc:decode_term(Opts)); - _ -> error - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:restore_room(LServer, Host, Name). forget_room(ServerHost, Host, Name) -> LServer = jid:nameprep(ServerHost), - forget_room(LServer, Host, Name, - gen_mod:db_type(LServer, ?MODULE)). - -forget_room(LServer, Host, Name, mnesia) -> remove_room_mam(LServer, Host, Name), - F = fun () -> mnesia:delete({muc_room, {Name, Host}}) - end, - mnesia:transaction(F); -forget_room(LServer, Host, Name, riak) -> - remove_room_mam(LServer, Host, Name), - {atomic, ejabberd_riak:delete(muc_room, {Name, Host})}; -forget_room(LServer, Host, Name, odbc) -> - remove_room_mam(LServer, Host, Name), - SName = ejabberd_odbc:escape(Name), - SHost = ejabberd_odbc:escape(Host), - F = fun () -> - ejabberd_odbc:sql_query_t([<<"delete from muc_room where name='">>, - SName, <<"' and host='">>, SHost, - <<"';">>]) - end, - ejabberd_odbc:sql_transaction(LServer, F). + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:forget_room(LServer, Host, Name). remove_room_mam(LServer, Host, Name) -> case gen_mod:is_loaded(LServer, mod_mam) of @@ -233,48 +181,8 @@ process_iq_disco_items(Host, From, To, can_use_nick(_ServerHost, _Host, _JID, <<"">>) -> false; can_use_nick(ServerHost, Host, JID, Nick) -> LServer = jid:nameprep(ServerHost), - can_use_nick(LServer, Host, JID, Nick, - gen_mod:db_type(LServer, ?MODULE)). - -can_use_nick(_LServer, Host, JID, Nick, mnesia) -> - {LUser, LServer, _} = jid:tolower(JID), - LUS = {LUser, LServer}, - case catch mnesia:dirty_select(muc_registered, - [{#muc_registered{us_host = '$1', - nick = Nick, _ = '_'}, - [{'==', {element, 2, '$1'}, Host}], - ['$_']}]) - of - {'EXIT', _Reason} -> true; - [] -> true; - [#muc_registered{us_host = {U, _Host}}] -> U == LUS - end; -can_use_nick(LServer, Host, JID, Nick, riak) -> - {LUser, LServer, _} = jid:tolower(JID), - LUS = {LUser, LServer}, - case ejabberd_riak:get_by_index(muc_registered, - muc_registered_schema(), - <<"nick_host">>, {Nick, Host}) of - {ok, []} -> - true; - {ok, [#muc_registered{us_host = {U, _Host}}]} -> - U == LUS; - {error, _} -> - true - end; -can_use_nick(LServer, Host, JID, Nick, odbc) -> - SJID = - jid:to_string(jid:tolower(jid:remove_resource(JID))), - SNick = ejabberd_odbc:escape(Nick), - SHost = ejabberd_odbc:escape(Host), - case catch ejabberd_odbc:sql_query(LServer, - [<<"select jid from muc_registered ">>, - <<"where nick='">>, SNick, - <<"' and host='">>, SHost, <<"';">>]) - of - {selected, [<<"jid">>], [[SJID1]]} -> SJID == SJID1; - _ -> true - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:can_use_nick(LServer, Host, JID, Nick). %%==================================================================== %% gen_server callbacks @@ -283,21 +191,8 @@ can_use_nick(LServer, Host, JID, Nick, odbc) -> init([Host, Opts]) -> MyHost = gen_mod:get_opt_host(Host, Opts, <<"conference.@HOST@">>), - case gen_mod:db_type(Host, Opts) of - mnesia -> - mnesia:create_table(muc_room, - [{disc_copies, [node()]}, - {attributes, - record_info(fields, muc_room)}]), - mnesia:create_table(muc_registered, - [{disc_copies, [node()]}, - {attributes, - record_info(fields, muc_registered)}]), - update_tables(MyHost), - mnesia:add_table_index(muc_registered, nick); - _ -> - ok - end, + Mod = gen_mod:db_mod(Host, Opts, ?MODULE), + Mod:init(Host, [{host, MyHost}|Opts]), mnesia:create_table(muc_online_room, [{ram_copies, [node()]}, {attributes, record_info(fields, muc_online_room)}]), @@ -647,43 +542,8 @@ check_create_roomid(ServerHost, RoomID) -> get_rooms(ServerHost, Host) -> LServer = jid:nameprep(ServerHost), - get_rooms(LServer, Host, - gen_mod:db_type(LServer, ?MODULE)). - -get_rooms(_LServer, Host, mnesia) -> - case catch mnesia:dirty_select(muc_room, - [{#muc_room{name_host = {'_', Host}, - _ = '_'}, - [], ['$_']}]) - of - {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]), []; - Rs -> Rs - end; -get_rooms(_LServer, Host, riak) -> - case ejabberd_riak:get(muc_room, muc_room_schema()) of - {ok, Rs} -> - lists:filter( - fun(#muc_room{name_host = {_, H}}) -> - Host == H - end, Rs); - _Err -> - [] - end; -get_rooms(LServer, Host, odbc) -> - SHost = ejabberd_odbc:escape(Host), - case catch ejabberd_odbc:sql_query(LServer, - [<<"select name, opts from muc_room ">>, - <<"where host='">>, SHost, <<"';">>]) - of - {selected, [<<"name">>, <<"opts">>], RoomOpts} -> - lists:map(fun ([Room, Opts]) -> - #muc_room{name_host = {Room, Host}, - opts = opts_to_binary( - ejabberd_odbc:decode_term(Opts))} - end, - RoomOpts); - Err -> ?ERROR_MSG("failed to get rooms: ~p", [Err]), [] - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:get_rooms(LServer, Host). load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) -> @@ -873,41 +733,8 @@ iq_get_unique(From) -> get_nick(ServerHost, Host, From) -> LServer = jid:nameprep(ServerHost), - get_nick(LServer, Host, From, - gen_mod:db_type(LServer, ?MODULE)). - -get_nick(_LServer, Host, From, mnesia) -> - {LUser, LServer, _} = jid:tolower(From), - LUS = {LUser, LServer}, - case catch mnesia:dirty_read(muc_registered, - {LUS, Host}) - of - {'EXIT', _Reason} -> error; - [] -> error; - [#muc_registered{nick = Nick}] -> Nick - end; -get_nick(LServer, Host, From, riak) -> - {LUser, LServer, _} = jid:tolower(From), - US = {LUser, LServer}, - case ejabberd_riak:get(muc_registered, - muc_registered_schema(), - {US, Host}) of - {ok, #muc_registered{nick = Nick}} -> Nick; - {error, _} -> error - end; -get_nick(LServer, Host, From, odbc) -> - SJID = - ejabberd_odbc:escape(jid:to_string(jid:tolower(jid:remove_resource(From)))), - SHost = ejabberd_odbc:escape(Host), - case catch ejabberd_odbc:sql_query(LServer, - [<<"select nick from muc_registered where " - "jid='">>, - SJID, <<"' and host='">>, SHost, - <<"';">>]) - of - {selected, [<<"nick">>], [[Nick]]} -> Nick; - _ -> error - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:get_nick(LServer, Host, From). iq_get_register_info(ServerHost, Host, From, Lang) -> {Nick, Registered} = case get_nick(ServerHost, Host, @@ -946,107 +773,8 @@ iq_get_register_info(ServerHost, Host, From, Lang) -> set_nick(ServerHost, Host, From, Nick) -> LServer = jid:nameprep(ServerHost), - set_nick(LServer, Host, From, Nick, - gen_mod:db_type(LServer, ?MODULE)). - -set_nick(_LServer, Host, From, Nick, mnesia) -> - {LUser, LServer, _} = jid:tolower(From), - LUS = {LUser, LServer}, - F = fun () -> - case Nick of - <<"">> -> - mnesia:delete({muc_registered, {LUS, Host}}), ok; - _ -> - Allow = case mnesia:select(muc_registered, - [{#muc_registered{us_host = - '$1', - nick = Nick, - _ = '_'}, - [{'==', {element, 2, '$1'}, - Host}], - ['$_']}]) - of - [] -> true; - [#muc_registered{us_host = {U, _Host}}] -> - U == LUS - end, - if Allow -> - mnesia:write(#muc_registered{us_host = {LUS, Host}, - nick = Nick}), - ok; - true -> false - end - end - end, - mnesia:transaction(F); -set_nick(LServer, Host, From, Nick, riak) -> - {LUser, LServer, _} = jid:tolower(From), - LUS = {LUser, LServer}, - {atomic, - case Nick of - <<"">> -> - ejabberd_riak:delete(muc_registered, {LUS, Host}); - _ -> - Allow = case ejabberd_riak:get_by_index( - muc_registered, - muc_registered_schema(), - <<"nick_host">>, {Nick, Host}) of - {ok, []} -> - true; - {ok, [#muc_registered{us_host = {U, _Host}}]} -> - U == LUS; - {error, _} -> - false - end, - if Allow -> - ejabberd_riak:put(#muc_registered{us_host = {LUS, Host}, - nick = Nick}, - muc_registered_schema(), - [{'2i', [{<<"nick_host">>, - {Nick, Host}}]}]); - true -> - false - end - end}; -set_nick(LServer, Host, From, Nick, odbc) -> - JID = - jid:to_string(jid:tolower(jid:remove_resource(From))), - SJID = ejabberd_odbc:escape(JID), - SNick = ejabberd_odbc:escape(Nick), - SHost = ejabberd_odbc:escape(Host), - F = fun () -> - case Nick of - <<"">> -> - ejabberd_odbc:sql_query_t([<<"delete from muc_registered where ">>, - <<"jid='">>, SJID, - <<"' and host='">>, Host, - <<"';">>]), - ok; - _ -> - Allow = case - ejabberd_odbc:sql_query_t([<<"select jid from muc_registered ">>, - <<"where nick='">>, - SNick, - <<"' and host='">>, - SHost, <<"';">>]) - of - {selected, [<<"jid">>], [[J]]} -> J == JID; - _ -> true - end, - if Allow -> - odbc_queries:update_t(<<"muc_registered">>, - [<<"jid">>, <<"host">>, - <<"nick">>], - [SJID, SHost, SNick], - [<<"jid='">>, SJID, - <<"' and host='">>, SHost, - <<"'">>]), - ok; - true -> false - end - end - end, - ejabberd_odbc:sql_transaction(LServer, F). + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:set_nick(LServer, Host, From, Nick). iq_set_register_info(ServerHost, Host, From, Nick, Lang) -> @@ -1192,118 +920,17 @@ opts_to_binary(Opts) -> Opt end, Opts). -update_tables(Host) -> - update_muc_room_table(Host), - update_muc_registered_table(Host). +export(LServer) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:export(LServer). -muc_room_schema() -> - {record_info(fields, muc_room), #muc_room{}}. +import(LServer) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:import(LServer). -muc_registered_schema() -> - {record_info(fields, muc_registered), #muc_registered{}}. - -update_muc_room_table(_Host) -> - Fields = record_info(fields, muc_room), - case mnesia:table_info(muc_room, attributes) of - Fields -> - ejabberd_config:convert_table_to_binary( - muc_room, Fields, set, - fun(#muc_room{name_host = {N, _}}) -> N end, - fun(#muc_room{name_host = {N, H}, - opts = Opts} = R) -> - R#muc_room{name_host = {iolist_to_binary(N), - iolist_to_binary(H)}, - opts = opts_to_binary(Opts)} - end); - _ -> - ?INFO_MSG("Recreating muc_room table", []), - mnesia:transform_table(muc_room, ignore, Fields) - end. - -update_muc_registered_table(_Host) -> - Fields = record_info(fields, muc_registered), - case mnesia:table_info(muc_registered, attributes) of - Fields -> - ejabberd_config:convert_table_to_binary( - muc_registered, Fields, set, - fun(#muc_registered{us_host = {_, H}}) -> H end, - fun(#muc_registered{us_host = {{U, S}, H}, - nick = Nick} = R) -> - R#muc_registered{us_host = {{iolist_to_binary(U), - iolist_to_binary(S)}, - iolist_to_binary(H)}, - nick = iolist_to_binary(Nick)} - end); - _ -> - ?INFO_MSG("Recreating muc_registered table", []), - mnesia:transform_table(muc_registered, ignore, Fields) - end. - -export(_Server) -> - [{muc_room, - fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) -> - case str:suffix(Host, RoomHost) of - true -> - SName = ejabberd_odbc:escape(Name), - SRoomHost = ejabberd_odbc:escape(RoomHost), - SOpts = ejabberd_odbc:encode_term(Opts), - [[<<"delete from muc_room where name='">>, SName, - <<"' and host='">>, SRoomHost, <<"';">>], - [<<"insert into muc_room(name, host, opts) ", - "values (">>, - <<"'">>, SName, <<"', '">>, SRoomHost, - <<"', '">>, SOpts, <<"');">>]]; - false -> - [] - end - end}, - {muc_registered, - fun(Host, #muc_registered{us_host = {{U, S}, RoomHost}, - nick = Nick}) -> - case str:suffix(Host, RoomHost) of - true -> - SJID = ejabberd_odbc:escape( - jid:to_string( - jid:make(U, S, <<"">>))), - SNick = ejabberd_odbc:escape(Nick), - SRoomHost = ejabberd_odbc:escape(RoomHost), - [[<<"delete from muc_registered where jid='">>, - SJID, <<"' and host='">>, SRoomHost, <<"';">>], - [<<"insert into muc_registered(jid, host, " - "nick) values ('">>, - SJID, <<"', '">>, SRoomHost, <<"', '">>, SNick, - <<"');">>]]; - false -> - [] - end - end}]. - -import(_LServer) -> - [{<<"select name, host, opts from muc_room;">>, - fun([Name, RoomHost, SOpts]) -> - Opts = opts_to_binary(ejabberd_odbc:decode_term(SOpts)), - #muc_room{name_host = {Name, RoomHost}, opts = Opts} - end}, - {<<"select jid, host, nick from muc_registered;">>, - fun([J, RoomHost, Nick]) -> - #jid{user = U, server = S} = - jid:from_string(J), - #muc_registered{us_host = {{U, S}, RoomHost}, - nick = Nick} - end}]. - -import(_LServer, mnesia, #muc_room{} = R) -> - mnesia:dirty_write(R); -import(_LServer, mnesia, #muc_registered{} = R) -> - mnesia:dirty_write(R); -import(_LServer, riak, #muc_room{} = R) -> - ejabberd_riak:put(R, muc_room_schema()); -import(_LServer, riak, - #muc_registered{us_host = {_, Host}, nick = Nick} = R) -> - ejabberd_riak:put(R, muc_registered_schema(), - [{'2i', [{<<"nick_host">>, {Nick, Host}}]}]); -import(_, _, _) -> - pass. +import(LServer, DBType, Data) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Data). mod_opt_type(access) -> fun (A) when is_atom(A) -> A end; diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl new file mode 100644 index 000000000..e3ae36978 --- /dev/null +++ b/src/mod_muc_mnesia.erl @@ -0,0 +1,163 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 13 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_muc_mnesia). + +-behaviour(mod_muc). + +%% API +-export([init/2, import/2, store_room/4, restore_room/3, forget_room/3, + can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]). + +-include("mod_muc.hrl"). +-include("logger.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, Opts) -> + MyHost = proplists:get_value(host, Opts), + mnesia:create_table(muc_room, + [{disc_copies, [node()]}, + {attributes, + record_info(fields, muc_room)}]), + mnesia:create_table(muc_registered, + [{disc_copies, [node()]}, + {attributes, + record_info(fields, muc_registered)}]), + update_tables(MyHost), + mnesia:add_table_index(muc_registered, nick). + +store_room(_LServer, Host, Name, Opts) -> + F = fun () -> + mnesia:write(#muc_room{name_host = {Name, Host}, + opts = Opts}) + end, + mnesia:transaction(F). + +restore_room(_LServer, Host, Name) -> + case catch mnesia:dirty_read(muc_room, {Name, Host}) of + [#muc_room{opts = Opts}] -> Opts; + _ -> error + end. + +forget_room(_LServer, Host, Name) -> + F = fun () -> mnesia:delete({muc_room, {Name, Host}}) + end, + mnesia:transaction(F). + +can_use_nick(_LServer, Host, JID, Nick) -> + {LUser, LServer, _} = jid:tolower(JID), + LUS = {LUser, LServer}, + case catch mnesia:dirty_select(muc_registered, + [{#muc_registered{us_host = '$1', + nick = Nick, _ = '_'}, + [{'==', {element, 2, '$1'}, Host}], + ['$_']}]) + of + {'EXIT', _Reason} -> true; + [] -> true; + [#muc_registered{us_host = {U, _Host}}] -> U == LUS + end. + +get_rooms(_LServer, Host) -> + mnesia:dirty_select(muc_room, + [{#muc_room{name_host = {'_', Host}, + _ = '_'}, + [], ['$_']}]). + +get_nick(_LServer, Host, From) -> + {LUser, LServer, _} = jid:tolower(From), + LUS = {LUser, LServer}, + case mnesia:dirty_read(muc_registered, {LUS, Host}) of + [] -> error; + [#muc_registered{nick = Nick}] -> Nick + end. + +set_nick(_LServer, Host, From, Nick) -> + {LUser, LServer, _} = jid:tolower(From), + LUS = {LUser, LServer}, + F = fun () -> + case Nick of + <<"">> -> + mnesia:delete({muc_registered, {LUS, Host}}), + ok; + _ -> + Allow = case mnesia:select( + muc_registered, + [{#muc_registered{us_host = + '$1', + nick = Nick, + _ = '_'}, + [{'==', {element, 2, '$1'}, + Host}], + ['$_']}]) of + [] -> true; + [#muc_registered{us_host = {U, _Host}}] -> + U == LUS + end, + if Allow -> + mnesia:write(#muc_registered{ + us_host = {LUS, Host}, + nick = Nick}), + ok; + true -> + false + end + end + end, + mnesia:transaction(F). + +import(_LServer, #muc_room{} = R) -> + mnesia:dirty_write(R); +import(_LServer, #muc_registered{} = R) -> + mnesia:dirty_write(R). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +update_tables(Host) -> + update_muc_room_table(Host), + update_muc_registered_table(Host). + +update_muc_room_table(_Host) -> + Fields = record_info(fields, muc_room), + case mnesia:table_info(muc_room, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + muc_room, Fields, set, + fun(#muc_room{name_host = {N, _}}) -> N end, + fun(#muc_room{name_host = {N, H}, + opts = Opts} = R) -> + R#muc_room{name_host = {iolist_to_binary(N), + iolist_to_binary(H)}, + opts = mod_muc:opts_to_binary(Opts)} + end); + _ -> + ?INFO_MSG("Recreating muc_room table", []), + mnesia:transform_table(muc_room, ignore, Fields) + end. + +update_muc_registered_table(_Host) -> + Fields = record_info(fields, muc_registered), + case mnesia:table_info(muc_registered, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + muc_registered, Fields, set, + fun(#muc_registered{us_host = {_, H}}) -> H end, + fun(#muc_registered{us_host = {{U, S}, H}, + nick = Nick} = R) -> + R#muc_registered{us_host = {{iolist_to_binary(U), + iolist_to_binary(S)}, + iolist_to_binary(H)}, + nick = iolist_to_binary(Nick)} + end); + _ -> + ?INFO_MSG("Recreating muc_registered table", []), + mnesia:transform_table(muc_registered, ignore, Fields) + end. diff --git a/src/mod_muc_riak.erl b/src/mod_muc_riak.erl new file mode 100644 index 000000000..bc6e5959a --- /dev/null +++ b/src/mod_muc_riak.erl @@ -0,0 +1,117 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 13 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_muc_riak). + +-behaviour(mod_muc). + +%% API +-export([init/2, import/2, store_room/4, restore_room/3, forget_room/3, + can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]). + +-include("mod_muc.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + ok. + +store_room(_LServer, Host, Name, Opts) -> + {atomic, ejabberd_riak:put(#muc_room{name_host = {Name, Host}, + opts = Opts}, + muc_room_schema())}. + +restore_room(_LServer, Host, Name) -> + case ejabberd_riak:get(muc_room, muc_room_schema(), {Name, Host}) of + {ok, #muc_room{opts = Opts}} -> Opts; + _ -> error + end. + +forget_room(_LServer, Host, Name) -> + {atomic, ejabberd_riak:delete(muc_room, {Name, Host})}. + +can_use_nick(LServer, Host, JID, Nick) -> + {LUser, LServer, _} = jid:tolower(JID), + LUS = {LUser, LServer}, + case ejabberd_riak:get_by_index(muc_registered, + muc_registered_schema(), + <<"nick_host">>, {Nick, Host}) of + {ok, []} -> + true; + {ok, [#muc_registered{us_host = {U, _Host}}]} -> + U == LUS; + {error, _} -> + true + end. + +get_rooms(_LServer, Host) -> + case ejabberd_riak:get(muc_room, muc_room_schema()) of + {ok, Rs} -> + lists:filter( + fun(#muc_room{name_host = {_, H}}) -> + Host == H + end, Rs); + _Err -> + [] + end. + +get_nick(LServer, Host, From) -> + {LUser, LServer, _} = jid:tolower(From), + US = {LUser, LServer}, + case ejabberd_riak:get(muc_registered, + muc_registered_schema(), + {US, Host}) of + {ok, #muc_registered{nick = Nick}} -> Nick; + {error, _} -> error + end. + +set_nick(LServer, Host, From, Nick) -> + {LUser, LServer, _} = jid:tolower(From), + LUS = {LUser, LServer}, + {atomic, + case Nick of + <<"">> -> + ejabberd_riak:delete(muc_registered, {LUS, Host}); + _ -> + Allow = case ejabberd_riak:get_by_index( + muc_registered, + muc_registered_schema(), + <<"nick_host">>, {Nick, Host}) of + {ok, []} -> + true; + {ok, [#muc_registered{us_host = {U, _Host}}]} -> + U == LUS; + {error, _} -> + false + end, + if Allow -> + ejabberd_riak:put(#muc_registered{us_host = {LUS, Host}, + nick = Nick}, + muc_registered_schema(), + [{'2i', [{<<"nick_host">>, + {Nick, Host}}]}]); + true -> + false + end + end}. + +import(_LServer, #muc_room{} = R) -> + ejabberd_riak:put(R, muc_room_schema()); +import(_LServer, #muc_registered{us_host = {_, Host}, nick = Nick} = R) -> + ejabberd_riak:put(R, muc_registered_schema(), + [{'2i', [{<<"nick_host">>, {Nick, Host}}]}]). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +muc_room_schema() -> + {record_info(fields, muc_room), #muc_room{}}. + +muc_registered_schema() -> + {record_info(fields, muc_registered), #muc_registered{}}. diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl new file mode 100644 index 000000000..9acd9f8d7 --- /dev/null +++ b/src/mod_muc_sql.erl @@ -0,0 +1,202 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 13 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_muc_sql). + +-behaviour(mod_muc). + +%% API +-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/1, import/2, export/1]). + +-include("jlib.hrl"). +-include("mod_muc.hrl"). +-include("logger.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + ok. + +store_room(LServer, Host, Name, Opts) -> + SName = ejabberd_odbc:escape(Name), + SHost = ejabberd_odbc:escape(Host), + SOpts = ejabberd_odbc:encode_term(Opts), + F = fun () -> + odbc_queries:update_t(<<"muc_room">>, + [<<"name">>, <<"host">>, <<"opts">>], + [SName, SHost, SOpts], + [<<"name='">>, SName, <<"' and host='">>, + SHost, <<"'">>]) + end, + ejabberd_odbc:sql_transaction(LServer, F). + +restore_room(LServer, Host, Name) -> + SName = ejabberd_odbc:escape(Name), + SHost = ejabberd_odbc:escape(Host), + case catch ejabberd_odbc:sql_query(LServer, + [<<"select opts from muc_room where name='">>, + SName, <<"' and host='">>, SHost, + <<"';">>]) of + {selected, [<<"opts">>], [[Opts]]} -> + mod_muc:opts_to_binary(ejabberd_odbc:decode_term(Opts)); + _ -> + error + end. + +forget_room(LServer, Host, Name) -> + SName = ejabberd_odbc:escape(Name), + SHost = ejabberd_odbc:escape(Host), + F = fun () -> + ejabberd_odbc:sql_query_t([<<"delete from muc_room where name='">>, + SName, <<"' and host='">>, SHost, + <<"';">>]) + end, + ejabberd_odbc:sql_transaction(LServer, F). + +can_use_nick(LServer, Host, JID, Nick) -> + SJID = jid:to_string(jid:tolower(jid:remove_resource(JID))), + SNick = ejabberd_odbc:escape(Nick), + SHost = ejabberd_odbc:escape(Host), + case catch ejabberd_odbc:sql_query(LServer, + [<<"select jid from muc_registered ">>, + <<"where nick='">>, SNick, + <<"' and host='">>, SHost, <<"';">>]) of + {selected, [<<"jid">>], [[SJID1]]} -> SJID == SJID1; + _ -> true + end. + +get_rooms(LServer, Host) -> + SHost = ejabberd_odbc:escape(Host), + case catch ejabberd_odbc:sql_query(LServer, + [<<"select name, opts from muc_room ">>, + <<"where host='">>, SHost, <<"';">>]) of + {selected, [<<"name">>, <<"opts">>], RoomOpts} -> + lists:map( + fun([Room, Opts]) -> + #muc_room{name_host = {Room, Host}, + opts = mod_muc:opts_to_binary( + ejabberd_odbc:decode_term(Opts))} + end, RoomOpts); + Err -> + ?ERROR_MSG("failed to get rooms: ~p", [Err]), + [] + end. + +get_nick(LServer, Host, From) -> + SJID = ejabberd_odbc:escape(jid:to_string(jid:tolower(jid:remove_resource(From)))), + SHost = ejabberd_odbc:escape(Host), + case catch ejabberd_odbc:sql_query(LServer, + [<<"select nick from muc_registered where " + "jid='">>, + SJID, <<"' and host='">>, SHost, + <<"';">>]) of + {selected, [<<"nick">>], [[Nick]]} -> Nick; + _ -> error + end. + +set_nick(LServer, Host, From, Nick) -> + JID = jid:to_string(jid:tolower(jid:remove_resource(From))), + SJID = ejabberd_odbc:escape(JID), + SNick = ejabberd_odbc:escape(Nick), + SHost = ejabberd_odbc:escape(Host), + F = fun () -> + case Nick of + <<"">> -> + ejabberd_odbc:sql_query_t( + [<<"delete from muc_registered where ">>, + <<"jid='">>, SJID, + <<"' and host='">>, Host, + <<"';">>]), + ok; + _ -> + Allow = case ejabberd_odbc:sql_query_t( + [<<"select jid from muc_registered ">>, + <<"where nick='">>, + SNick, + <<"' and host='">>, + SHost, <<"';">>]) of + {selected, [<<"jid">>], [[J]]} -> J == JID; + _ -> true + end, + if Allow -> + odbc_queries:update_t(<<"muc_registered">>, + [<<"jid">>, <<"host">>, + <<"nick">>], + [SJID, SHost, SNick], + [<<"jid='">>, SJID, + <<"' and host='">>, SHost, + <<"'">>]), + ok; + true -> + false + end + end + end, + ejabberd_odbc:sql_transaction(LServer, F). + +export(_Server) -> + [{muc_room, + fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) -> + case str:suffix(Host, RoomHost) of + true -> + SName = ejabberd_odbc:escape(Name), + SRoomHost = ejabberd_odbc:escape(RoomHost), + SOpts = ejabberd_odbc:encode_term(Opts), + [[<<"delete from muc_room where name='">>, SName, + <<"' and host='">>, SRoomHost, <<"';">>], + [<<"insert into muc_room(name, host, opts) ", + "values (">>, + <<"'">>, SName, <<"', '">>, SRoomHost, + <<"', '">>, SOpts, <<"');">>]]; + false -> + [] + end + end}, + {muc_registered, + fun(Host, #muc_registered{us_host = {{U, S}, RoomHost}, + nick = Nick}) -> + case str:suffix(Host, RoomHost) of + true -> + SJID = ejabberd_odbc:escape( + jid:to_string( + jid:make(U, S, <<"">>))), + SNick = ejabberd_odbc:escape(Nick), + SRoomHost = ejabberd_odbc:escape(RoomHost), + [[<<"delete from muc_registered where jid='">>, + SJID, <<"' and host='">>, SRoomHost, <<"';">>], + [<<"insert into muc_registered(jid, host, " + "nick) values ('">>, + SJID, <<"', '">>, SRoomHost, <<"', '">>, SNick, + <<"');">>]]; + false -> + [] + end + end}]. + +import(_LServer) -> + [{<<"select name, host, opts from muc_room;">>, + fun([Name, RoomHost, SOpts]) -> + Opts = mod_muc:opts_to_binary(ejabberd_odbc:decode_term(SOpts)), + #muc_room{name_host = {Name, RoomHost}, opts = Opts} + end}, + {<<"select jid, host, nick from muc_registered;">>, + fun([J, RoomHost, Nick]) -> + #jid{user = U, server = S} = jid:from_string(J), + #muc_registered{us_host = {{U, S}, RoomHost}, + nick = Nick} + end}]. + +import(_, _) -> + pass. + +%%%=================================================================== +%%% Internal functions +%%%===================================================================