From 680384c342a7f65e395c1333b932d3b67a6e6d3f Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 9 May 2018 10:30:00 +0300 Subject: [PATCH] Reduce IQ handler code copying --- src/ejabberd_local.erl | 60 +++--------------------------------- src/ejabberd_router.erl | 8 ++--- src/ejabberd_sm.erl | 52 ++----------------------------- src/gen_iq_handler.erl | 68 +++++++++++++++++++++++++++++++++++------ src/mod_muc.erl | 2 +- 5 files changed, 67 insertions(+), 123 deletions(-) diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 9d75c69f2..9f250fab3 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -32,10 +32,8 @@ %% API -export([start/0, start_link/0]). --export([route/1, process_iq/1, +-export([route/1, get_features/1, - register_iq_handler/4, - unregister_iq_handler/2, bounce_resource_packet/1, host_up/1, host_down/1]). @@ -54,8 +52,6 @@ -record(state, {}). --define(IQTABLE, local_iqtable). - %%==================================================================== %% API %%==================================================================== @@ -72,30 +68,6 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec process_iq(iq()) -> any(). -process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet) - when T == get; T == set -> - XMLNS = xmpp:get_ns(El), - Host = To#jid.lserver, - case ets:lookup(?IQTABLE, {Host, XMLNS}) of - [{_, Module, Function}] -> - gen_iq_handler:handle(Host, Module, Function, Packet); - [] -> - Txt = <<"No module is handling this query">>, - Err = xmpp:err_service_unavailable(Txt, Lang), - ejabberd_router:route_error(Packet, Err) - end; -process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet) - when T == get; T == set -> - Txt = case SubEls of - [] -> <<"No child elements found">>; - _ -> <<"Too many child elements">> - end, - Err = xmpp:err_bad_request(Txt, Lang), - ejabberd_router:route_error(Packet, Err); -process_iq(#iq{type = T}) when T == result; T == error -> - ok. - -spec route(stanza()) -> any(). route(Packet) -> try do_route(Packet) @@ -112,15 +84,6 @@ route_iq(IQ, Fun) -> route_iq(IQ, Fun, Timeout) -> ejabberd_router:route_iq(IQ, Fun, undefined, Timeout). --spec register_iq_handler(binary(), binary(), module(), function()) -> ok. -register_iq_handler(Host, XMLNS, Module, Fun) -> - gen_server:cast(?MODULE, - {register_iq_handler, Host, XMLNS, Module, Fun}). - --spec unregister_iq_handler(binary(), binary()) -> ok. -unregister_iq_handler(Host, XMLNS) -> - gen_server:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}). - -spec bounce_resource_packet(stanza()) -> ok | stop. bounce_resource_packet(#presence{to = #jid{lresource = <<"">>}}) -> ok; @@ -135,12 +98,7 @@ bounce_resource_packet(Packet) -> -spec get_features(binary()) -> [binary()]. get_features(Host) -> - get_features(ets:next(?IQTABLE, {Host, <<"">>}), Host, []). - -get_features({Host, XMLNS}, Host, XMLNSs) -> - get_features(ets:next(?IQTABLE, {Host, XMLNS}), Host, [XMLNS|XMLNSs]); -get_features(_, _, XMLNSs) -> - XMLNSs. + gen_iq_handler:get_features(?MODULE, Host). %%==================================================================== %% gen_server callbacks @@ -151,23 +109,13 @@ init([]) -> lists:foreach(fun host_up/1, ?MYHOSTS), ejabberd_hooks:add(host_up, ?MODULE, host_up, 10), ejabberd_hooks:add(host_down, ?MODULE, host_down, 100), - catch ets:new(?IQTABLE, [named_table, public, ordered_set, - {read_concurrency, true}]), + gen_iq_handler:start(?MODULE), update_table(), {ok, #state{}}. handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. -handle_cast({register_iq_handler, Host, XMLNS, Module, Function}, - State) -> - ets:insert(?IQTABLE, - {{Host, XMLNS}, Module, Function}), - {noreply, State}; -handle_cast({unregister_iq_handler, Host, XMLNS}, - State) -> - ets:delete(?IQTABLE, {Host, XMLNS}), - {noreply, State}; handle_cast(_Msg, State) -> {noreply, State}. handle_info({route, Packet}, State) -> @@ -197,7 +145,7 @@ do_route(Packet) -> if To#jid.luser /= <<"">> -> ejabberd_sm:route(Packet); is_record(Packet, iq), To#jid.lresource == <<"">> -> - process_iq(Packet); + gen_iq_handler:handle(?MODULE, Packet); Type == result; Type == error -> ok; true -> diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index feb79549d..f49e94194 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -306,12 +306,8 @@ is_my_host(Domain) -> end. -spec process_iq(iq()) -> any(). -process_iq(#iq{to = To} = IQ) -> - if To#jid.luser == <<"">> -> - ejabberd_local:process_iq(IQ); - true -> - ejabberd_sm:process_iq(IQ) - end. +process_iq(IQ) -> + gen_iq_handler:handle(IQ). -spec config_reloaded() -> ok. config_reloaded() -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 8a9893437..e35f31079 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -39,7 +39,6 @@ stop/0, route/1, route/2, - process_iq/1, open_session/5, open_session/6, close_session/4, @@ -58,8 +57,6 @@ get_vh_session_list/1, get_vh_session_number/1, get_vh_by_backend/1, - register_iq_handler/4, - unregister_iq_handler/2, force_update_presence/1, connected_users/0, connected_users_number/0, @@ -397,17 +394,6 @@ get_vh_session_number(Server) -> Mod = get_sm_backend(LServer), length(online(get_sessions(Mod, LServer))). --spec register_iq_handler(binary(), binary(), atom(), atom()) -> ok. - -register_iq_handler(Host, XMLNS, Module, Fun) -> - ?GEN_SERVER:cast(?MODULE, - {register_iq_handler, Host, XMLNS, Module, Fun}). - --spec unregister_iq_handler(binary(), binary()) -> ok. - -unregister_iq_handler(Host, XMLNS) -> - ?GEN_SERVER:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}). - %% Why the hell do we have so many similar kicks? c2s_handle_info(#{lang := Lang} = State, replaced) -> State1 = State#{replaced => true}, @@ -437,7 +423,7 @@ init([]) -> init_cache(), lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()), clean_cache(), - ets:new(sm_iqtable, [named_table, public, {read_concurrency, true}]), + gen_iq_handler:start(?MODULE), ejabberd_hooks:add(host_up, ?MODULE, host_up, 50), ejabberd_hooks:add(host_down, ?MODULE, host_down, 60), ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50), @@ -448,15 +434,6 @@ init([]) -> handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. -handle_cast({register_iq_handler, Host, XMLNS, Module, Function}, - State) -> - ets:insert(sm_iqtable, - {{Host, XMLNS}, Module, Function}), - {noreply, State}; -handle_cast({unregister_iq_handler, Host, XMLNS}, - State) -> - ets:delete(sm_iqtable, {Host, XMLNS}), - {noreply, State}; handle_cast(_Msg, State) -> {noreply, State}. handle_info({route, Packet}, State) -> @@ -664,7 +641,7 @@ do_route(#message{to = #jid{lresource = <<"">>}, type = T} = Packet) -> end; do_route(#iq{to = #jid{lresource = <<"">>}} = Packet) -> ?DEBUG("processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]), - process_iq(Packet); + gen_iq_handler:handle(?MODULE, Packet); do_route(Packet) -> ?DEBUG("processing packet to full JID:~n~s", [xmpp:pp(Packet)]), To = xmpp:get_to(Packet), @@ -849,31 +826,6 @@ get_max_user_sessions(LUser, Host) -> end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --spec process_iq(iq()) -> any(). -process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet) - when T == get; T == set -> - XMLNS = xmpp:get_ns(El), - Host = To#jid.lserver, - case ets:lookup(sm_iqtable, {Host, XMLNS}) of - [{_, Module, Function}] -> - gen_iq_handler:handle(Host, Module, Function, Packet); - [] -> - Txt = <<"No module is handling this query">>, - Err = xmpp:err_service_unavailable(Txt, Lang), - ejabberd_router:route_error(Packet, Err) - end; -process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet) - when T == get; T == set -> - Txt = case SubEls of - [] -> <<"No child elements found">>; - _ -> <<"Too many child elements">> - end, - Err = xmpp:err_bad_request(Txt, Lang), - ejabberd_router:route_error(Packet, Err); -process_iq(#iq{}) -> - ok. - -spec force_update_presence({binary(), binary()}) -> ok. force_update_presence({LUser, LServer}) -> diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 0982a9f46..15155ac1a 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -30,9 +30,9 @@ -behaviour(ejabberd_config). %% API --export([add_iq_handler/5, remove_iq_handler/3, handle/4, - process_iq/4, check_type/1, transform_module_options/1, - opt_type/1]). +-export([add_iq_handler/5, remove_iq_handler/3, handle/1, handle/2, + check_type/1, transform_module_options/1, + opt_type/1, start/1, get_features/2]). %% Deprecated functions -export([add_iq_handler/6, handle/5, iqdisc/1]). -deprecated([{add_iq_handler, 6}, {handle, 5}, {iqdisc, 1}]). @@ -46,17 +46,65 @@ %%==================================================================== %% API %%==================================================================== --spec add_iq_handler(module(), binary(), binary(), module(), atom()) -> ok. +-spec start(component()) -> ok. +start(Component) -> + catch ets:new(Component, [named_table, public, ordered_set, + {read_concurrency, true}, + {heir, erlang:group_leader(), none}]), + ok. + +-spec add_iq_handler(component(), binary(), binary(), module(), atom()) -> ok. add_iq_handler(Component, Host, NS, Module, Function) -> - Component:register_iq_handler(Host, NS, Module, Function). + ets:insert(Component, {{Host, NS}, Module, Function}), + ok. -spec remove_iq_handler(component(), binary(), binary()) -> ok. remove_iq_handler(Component, Host, NS) -> - Component:unregister_iq_handler(Host, NS). + ets:delete(Component, {Host, NS}), + ok. --spec handle(binary(), atom(), atom(), iq()) -> any(). -handle(Host, Module, Function, IQ) -> - process_iq(Host, Module, Function, IQ). +-spec handle(iq()) -> ok. +handle(#iq{to = To} = IQ) -> + Component = case To#jid.luser of + <<"">> -> ejabberd_local; + _ -> ejabberd_sm + end, + handle(Component, IQ). + +-spec handle(component(), iq()) -> ok. +handle(Component, + #iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet) + when T == get; T == set -> + XMLNS = xmpp:get_ns(El), + Host = To#jid.lserver, + case ets:lookup(Component, {Host, XMLNS}) of + [{_, Module, Function}] -> + process_iq(Host, Module, Function, Packet); + [] -> + Txt = <<"No module is handling this query">>, + Err = xmpp:err_service_unavailable(Txt, Lang), + ejabberd_router:route_error(Packet, Err) + end; +handle(_, #iq{type = T, lang = Lang, sub_els = SubEls} = Packet) + when T == get; T == set -> + Txt = case SubEls of + [] -> <<"No child elements found">>; + _ -> <<"Too many child elements">> + end, + Err = xmpp:err_bad_request(Txt, Lang), + ejabberd_router:route_error(Packet, Err); +handle(_, #iq{type = T}) when T == result; T == error -> + ok. + +-spec get_features(component(), binary()) -> [binary()]. +get_features(Component, Host) -> + get_features(Component, ets:next(Component, {Host, <<"">>}), Host, []). + +get_features(Component, {Host, XMLNS}, Host, XMLNSs) -> + get_features(Component, + ets:next(Component, {Host, XMLNS}), Host, [XMLNS|XMLNSs]); +get_features(_, _, _, XMLNSs) -> + XMLNSs. -spec process_iq(binary(), atom(), atom(), iq()) -> any(). process_iq(_Host, Module, Function, IQ) -> @@ -139,4 +187,4 @@ add_iq_handler(Component, Host, NS, Module, Function, _Type) -> -spec handle(binary(), atom(), atom(), any(), iq()) -> any(). handle(Host, Module, Function, _Opts, IQ) -> - handle(Host, Module, Function, IQ). + process_iq(Host, Module, Function, IQ). diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 2c10435b6..5a52c9bdd 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -399,7 +399,7 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, do_route1(_Host, _ServerHost, _Access, _HistorySize, _RoomShaper, _From, #jid{luser = <<"">>, lresource = <<"">>} = _To, #iq{} = IQ, _DefRoomOpts, _QueueType) -> - ejabberd_local:process_iq(IQ); + ejabberd_router:process_iq(IQ); do_route1(Host, ServerHost, Access, _HistorySize, _RoomShaper, From, #jid{luser = <<"">>, lresource = <<"">>} = _To, #message{lang = Lang, body = Body, type = Type} = Packet, _, _) ->