From b5b25d55b123a87ba3da7baaef070984280872f7 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Mon, 5 Jul 2021 01:03:05 +0200 Subject: [PATCH 01/13] fixing mongoose_cleanup_SUITE:cleaner_runs_hook_on_nodedown/1 test case --- src/ejabberd_hooks.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index bc774c1483..6bd69fb34d 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -279,7 +279,7 @@ run_hook([{_Priority, Module, Function} | Ls], Key, Acc, Args) -> Res = hook_apply_function(Module, Function, Acc, Args), case Res of {'EXIT', Reason} -> - error_running_hook(Reason, Key, Args), + ?MODULE:error_running_hook(Reason, Key, Args), run_hook(Ls, Key, Acc, Args); stop -> stopped; From 32a68ff8bdba548138b5209752bfa3fb7cbe7a7b Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Thu, 17 Jun 2021 08:40:18 +0200 Subject: [PATCH 02/13] initial gen_hooks implementation --- src/gen_hook.erl | 247 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 src/gen_hook.erl diff --git a/src/gen_hook.erl b/src/gen_hook.erl new file mode 100644 index 0000000000..61c35ee3c6 --- /dev/null +++ b/src/gen_hook.erl @@ -0,0 +1,247 @@ +-module(gen_hook). + +-behaviour(gen_server). + +%% External exports +-export([start_link/0, + add_handler/5, + delete_handler/5, + add_handlers/1, + delete_handlers/1, + run_fold/4]). + +%% gen_server callbacks +-export([init/1, + handle_call/3, + handle_cast/2, + code_change/3, + handle_info/2, + terminate/2]). + +%% exported for unit tests only +-export([error_running_hook/4]). + +-include("mongoose.hrl"). + +-type hook_name() :: atom(). +-type hook_tag() :: any(). + +%% while Accumulator is not limited to any type, it's recommended to use maps. +-type hook_acc() :: any(). +-type hook_params() :: map(). +-type hook_extra() :: map(). + +-type hook_fn_ret_value() :: {ok | stop, NewAccumulator :: hook_acc()}. +-type hook_fn() :: %% see run_fold/4 documentation + fun((Accumulator :: hook_acc(), + ExecutionParameters :: hook_params(), + ExtraParameters :: hook_extra()) -> hook_fn_ret_value()). + +-type key() :: {HookName :: atom(), + Tag :: any()}. + +-record(hook_handler, {key :: key(), + %% 'prio' field must go right after the 'key', + %% this is required for the proper sorting. + prio :: pos_integer(), + fn :: hook_fn(), + extra :: map()}). + +-export_type([hook_fn/0]). + +-define(TABLE, ?MODULE). +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +%% @doc Add a handler for a hook. +%% Priority is used to sort the calls (lower numbers are executed first). +-spec add_handler(HookName :: hook_name(), + Tag :: hook_tag(), + Function :: hook_fn(), + Extra :: hook_extra(), + Priority :: pos_integer()) -> ok. +add_handler(HookName, Tag, Function, Extra, Priority) when is_atom(HookName), + is_function(Function, 3), + is_map(Extra), + is_integer(Priority), + Priority > 0 -> + NewExtra = extend_extra(HookName, Tag, Extra), + Handler = #hook_handler{key = hook_key(HookName, Tag), + prio = Priority, + fn = Function, + extra = NewExtra}, + gen_server:call(?MODULE, {add_handler, Handler}). + +%% @doc Delete a hook handler. +%% It is important to indicate exactly the same information than when the call was added. +-spec delete_handler(HookName :: hook_name(), + Tag :: hook_tag(), + Function :: hook_fn(), + Extra :: hook_extra(), + Priority :: pos_integer()) -> ok. +delete_handler(HookName, Tag, Function, Extra, Priority) when is_atom(HookName), + is_function(Function, 3), + is_map(Extra), + is_integer(Priority), + Priority > 0 -> + NewExtra = extend_extra(HookName, Tag, Extra), + Handler = #hook_handler{key = hook_key(HookName, Tag), + prio = Priority, + fn = Function, + extra = NewExtra}, + gen_server:call(?MODULE, {delete_handler, Handler}). + +-spec add_handlers([{HookName :: hook_name(), + Tag :: hook_tag(), + Function :: hook_fn(), + Extra :: hook_extra(), + Priority :: pos_integer()}]) -> ok. +add_handlers(List) -> + [add_handler(HookName, Tag, Function, Extra, Priority) || + {HookName, Tag, Function, Extra, Priority} <- List, is_atom(HookName), + is_function(Function, 3), + is_map(Extra), + is_integer(Priority), + Priority > 0], + ok. + +-spec delete_handlers([{HookName :: hook_name(), + Tag :: hook_tag(), + Function :: hook_fn(), + Extra :: hook_extra(), + Priority :: pos_integer()}]) -> ok. +delete_handlers(List) -> + [delete_handler(HookName, Tag, Function, Extra, Priority) || + {HookName, Tag, Function, Extra, Priority} <- List, is_atom(HookName), + is_function(Function, 3), + is_map(Extra), + is_integer(Priority), + Priority > 0], + ok. + +%% @doc Run hook handlers in order of priority (lower number means higher priority). +%% * if hook handler returns {ok, NewAcc}, the NewAcc value is used +%% as an accumulator parameter for the following hook handler. +%% * if a hook handler returns {stop, NewAcc}, execution stops immediately +%% without invoking lower priority hook handlers. +%% * if hook handler crashes, the error is logged and the next hook handler +%% is executed. +%% Note that every hook handler MUST return a valid Acc. If hook handler is not +%% interested in changing Acc parameter (or even if Acc is not used for a hook +%% at all), it must return (pass through) an unchanged input accumulator value. +-spec run_fold(HookName :: hook_name(), + Tag :: hook_tag(), + Acc :: hook_acc(), + Params :: hook_params()) -> hook_fn_ret_value(). +run_fold(HookName, Tag, Acc, Params) -> + Key = hook_key(HookName, Tag), + case ets:lookup(?TABLE, Key) of + [{_, Ls}] -> + mongoose_metrics:increment_generic_hook_metric(Tag, HookName), + run_hook(Ls, Acc, Params); + [] -> + {ok, Acc} + end. + +%%%---------------------------------------------------------------------- +%%% gen_server callback functions +%%%---------------------------------------------------------------------- + +init([]) -> + ets:new(?TABLE, [named_table, {read_concurrency, true}]), + {ok, no_state}. + +handle_call({add_handler, #hook_handler{key = Key} = HookHandler}, _From, State) -> + Reply = case ets:lookup(?TABLE, Key) of + [{_, Ls}] -> + case lists:member(HookHandler, Ls) of + true -> + ok; + false -> + %% NB: lists:merge/2 returns sorted list! + NewLs = lists:merge(Ls, [HookHandler]), + ets:insert(?TABLE, {Key, NewLs}), + ok + end; + [] -> + NewLs = [HookHandler], + ets:insert(?TABLE, {Key, NewLs}), + create_hook_metric(Key), + ok + end, + {reply, Reply, State}; +handle_call({delete_handler, #hook_handler{key = Key} = HookHandler}, _From, State) -> + Reply = case ets:lookup(?TABLE, Key) of + [{_, Ls}] -> + NewLs = lists:delete(HookHandler, Ls), + ets:insert(?TABLE, {Key, NewLs}), + ok; + [] -> + ok + end, + {reply, Reply, State}; +handle_call(Request, From, State) -> + ?UNEXPECTED_CALL(Request, From), + {reply, bad_request, State}. + +handle_cast(Msg, State) -> + ?UNEXPECTED_CAST(Msg), + {noreply, State}. + +handle_info(Info, State) -> + ?UNEXPECTED_INFO(Info), + {noreply, State}. + +terminate(_Reason, _State) -> + ets:delete(?TABLE), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%---------------------------------------------------------------------- +%%% Internal functions +%%%---------------------------------------------------------------------- +-spec run_hook([#hook_handler{}], hook_acc(), hook_params()) -> hook_fn_ret_value(). +run_hook([], Acc, _Params) -> + {ok, Acc}; +run_hook([#hook_handler{fn = Function, extra = Extra} = Handler | Ls], Acc, Params) -> + case apply_hook_function(Function, Acc, Params, Extra) of + {'EXIT', Reason} -> + ?MODULE:error_running_hook(Reason, Handler, Acc, Params), + run_hook(Ls, Acc, Params); + {stop, NewAcc} -> + {stop, NewAcc}; + {ok, NewAcc} -> + run_hook(Ls, NewAcc, Params) + end. + +-spec apply_hook_function(hook_fn(), hook_acc(), hook_params(), hook_extra()) -> + hook_fn_ret_value() | {'EXIT', Reason :: any()}. +apply_hook_function(Function, Acc, Params, Extra) -> + safely:apply(Function, [Acc, Params, Extra]). + +error_running_hook(Reason, Handler, Acc, Params) -> + ?LOG_ERROR(#{what => hook_failed, + text => <<"Error running hook">>, + handler => Handler, + acc => Acc, + params => Params, + reason => Reason}). + +-spec hook_key(hook_name(), hook_tag()) -> key(). +hook_key(HookName, Tag) -> {HookName, Tag}. + +extend_extra(HookName, Tag, OriginalExtra) -> + ExtendedExtra = #{hook_name => HookName, hook_tag => Tag}, + %% KV pairs of the OriginalExtra map will remain unchanged, + %% only the new keys from the ExtendedExtra map will be added + %% to the NewExtra map + maps:merge(ExtendedExtra, OriginalExtra). + +-spec create_hook_metric(Key :: key()) -> any(). +create_hook_metric({HookName, Tag}) -> + mongoose_metrics:create_generic_hook_metric(Tag, HookName). From 10a116d71eae77ca99f9b9f021e312185eabbcc2 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Mon, 5 Jul 2021 20:54:12 +0200 Subject: [PATCH 03/13] initial rework of ejabberd_hooks module --- big_tests/tests/mod_ping_SUITE.erl | 28 ++-- big_tests/tests/push_SUITE.erl | 79 +++++---- big_tests/tests/sm_SUITE.erl | 41 +++-- src/ejabberd_hooks.erl | 249 ++++------------------------- src/ejabberd_sup.erl | 6 +- test/auth_tokens_SUITE.erl | 6 +- test/commands_SUITE.erl | 2 +- test/component_reg_SUITE.erl | 6 +- test/ejabberd_hooks_SUITE.erl | 35 +--- test/keystore_SUITE.erl | 2 +- test/mongoose_cleanup_SUITE.erl | 20 ++- test/mongooseim_metrics_SUITE.erl | 6 +- test/muc_light_SUITE.erl | 11 +- test/privacy_SUITE.erl | 2 +- test/roster_SUITE.erl | 2 +- test/router_SUITE.erl | 2 +- 16 files changed, 172 insertions(+), 325 deletions(-) diff --git a/big_tests/tests/mod_ping_SUITE.erl b/big_tests/tests/mod_ping_SUITE.erl index 029ae72950..9df29433bb 100644 --- a/big_tests/tests/mod_ping_SUITE.erl +++ b/big_tests/tests/mod_ping_SUITE.erl @@ -107,24 +107,30 @@ start_mod_ping(Opts) -> setup_pong_hook(Config) -> Pid = self(), HostType = domain_helper:host_type(mim), - Handler = mongoose_helper:successful_rpc(?MODULE, setup_pong_hook, [HostType, Pid]), - [{pong_handler, Handler} | Config]. + mongoose_helper:successful_rpc(?MODULE, setup_pong_hook, [HostType, Pid]), + [{pid, Pid} | Config]. setup_pong_hook(HostType, Pid) -> - Handler = fun(_Acc, _HostType, JID, _Response, _TDelta) -> - Pid ! {pong, jid:to_binary(jid:to_lower(JID))} - end, - ejabberd_hooks:add(user_ping_response, HostType, Handler, 50), - Handler. + gen_hook:add_handler(user_ping_response, HostType, + fun ?MODULE:pong_hook_handler/3, + #{pid => Pid}, 50). + +pong_hook_handler(Acc, + #{args := [_HostType, JID, _Response, _TDelta]} = _Params, + #{pid := Pid} = _Extra) -> + Pid ! {pong, jid:to_binary(jid:to_lower(JID))}, + {ok, Acc}. clear_pong_hook(Config) -> - {value, {_, Handler}, NConfig} = lists:keytake(pong_handler, 1, Config), + {value, {_, Pid}, NConfig} = lists:keytake(pid, 1, Config), HostType = domain_helper:host_type(mim), - mongoose_helper:successful_rpc(?MODULE, clear_pong_hook, [HostType, Handler]), + mongoose_helper:successful_rpc(?MODULE, clear_pong_hook, [HostType, Pid]), NConfig. -clear_pong_hook(HostType, Handler) -> - ejabberd_hooks:delete(user_ping_response, HostType, Handler, 50). +clear_pong_hook(HostType, Pid) -> + gen_hook:delete_handler(user_ping_response, HostType, + fun ?MODULE:pong_hook_handler/3, + #{pid => Pid}, 50). %%-------------------------------------------------------------------- %% Ping tests diff --git a/big_tests/tests/push_SUITE.erl b/big_tests/tests/push_SUITE.erl index 5187fc02eb..5b78982eb0 100644 --- a/big_tests/tests/push_SUITE.erl +++ b/big_tests/tests/push_SUITE.erl @@ -134,14 +134,14 @@ init_per_testcase(CaseName = push_notifications_not_listed_disco_when_not_availa escalus:init_per_testcase(CaseName, Config); init_per_testcase(CaseName, Config0) -> Config1 = escalus_fresh:create_users(Config0, [{bob, 1}, {alice, 1}, {kate, 1}]), - Config = add_pubsub_jid([{case_name, CaseName} | Config1]), + Config2 = add_pubsub_jid([{case_name, CaseName} | Config1]), - case ?config(pubsub_host, Config0) of - virtual -> - start_hook_listener(Config); - _ -> - start_route_listener(Config) - end, + Config = case ?config(pubsub_host, Config0) of + virtual -> + start_hook_listener(Config2); + _ -> + start_route_listener(Config2) + end, escalus:init_per_testcase(CaseName, Config). @@ -151,7 +151,12 @@ end_per_testcase(CaseName = push_notifications_listed_disco_when_available, Conf end_per_testcase(CaseName = push_notifications_not_listed_disco_when_not_available, Config) -> escalus:end_per_testcase(CaseName, Config); end_per_testcase(CaseName, Config) -> - rpc(ejabberd_router, unregister_route, [atom_to_binary(CaseName, utf8)]), + case ?config(pubsub_host, Config) of + virtual -> + stop_hook_listener(Config); + _ -> + stop_route_listener(Config) + end, escalus:end_per_testcase(CaseName, Config). %% --------------------- Helpers ------------------------ @@ -692,7 +697,12 @@ start_route_listener(Config) -> push_form_ns => push_helper:push_form_type() }, Handler = rpc(mongoose_packet_handler, new, [?MODULE, #{state => State}]), Domain = pubsub_domain(Config), - rpc(ejabberd_router, register_route, [Domain, Handler]). + rpc(ejabberd_router, register_route, [Domain, Handler]), + Config. + +stop_route_listener(Config) -> + Domain = pubsub_domain(Config), + rpc(ejabberd_router, unregister_route, [Domain]). process_packet(_Acc, _From, To, El, #{state := State}) -> #{ pid := TestCasePid, pub_options_ns := PubOptionsNS, push_form_ns := PushFormNS } = State, @@ -739,26 +749,41 @@ valid_ns_if_defined(NS, FormProplist) -> start_hook_listener(Config) -> TestCasePid = self(), PubSubJID = pubsub_jid(Config), - rpc(?MODULE, rpc_start_hook_handler, [TestCasePid, PubSubJID]). + rpc(?MODULE, rpc_start_hook_handler, [TestCasePid, PubSubJID]), + [{pid, TestCasePid}, {jid, PubSubJID} | Config]. + +stop_hook_listener(Config) -> + TestCasePid = proplists:get_value(pid, Config), + PubSubJID = proplists:get_value(jid, Config), + rpc(?MODULE, rpc_stop_hook_handler, [TestCasePid, PubSubJID]). rpc_start_hook_handler(TestCasePid, PubSubJID) -> - Handler = fun(Acc, _Host, [PayloadMap], OptionMap) -> - try jid:to_binary(mongoose_acc:get(push_notifications, pubsub_jid, Acc)) of - PubSubJIDBin when PubSubJIDBin =:= PubSubJID-> - TestCasePid ! push_notification(PubSubJIDBin, - maps:to_list(PayloadMap), - maps:to_list(OptionMap)); - _ -> ok - catch - C:R:S -> - TestCasePid ! #{ event => handler_error, - class => C, - reason => R, - stacktrace => S } - end, - Acc - end, - ejabberd_hooks:add(push_notifications, <<"localhost">>, Handler, 50). + gen_hook:add_handler(push_notifications, <<"localhost">>, + fun ?MODULE:hook_handler_fn/3, + #{pid => TestCasePid, jid => PubSubJID}, 50). + +hook_handler_fn(Acc, + #{args := [_Host, [PayloadMap], OptionMap]} = _Params, + #{pid := TestCasePid, jid := PubSubJID} = _Extra) -> + try jid:to_binary(mongoose_acc:get(push_notifications, pubsub_jid, Acc)) of + PubSubJIDBin when PubSubJIDBin =:= PubSubJID -> + TestCasePid ! push_notification(PubSubJIDBin, + maps:to_list(PayloadMap), + maps:to_list(OptionMap)); + _ -> ok + catch + C:R:S -> + TestCasePid ! #{event => handler_error, + class => C, + reason => R, + stacktrace => S} + end, + {ok, Acc}. + +rpc_stop_hook_handler(TestCasePid, PubSubJID) -> + gen_hook:delete_handler(push_notifications, <<"localhost">>, + fun ?MODULE:hook_handler_fn/3, + #{pid => TestCasePid, jid => PubSubJID}, 50). %%-------------------------------------------------------------------- %% Test helpers diff --git a/big_tests/tests/sm_SUITE.erl b/big_tests/tests/sm_SUITE.erl index bfd41a7f21..21df63604c 100644 --- a/big_tests/tests/sm_SUITE.erl +++ b/big_tests/tests/sm_SUITE.erl @@ -865,7 +865,7 @@ unacknowledged_message_hook_common(RestartConnectionFN, Config) -> AliceSpec0 = escalus_fresh:create_fresh_user(Config, alice), Resource = proplists:get_value(username, AliceSpec0), AliceSpec = [{resource, Resource} | AliceSpec0], - start_hook_listener(Resource), + HookHandlerExtra = start_hook_listener(Resource), {ok, Alice, _} = escalus_connection:start(AliceSpec, ConnSteps ++ [stream_resumption]), SMID = proplists:get_value(smid, Alice#client.props), escalus_connection:send(Alice, escalus_stanza:presence(<<"available">>)), @@ -912,7 +912,7 @@ unacknowledged_message_hook_common(RestartConnectionFN, Config) -> escalus:assert(is_chat_message, [<<"msg-3">>], wait_for_unacked_msg_hook(1, NewResource, 100)), escalus:assert(is_chat_message, [<<"msg-4">>], wait_for_unacked_msg_hook(1, NewResource, 100)), ?assertEqual(timeout, wait_for_unacked_msg_hook(0, Resource, 100)), - + stop_hook_listener(HookHandlerExtra), escalus_connection:stop(Bob). resume_session(Config) -> @@ -1323,20 +1323,33 @@ start_hook_listener(Resource) -> TestCasePid = self(), rpc(mim(), ?MODULE, rpc_start_hook_handler, [TestCasePid, Resource, host_type()]). +stop_hook_listener(HookExtra) -> + rpc(mim(), ?MODULE, rpc_stop_hook_handler, [HookExtra, host_type()]). + rpc_start_hook_handler(TestCasePid, User, HostType) -> LUser=jid:nodeprep(User), - Handler = fun(Acc, Jid) -> - {U, _S, R} = jid:to_lower(Jid), - case U of - LUser -> - Counter = mongoose_acc:get(sm_test, counter, 0, Acc), - El = mongoose_acc:element(Acc), - TestCasePid ! {sm_test, Counter, R, El}, - mongoose_acc:set_permanent(sm_test, counter, Counter + 1, Acc); - _ -> Acc - end - end, - ejabberd_hooks:add(unacknowledged_message, HostType, Handler, 50). + gen_hook:add_handler(unacknowledged_message, HostType, + fun ?MODULE:hook_handler_fn/3, + #{luser => LUser, pid => TestCasePid}, 50), + #{luser => LUser, pid => TestCasePid}. + +rpc_stop_hook_handler(HookExtra, HostType) -> + gen_hook:delete_handler(unacknowledged_message, HostType, + fun ?MODULE:hook_handler_fn/3, + HookExtra, 50). + +hook_handler_fn(Acc, + #{args := [Jid]} = _Params, + #{luser := LUser, pid := TestCasePid} = _Extra) -> + {U, _S, R} = jid:to_lower(Jid), + case U of + LUser -> + Counter = mongoose_acc:get(sm_test, counter, 0, Acc), + El = mongoose_acc:element(Acc), + TestCasePid ! {sm_test, Counter, R, El}, + {ok, mongoose_acc:set_permanent(sm_test, counter, Counter + 1, Acc)}; + _ -> {ok, Acc} + end. wait_for_unacked_msg_hook(Counter, Res, Timeout) -> receive diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 6bd69fb34d..040eb99c19 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -26,72 +26,36 @@ -module(ejabberd_hooks). -author('alexey@process-one.net'). --behaviour(gen_server). %% External exports --export([start_link/0, - add/4, - add/5, - delete/4, +-export([add/5, delete/5, run_global/3, run_for_host_type/4]). -%% gen_server callbacks --export([init/1, - handle_call/3, - handle_cast/2, - code_change/3, - handle_info/2, - terminate/2]). - -export([add/1, delete/1]). --export([error_running_hook/3]). - -include("mongoose.hrl"). -type hook() :: {HookName :: atom(), - HostType :: binary() | global, - Module :: module() | undefined, - Fn :: fun() | atom(), + HostType :: mongooseim:host_type() | global, + Module :: module(), + Fn :: atom(), Priority:: integer()}. --type key() :: {HookName :: atom(), - HostType :: binary() | global}. - --type element() :: {Priority:: integer(), %% must be first to ensure proper sorting - Module :: module() | undefined, - Fn :: fun() | atom()}. - --record(state, {}). - -export_type([hook/0]). - %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start_link() -> - gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []). - -%% @doc Add a fun to the given hook. -%% The integer Priority is used to sort the calls: -%% low numbers are executed before high numbers. --spec add(HookName :: atom(), - HostType :: binary() | global, - Function :: fun() | atom(), - Priority :: integer()) -> ok. -add(HookName, HostType, Function, Priority) when is_function(Function) -> - add_hook({HookName, HostType, undefined, Function, Priority}). %% @doc Add a module and function to the given hook. %% The integer Priority is used to sort the calls: %% low numbers are executed before high numbers. -spec add(HookName :: atom(), - HostType :: binary() | global, - Module :: atom(), - Function :: fun() | atom(), + HostType :: mongooseim:host_type() | global, + Module :: module(), + Function :: atom(), Priority :: integer()) -> ok. add(HookName, HostType, Module, Function, Priority) -> add_hook({HookName, HostType, Module, Function, Priority}). @@ -101,23 +65,13 @@ add(Hooks) when is_list(Hooks) -> [add_hook(Hook) || Hook <- Hooks], ok. --spec add_hook(hook()) -> ok. -add_hook(Hook) -> - gen_server:call(ejabberd_hooks, {add, Hook}). %% @doc Delete a module and function from this hook. %% It is important to indicate exactly the same information than when the call was added. -spec delete(HookName :: atom(), - HostType :: binary() | global, - Function :: fun() | atom(), - Priority :: integer()) -> ok. -delete(HookName, HostType, Function, Priority) when is_function(Function) -> - delete_hook({HookName, HostType, undefined, Function, Priority}). - --spec delete(HookName :: atom(), - HostType :: binary() | global, - Module :: atom(), - Function :: fun() | atom(), + HostType :: mongooseim:host_type() | global, + Module :: module(), + Function :: atom(), Priority :: integer()) -> ok. delete(HookName, HostType, Module, Function, Priority) -> delete_hook({HookName, HostType, Module, Function, Priority}). @@ -127,17 +81,14 @@ delete(Hooks) when is_list(Hooks) -> [delete_hook(Hook) || Hook <- Hooks], ok. --spec delete_hook(hook()) -> ok. -delete_hook(Hook) -> - gen_server:call(ejabberd_hooks, {delete, Hook}). - -%% @doc run global hook, for more details see run_fold/4 documentation. +%% @doc run global hook. -spec run_global(HookName :: atom(), Acc :: term(), Args :: [term()]) -> NewAcc :: term() | stopped. run_global(HookName, Acc, Args) -> - run_fold(HookName, global, Acc, Args). + {_, RetValue} = gen_hook:run_fold(HookName, global, Acc, #{args => Args}), + RetValue. -%% @doc run hook for the host type, for more details see run_fold/4 documentation. +%% @doc run hook for the host type. -spec run_for_host_type(HookName :: atom(), HostType :: binary() | undefined, Acc :: term(), @@ -149,162 +100,30 @@ run_for_host_type(HookName, undefined, Acc, Args) -> hook_name => HookName, hook_acc => Acc, hook_args => Args}), Acc; run_for_host_type(HookName, HostType, Acc, Args) when is_binary(HostType) -> - run_fold(HookName, HostType, Acc, Args). - -%%%---------------------------------------------------------------------- -%%% Callback functions from gen_server -%%%---------------------------------------------------------------------- - -%%---------------------------------------------------------------------- -%% Func: init/1 -%% Returns: {ok, State} | -%% {ok, State, Timeout} | -%% ignore | -%% {stop, Reason} -%%---------------------------------------------------------------------- -init([]) -> - ets:new(hooks, [named_table, {read_concurrency, true}]), - {ok, #state{}}. - -%%---------------------------------------------------------------------- -%% Func: handle_call/3 -%% Returns: {reply, Reply, State} | -%% {reply, Reply, State, Timeout} | -%% {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, Reply, State} | (terminate/2 is called) -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_call({add, Hook}, _From, State) -> - {Key, El} = get_key_and_el(Hook), - Reply = case ets:lookup(hooks, Key) of - [{_, Ls}] -> - case lists:member(El, Ls) of - true -> - ok; - false -> - %% NB: lists:merge/2 returns sorted list! - NewLs = lists:merge(Ls, [El]), - ets:insert(hooks, {Key, NewLs}), - ok - end; - [] -> - NewLs = [El], - ets:insert(hooks, {Key, NewLs}), - create_hook_metric(Key), - ok - end, - {reply, Reply, State}; - -handle_call({delete, Hook}, _From, State) -> - {Key, El} = get_key_and_el(Hook), - Reply = case ets:lookup(hooks, Key) of - [{_, Ls}] -> - NewLs = lists:delete(El, Ls), - ets:insert(hooks, {Key, NewLs}), - ok; - [] -> - ok - end, - {reply, Reply, State}; - -handle_call(_Request, _From, State) -> - Reply = ok, - {reply, Reply, State}. - -%%---------------------------------------------------------------------- -%% Func: handle_cast/2 -%% Returns: {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_cast(_Msg, State) -> - {noreply, State}. - -%%---------------------------------------------------------------------- -%% Func: handle_info/2 -%% Returns: {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_info(_Info, State) -> - {noreply, State}. - -%%---------------------------------------------------------------------- -%% Func: terminate/2 -%% Purpose: Shutdown the server -%% Returns: any (ignored by gen_server) -%%---------------------------------------------------------------------- -terminate(_Reason, _State) -> - ets:delete(hooks), - ok. - - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. + {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, #{args => Args}), + RetValue. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -%% @doc Run the handlers of the hook in order. -%% The arguments passed to the hook handler function are: [Acc | Args]. -%% The result of a call is used as Acc for the next call. -%% If a call returns 'stop', no more calls are performed and 'stopped' is returned. -%% If a call returns {stop, NewAcc}, no more calls are performed and NewAcc is returned. -%% If hook doesn't need accumulator and doesn't care about the return value. The 'ok' -%% atom can be used as initial Acc value. -%% -%% Note that every hook handler MUST return a valid Acc. if any hook handler is not -%% interested in Acc parameter (or even if Acc is not used for a hook at all), it must -%% return (pass through) an unchanged input accumulator value. --spec run_fold(HookName :: atom(), - HostType :: global | binary(), - Acc :: term(), - Args :: [term()]) -> - term() | stopped. -run_fold(HookName, HostType, Acc, Args) -> - Key = {HookName, HostType}, - case ets:lookup(hooks, Key) of - [{_, Ls}] -> - mongoose_metrics:increment_generic_hook_metric(HostType, HookName), - run_hook(Ls, Key, Acc, Args); - [] -> - Acc - end. +-spec add_hook(hook()) -> ok. +add_hook({HookName, HostType, Module, Function, Priority}) when is_atom(Function) -> + gen_hook:add_handler(HookName, HostType, + fun gen_hook_fn_wrapper/3, + #{module => Module, function =>Function}, + Priority). -run_hook([], _Key, Val, _Args) -> - Val; -run_hook([{_Priority, Module, Function} | Ls], Key, Acc, Args) -> - Res = hook_apply_function(Module, Function, Acc, Args), - case Res of - {'EXIT', Reason} -> - ?MODULE:error_running_hook(Reason, Key, Args), - run_hook(Ls, Key, Acc, Args); - stop -> - stopped; - {stop, NewAcc} -> - NewAcc; - NewAcc -> - run_hook(Ls, Key, NewAcc, Args) +-spec delete_hook(hook()) -> ok. +delete_hook({HookName, HostType, Module, Function, Priority}) when is_atom(Function) -> + gen_hook:delete_handler(HookName, HostType, + fun gen_hook_fn_wrapper/3, + #{module => Module, function => Function}, + Priority). + +gen_hook_fn_wrapper(Acc, #{args := Args}, #{module := Module, function := Function}) -> + case apply(Module, Function, [Acc | Args]) of + stop -> {stop, stopped}; + {stop, NewAcc} -> {stop, NewAcc}; + NewAcc -> {ok, NewAcc} end. - -hook_apply_function(_Module, Function, Acc, Args) when is_function(Function) -> - safely:apply(Function, [Acc | Args]); -hook_apply_function(Module, Function, Acc, Args) -> - safely:apply(Module, Function, [Acc | Args]). - -error_running_hook(Reason, Key, Args) -> - ?LOG_ERROR(#{what => hook_failed, - text => <<"Error running hook">>, - hook_key => Key, args => Args, reason => Reason}). - --spec get_key_and_el(hook()) -> {key(), element()}. -get_key_and_el({HookName, HostType, Module, Function, Priority}) -> - Key = {HookName, HostType}, - El = {Priority, Module, Function}, - {Key, El}. - --spec create_hook_metric(Key :: key()) -> any(). -create_hook_metric({HookName, HostType}) -> - mongoose_metrics:create_generic_hook_metric(HostType, HookName). diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 4a43012b4b..97670ad0e3 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -38,12 +38,12 @@ start_link() -> init([]) -> Hooks = - {ejabberd_hooks, - {ejabberd_hooks, start_link, []}, + {gen_hook, + {gen_hook, start_link, []}, permanent, brutal_kill, worker, - [ejabberd_hooks]}, + [gen_hook]}, Cleaner = {mongoose_cleaner, {mongoose_cleaner, start_link, []}, diff --git a/test/auth_tokens_SUITE.erl b/test/auth_tokens_SUITE.erl index efed59b9ca..325c4a45ed 100644 --- a/test/auth_tokens_SUITE.erl +++ b/test/auth_tokens_SUITE.erl @@ -52,7 +52,7 @@ init_per_testcase(Test, Config) Test =:= validation_property; Test =:= choose_key_by_token_type -> mock_mongoose_metrics(), - Config1 = async_helper:start(Config, [{ejabberd_hooks, start_link, []}, + Config1 = async_helper:start(Config, [{gen_hook, start_link, []}, {gen_mod, start, []}]), mock_keystore(), mock_rdbms_backend(), @@ -64,13 +64,13 @@ init_per_testcase(validity_period_test, Config) -> mock_gen_iq_handler(), mock_ejabberd_commands(), async_helper:start(Config, [{gen_mod, start, []}, - {ejabberd_hooks, start_link, []}]); + {gen_hook, start_link, []}]); init_per_testcase(revoked_token_is_not_valid, Config) -> mock_mongoose_metrics(), mock_tested_backend(), Config1 = async_helper:start(Config, [{gen_mod, start, []}, - {ejabberd_hooks, start_link, []}]), + {gen_hook, start_link, []}]), mock_keystore(), Config1; diff --git a/test/commands_SUITE.erl b/test/commands_SUITE.erl index e845238604..6868d5b1b8 100644 --- a/test/commands_SUITE.erl +++ b/test/commands_SUITE.erl @@ -583,7 +583,7 @@ ec_holder() -> mc_holder() -> % we have to do it here to avoid race condition and random failures - {ok, Pid} = ejabberd_hooks:start_link(), + {ok, Pid} = gen_hook:start_link(), mongoose_commands:init(), mongoose_commands:register(commands_new()), receive diff --git a/test/component_reg_SUITE.erl b/test/component_reg_SUITE.erl index 382411d9d1..a8758817c4 100644 --- a/test/component_reg_SUITE.erl +++ b/test/component_reg_SUITE.erl @@ -24,12 +24,12 @@ init_per_suite(C) -> meck:expect(mongoose_domain_api, get_host_type, fun(_) -> {error, not_found} end), application:ensure_all_started(exometer_core), - ejabberd_hooks:start_link(), + gen_hook:start_link(), ejabberd_router:start_link(), C. init_per_testcase(_, C) -> - ejabberd_hooks:start_link(), + gen_hook:start_link(), C. end_per_suite(_C) -> @@ -48,7 +48,7 @@ registering(_C) -> ok. registering_with_local(_C) -> - ejabberd_hooks:start_link(), + gen_hook:start_link(), Dom = <<"aaa.bbb.com">>, ThisNode = node(), AnotherNode = 'another@nohost', diff --git a/test/ejabberd_hooks_SUITE.erl b/test/ejabberd_hooks_SUITE.erl index 65264462fa..5f7910fd3e 100644 --- a/test/ejabberd_hooks_SUITE.erl +++ b/test/ejabberd_hooks_SUITE.erl @@ -4,9 +4,8 @@ -define(HOST, <<"localhost">>). all() -> - [ a_fun_can_be_added, + [ a_module_fun_can_be_added, - a_fun_can_be_removed, a_module_fun_can_be_removed, hooks_run_launches_nullary_fun, @@ -33,20 +32,10 @@ end_per_suite(_C) -> application:stop(exometer_core). init_per_testcase(_, C) -> - ejabberd_hooks:start_link(), + gen_hook:start_link(), catch ets:new(local_config, [named_table]), C. -a_fun_can_be_added(_) -> - given_hooks_started(), - - % when - ejabberd_hooks:add(test_run_hook, ?HOST, fun(_) -> ok end, 1), - - % then - [{{test_run_hook,<<"localhost">>}, [{1,undefined,_}]}] = get_hooks(). - - a_module_fun_can_be_added(_) -> given_hooks_started(), given_module(hook_mod, fun_a, fun(_) -> ok end), @@ -55,19 +44,9 @@ a_module_fun_can_be_added(_) -> ejabberd_hooks:add(test_run_hook, ?HOST, hook_mod, fun_a, 1), % then - [{{test_run_hook,<<"localhost">>}, [{1,hook_mod,fun_a}]}] = get_hooks(). - - -a_fun_can_be_removed(_) -> - given_hooks_started(), - GivenFun = fun(_) -> ok end, - ejabberd_hooks:add(test_run_hook, ?HOST, GivenFun, 1), - - % when - ejabberd_hooks:delete(test_run_hook, ?HOST, GivenFun, 1), - - % then - [{{test_run_hook,<<"localhost">>}, []}] = get_hooks(). + [{{test_run_hook,<<"localhost">>}, + [{hook_handler, {test_run_hook,<<"localhost">>}, + 1,_FN,#{function := fun_a, module := hook_mod}}]}] = get_hooks(). a_module_fun_can_be_removed(_) -> given_hooks_started(), @@ -265,7 +244,7 @@ given_hooks_started() -> error_logger:tty(false), Fun = fun(all_metrics_are_global) -> false end, given_module(ejabberd_config, get_local_option, Fun), - ejabberd_hooks:start_link(). + gen_hook:start_link(). given_hook_added(HookName, ModName, FunName, Prio) -> ejabberd_hooks:add(HookName, ?HOST, ModName, FunName, Prio). @@ -280,4 +259,4 @@ given_fun(ModName, FunName, Fun) -> get_hooks() -> - ets:tab2list(hooks). + ets:tab2list(gen_hook). diff --git a/test/keystore_SUITE.erl b/test/keystore_SUITE.erl index 2eddb63b8f..9196084c29 100644 --- a/test/keystore_SUITE.erl +++ b/test/keystore_SUITE.erl @@ -28,7 +28,7 @@ end_per_suite(C) -> init_per_testcase(_, Config) -> mock_mongoose_metrics(), - async_helper:start(Config, ejabberd_hooks, start_link, []). + async_helper:start(Config, gen_hook, start_link, []). end_per_testcase(module_startup_non_unique_key_ids, C) -> clean_after_testcase(C); diff --git a/test/mongoose_cleanup_SUITE.erl b/test/mongoose_cleanup_SUITE.erl index a957047d41..42104a1235 100644 --- a/test/mongoose_cleanup_SUITE.erl +++ b/test/mongoose_cleanup_SUITE.erl @@ -6,7 +6,7 @@ -export([all/0, init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2]). --export([cleaner_runs_hook_on_nodedown/1]). +-export([cleaner_runs_hook_on_nodedown/1, notify_self_hook/3]). -export([auth_anonymous/1, last/1, stream_management/1, @@ -45,7 +45,7 @@ end_per_suite(Config) -> Config. init_per_testcase(T, Config) -> - {ok, _HooksServer} = ejabberd_hooks:start_link(), + {ok, _HooksServer} = gen_hook:start_link(), setup_meck(meck_mods(T)), Config. @@ -63,11 +63,11 @@ meck_mods(_) -> [exometer, ejabberd_sm, ejabberd_local, ejabberd_config]. %% ----------------------------------------------------- cleaner_runs_hook_on_nodedown(_Config) -> - meck:expect(ejabberd_hooks, error_running_hook, fun(_, _, _) -> ok end), + meck:expect(gen_hook, error_running_hook, fun(_, _, _, _) -> ok end), {ok, Cleaner} = mongoose_cleaner:start_link(), - Self = self(), - NotifySelf = fun(Acc, Node) -> Self ! {got_nodedown, Node}, Acc end, - ejabberd_hooks:add(node_cleanup, global, undefined, NotifySelf, 50), + gen_hook:add_handler(node_cleanup, global, + fun ?MODULE:notify_self_hook/3, + #{self => self()}, 50), FakeNode = fakename@fakehost, Cleaner ! {nodedown, FakeNode}, @@ -77,8 +77,12 @@ cleaner_runs_hook_on_nodedown(_Config) -> after timer:seconds(1) -> ct:fail({timeout, got_nodedown}) end, - ?assertEqual(false, meck:called(ejabberd_hooks, error_running_hook, - ['_', {node_cleanup, global}, '_'])). + ?assertEqual(false, meck:called(gen_hook, error_running_hook, + ['_', '_', '_', '_'])). + +notify_self_hook(Acc, #{args := [Node]}, #{self := Self}) -> + Self ! {got_nodedown, Node}, + {ok, Acc}. auth_anonymous(_Config) -> {U, S, R, JID, SID} = get_fake_session(), diff --git a/test/mongooseim_metrics_SUITE.erl b/test/mongooseim_metrics_SUITE.erl index 24a1a337b0..a967995331 100644 --- a/test/mongooseim_metrics_SUITE.erl +++ b/test/mongooseim_metrics_SUITE.erl @@ -37,12 +37,12 @@ init_per_suite(C) -> Sup = spawn(fun() -> mim_ct_sup:start_link(ejabberd_sup), Hooks = - {ejabberd_hooks, - {ejabberd_hooks, start_link, []}, + {gen_hook, + {gen_hook, start_link, []}, permanent, brutal_kill, worker, - [ejabberd_hooks]}, + [gen_hook]}, C2SSupervisor = {ejabberd_c2s_sup, {ejabberd_tmp_sup, start_link, [ejabberd_c2s_sup, ejabberd_c2s]}, diff --git a/test/muc_light_SUITE.erl b/test/muc_light_SUITE.erl index 993919db26..e8dc9c88f4 100644 --- a/test/muc_light_SUITE.erl +++ b/test/muc_light_SUITE.erl @@ -65,7 +65,7 @@ init_per_testcase(codec_calls, Config) -> ok = mnesia:start(), {ok, _} = application:ensure_all_started(exometer_core), ets:new(local_config, [named_table]), - ejabberd_hooks:start_link(), + gen_hook:start_link(), ejabberd_router:start_link(), mim_ct_sup:start_link(ejabberd_sup), gen_mod:start(), @@ -117,10 +117,11 @@ codec_calls(_Config) -> Sender = jid:from_binary(<<"bob@localhost/bbb">>), RoomUS = {<<"pokoik">>, <<"localhost">>}, HandleFun = fun(_, _, _) -> count_call(handler) end, - ejabberd_hooks:add(filter_room_packet, - <<"localhost">>, - fun(Acc, _HostType, _EvData) -> count_call(hook), Acc end, - 50), + gen_hook:add_handler(filter_room_packet, + <<"localhost">>, + fun(Acc, _Params, _Extra) -> count_call(hook), {ok, Acc} end, + #{}, + 50), % count_call/1 should've been called twice - by handler fun (for each affiliated user, % we have one) and by a filter_room_packet hook handler. diff --git a/test/privacy_SUITE.erl b/test/privacy_SUITE.erl index 6873eb66dd..546e3fb8b1 100644 --- a/test/privacy_SUITE.erl +++ b/test/privacy_SUITE.erl @@ -41,7 +41,7 @@ init_per_suite(C) -> init_per_testcase(_, C) -> catch ets:new(local_config, [named_table]), - ejabberd_hooks:start_link(), + gen_hook:start_link(), mod_privacy:start(<<"localhost">>, []), C. diff --git a/test/roster_SUITE.erl b/test/roster_SUITE.erl index 6679a536de..b3b4fcd3d6 100644 --- a/test/roster_SUITE.erl +++ b/test/roster_SUITE.erl @@ -58,7 +58,7 @@ end_per_suite(C) -> init_per_testcase(_TC, C) -> init_ets(), - ejabberd_hooks:start_link(), + gen_hook:start_link(), gen_mod:start(), gen_mod:start_module(host_type(), mod_roster, []), C. diff --git a/test/router_SUITE.erl b/test/router_SUITE.erl index 4cfdb16af2..ae773bbe89 100644 --- a/test/router_SUITE.erl +++ b/test/router_SUITE.erl @@ -48,7 +48,7 @@ init_per_group(routing, Config) -> (_) -> undefined end), - ejabberd_hooks:start_link(), + gen_hook:start_link(), ejabberd_router:start_link(), Config; init_per_group(schema, Config) -> From 8f71a78f22974444bff70a62db08522c761971bf Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Tue, 6 Jul 2021 22:53:41 +0200 Subject: [PATCH 04/13] updating mongoose_hooks --- src/ejabberd_hooks.erl | 30 +-- src/mongoose_hooks.erl | 407 +++++++++++++++--------------- test/commands_backend_SUITE.erl | 8 +- test/ejabberd_c2s_SUITE_mocks.erl | 22 +- test/ejabberd_hooks_SUITE.erl | 24 +- test/ejabberd_sm_SUITE.erl | 9 +- 6 files changed, 241 insertions(+), 259 deletions(-) diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 040eb99c19..440c7e7f67 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -26,12 +26,10 @@ -module(ejabberd_hooks). -author('alexey@process-one.net'). - %% External exports -export([add/5, delete/5, - run_global/3, - run_for_host_type/4]). + run_fold/4]). -export([add/1, delete/1]). @@ -65,9 +63,8 @@ add(Hooks) when is_list(Hooks) -> [add_hook(Hook) || Hook <- Hooks], ok. - %% @doc Delete a module and function from this hook. -%% It is important to indicate exactly the same information than when the call was added. +%% It is important to indicate exactly the same information as when the call was added. -spec delete(HookName :: atom(), HostType :: mongooseim:host_type() | global, Module :: module(), @@ -81,25 +78,14 @@ delete(Hooks) when is_list(Hooks) -> [delete_hook(Hook) || Hook <- Hooks], ok. -%% @doc run global hook. --spec run_global(HookName :: atom(), Acc :: term(), Args :: [term()]) -> - NewAcc :: term() | stopped. -run_global(HookName, Acc, Args) -> - {_, RetValue} = gen_hook:run_fold(HookName, global, Acc, #{args => Args}), - RetValue. -%% @doc run hook for the host type. --spec run_for_host_type(HookName :: atom(), - HostType :: binary() | undefined, - Acc :: term(), - Args :: [term()]) -> +%% @doc run the hook. +-spec run_fold(HookName :: atom(), + HostType :: mongooseim:host_type() | global, + Acc :: term(), + Args :: [term()]) -> NewAcc :: term() | stopped. -run_for_host_type(HookName, undefined, Acc, Args) -> - ?LOG_ERROR(#{what => undefined_host_type, - text => <<"Running hook for an undefined host type">>, - hook_name => HookName, hook_acc => Acc, hook_args => Args}), - Acc; -run_for_host_type(HookName, HostType, Acc, Args) when is_binary(HostType) -> +run_fold(HookName, HostType, Acc, Args) when is_binary(HostType); HostType =:= global -> {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, #{args => Args}), RetValue. diff --git a/src/mongoose_hooks.erl b/src/mongoose_hooks.erl index 09feb8d12d..2a13c7e8c2 100644 --- a/src/mongoose_hooks.erl +++ b/src/mongoose_hooks.erl @@ -7,6 +7,7 @@ -include("jlib.hrl"). -include("mod_privacy.hrl"). +-include("mongoose.hrl"). -export([adhoc_local_commands/4, adhoc_sm_commands/4, @@ -166,8 +167,8 @@ C2SState :: ejabberd_c2s:state(), Result :: term(). % ok | empty_state | HandlerState c2s_remote_hook(HostType, Tag, Args, HandlerState, C2SState) -> - ejabberd_hooks:run_for_host_type(c2s_remote_hook, HostType, HandlerState, - [Tag, Args, C2SState]). + run_hook_for_host_type(c2s_remote_hook, HostType, HandlerState, + [Tag, Args, C2SState]). -spec adhoc_local_commands(LServer, From, To, AdhocRequest) -> Result when LServer :: jid:lserver(), @@ -176,8 +177,8 @@ c2s_remote_hook(HostType, Tag, Args, HandlerState, C2SState) -> AdhocRequest :: adhoc:request(), Result :: mod_adhoc:command_hook_acc(). adhoc_local_commands(LServer, From, To, AdhocRequest) -> - ejabberd_hooks:run_for_host_type(adhoc_local_commands, LServer, empty, - [From, To, AdhocRequest]). + run_hook_for_host_type(adhoc_local_commands, LServer, empty, + [From, To, AdhocRequest]). -spec adhoc_sm_commands(LServer, From, To, AdhocRequest) -> Result when LServer :: jid:lserver(), @@ -186,8 +187,7 @@ adhoc_local_commands(LServer, From, To, AdhocRequest) -> AdhocRequest :: adhoc:request(), Result :: mod_adhoc:command_hook_acc(). adhoc_sm_commands(LServer, From, To, AdhocRequest) -> - ejabberd_hooks:run_for_host_type(adhoc_sm_commands, LServer, empty, - [From, To, AdhocRequest]). + run_hook_for_host_type(adhoc_sm_commands, LServer, empty, [From, To, AdhocRequest]). %%% @doc The `anonymous_purge_hook' hook is called when anonymous user's data is removed. -spec anonymous_purge_hook(LServer, Acc, LUser) -> Result when @@ -197,8 +197,7 @@ adhoc_sm_commands(LServer, From, To, AdhocRequest) -> Result :: mongose_acc:t(). anonymous_purge_hook(LServer, Acc, LUser) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(anonymous_purge_hook, HostType, Acc, - [LUser, LServer]). + run_hook_for_host_type(anonymous_purge_hook, HostType, Acc, [LUser, LServer]). -spec auth_failed(HostType, Server, Username) -> Result when HostType :: binary(), @@ -206,7 +205,7 @@ anonymous_purge_hook(LServer, Acc, LUser) -> Username :: jid:user() | unknown, Result :: ok. auth_failed(HostType, Server, Username) -> - ejabberd_hooks:run_for_host_type(auth_failed, HostType, ok, [Username, Server]). + run_hook_for_host_type(auth_failed, HostType, ok, [Username, Server]). -spec does_user_exist(HostType, Jid, RequestType) -> Result when HostType :: mongooseim:host_type(), @@ -214,33 +213,33 @@ auth_failed(HostType, Server, Username) -> RequestType :: ejabberd_auth:exist_type(), Result :: boolean(). does_user_exist(HostType, Jid, RequestType) -> - ejabberd_hooks:run_for_host_type(does_user_exist, HostType, - false, [HostType, Jid, RequestType]). + run_hook_for_host_type(does_user_exist, HostType, false, + [HostType, Jid, RequestType]). -spec remove_domain(HostType, Domain) -> Result when HostType :: binary(), Domain :: jid:lserver(), Result :: ok. remove_domain(HostType, Domain) -> - ejabberd_hooks:run_for_host_type(remove_domain, HostType, #{}, [HostType, Domain]). + run_hook_for_host_type(remove_domain, HostType, #{}, [HostType, Domain]). -spec node_cleanup(Node :: node()) -> Acc :: map(). node_cleanup(Node) -> - ejabberd_hooks:run_global(node_cleanup, #{}, [Node]). + run_global_hook(node_cleanup, #{}, [Node]). -spec ejabberd_ctl_process(Acc, Args) -> Result when Acc :: any(), Args :: [string()], Result :: any(). ejabberd_ctl_process(Acc, Args) -> - ejabberd_hooks:run_global(ejabberd_ctl_process, Acc, [Args]). + run_global_hook(ejabberd_ctl_process, Acc, [Args]). -spec failed_to_store_message(Acc) -> Result when Acc :: mongoose_acc:t(), Result :: mongoose_acc:t(). failed_to_store_message(Acc) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(failed_to_store_message, HostType, Acc, []). + run_hook_for_host_type(failed_to_store_message, HostType, Acc, []). %%% @doc The `filter_local_packet' hook is called to filter out %%% stanzas routed with `mongoose_local_delivery'. @@ -253,7 +252,7 @@ failed_to_store_message(Acc) -> Result :: drop | filter_packet_acc(). filter_local_packet(FilterAcc = {_From, _To, Acc, _Packet}) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(filter_local_packet, HostType, FilterAcc, []). + run_hook_for_host_type(filter_local_packet, HostType, FilterAcc, []). %%% @doc The `filter_packet' hook is called to filter out %%% stanzas routed with `mongoose_router_global'. @@ -261,7 +260,7 @@ filter_local_packet(FilterAcc = {_From, _To, Acc, _Packet}) -> Acc :: filter_packet_acc(), Result :: drop | filter_packet_acc(). filter_packet(Acc) -> - ejabberd_hooks:run_global(filter_packet, Acc, []). + run_global_hook(filter_packet, Acc, []). %%% @doc The `inbox_unread_count' hook is called to get the number %%% of unread messages in the inbox for a user. @@ -271,7 +270,7 @@ filter_packet(Acc) -> User :: jid:jid(), Result :: mongoose_acc:t(). inbox_unread_count(LServer, Acc, User) -> - ejabberd_hooks:run_for_host_type(inbox_unread_count, LServer, Acc, [User]). + run_hook_for_host_type(inbox_unread_count, LServer, Acc, [User]). %%% @doc The `get_key' hook is called to extract a key from `mod_keystore'. -spec get_key(LServer, KeyName) -> Result when @@ -279,8 +278,7 @@ inbox_unread_count(LServer, Acc, User) -> KeyName :: atom(), Result :: mod_keystore:key_list(). get_key(LServer, KeyName) -> - ejabberd_hooks:run_for_host_type(get_key, LServer, [], - [{KeyName, LServer}]). + run_hook_for_host_type(get_key, LServer, [], [{KeyName, LServer}]). -spec packet_to_component(Acc, From, To) -> Result when Acc :: mongoose_acc:t(), @@ -288,7 +286,7 @@ get_key(LServer, KeyName) -> To :: jid:jid(), Result :: mongoose_acc:t(). packet_to_component(Acc, From, To) -> - ejabberd_hooks:run_global(packet_to_component, Acc, [From, To]). + run_global_hook(packet_to_component, Acc, [From, To]). -spec presence_probe_hook(HostType, Acc, From, To, Pid) -> Result when HostType :: binary(), @@ -298,8 +296,7 @@ packet_to_component(Acc, From, To) -> Pid :: pid(), Result :: mongoose_acc:t(). presence_probe_hook(HostType, Acc, From, To, Pid) -> - ejabberd_hooks:run_for_host_type(presence_probe_hook, HostType, Acc, - [From, To, Pid]). + run_hook_for_host_type(presence_probe_hook, HostType, Acc, [From, To, Pid]). %%% @doc The `push_notifications' hook is called to push notifications. -spec push_notifications(Server, Acc, NotificationForms, Options) -> Result when @@ -309,8 +306,8 @@ presence_probe_hook(HostType, Acc, From, To, Pid) -> Options :: #{atom() => binary()}, Result :: ok | {error, any()}. push_notifications(Server, Acc, NotificationForms, Options) -> - ejabberd_hooks:run_for_host_type(push_notifications, Server, Acc, - [Server, NotificationForms, Options]). + run_hook_for_host_type(push_notifications, Server, Acc, + [Server, NotificationForms, Options]). %%% @doc The `register_command' hook is called when a command %%% is registered in `mongoose_commands'. @@ -318,7 +315,7 @@ push_notifications(Server, Acc, NotificationForms, Options) -> Command :: mongoose_commands:t(), Result :: drop. register_command(Command) -> - ejabberd_hooks:run_global(register_command, Command, []). + run_global_hook(register_command, Command, []). %%% @doc The `register_subhost' hook is called when a component %%% is registered for ejabberd_router. @@ -327,7 +324,7 @@ register_command(Command) -> IsHidden :: boolean(), Result :: any(). register_subhost(LDomain, IsHidden) -> - ejabberd_hooks:run_global(register_subhost, ok, [LDomain, IsHidden]). + run_global_hook(register_subhost, ok, [LDomain, IsHidden]). %%% @doc The `register_user' hook is called when a user is successfully %%% registered in an authentication backend. @@ -337,7 +334,7 @@ register_subhost(LDomain, IsHidden) -> LUser :: jid:luser(), Result :: any(). register_user(HostType, LServer, LUser) -> - ejabberd_hooks:run_for_host_type(register_user, HostType, ok, [LUser, LServer]). + run_hook_for_host_type(register_user, HostType, ok, [LUser, LServer]). %%% @doc The `remove_user' hook is called when a user is removed. -spec remove_user(Acc, LServer, LUser) -> Result when @@ -347,7 +344,7 @@ register_user(HostType, LServer, LUser) -> Result :: mongoose_acc:t(). remove_user(Acc, LServer, LUser) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(remove_user, HostType, Acc, [LUser, LServer]). + run_hook_for_host_type(remove_user, HostType, Acc, [LUser, LServer]). -spec resend_offline_messages_hook(HostType, Acc, JID) -> Result when HostType :: binary(), @@ -355,7 +352,7 @@ remove_user(Acc, LServer, LUser) -> JID :: jid:jid(), Result :: mongoose_acc:t(). resend_offline_messages_hook(HostType, Acc, JID) -> - ejabberd_hooks:run_for_host_type(resend_offline_messages_hook, HostType, Acc, [JID]). + run_hook_for_host_type(resend_offline_messages_hook, HostType, Acc, [JID]). %%% @doc The `rest_user_send_packet' hook is called when a user sends %%% a message using the REST API. @@ -367,8 +364,7 @@ resend_offline_messages_hook(HostType, Acc, JID) -> Result :: mongoose_acc:t(). rest_user_send_packet(Acc, From, To, Packet) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(rest_user_send_packet, HostType, Acc, - [From, To, Packet]). + run_hook_for_host_type(rest_user_send_packet, HostType, Acc, [From, To, Packet]). %%% @doc The `session_cleanup' hook is called when sm backend cleans up a user's session. -spec session_cleanup(Server, Acc, User, Resource, SID) -> Result when @@ -380,8 +376,8 @@ rest_user_send_packet(Acc, From, To, Packet) -> Result :: mongoose_acc:t(). session_cleanup(Server, Acc, User, Resource, SID) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(session_cleanup, HostType, Acc, - [User, Server, Resource, SID]). + run_hook_for_host_type(session_cleanup, HostType, Acc, + [User, Server, Resource, SID]). %%% @doc The `set_vcard' hook is called when the caller wants to set the VCard. -spec set_vcard(LServer, User, VCard) -> Result when @@ -390,8 +386,8 @@ session_cleanup(Server, Acc, User, Resource, SID) -> VCard :: exml:element(), Result :: ok | {error, any()}. set_vcard(LServer, User, VCard) -> - ejabberd_hooks:run_for_host_type(set_vcard, LServer, {error, no_handler_defined}, - [User, VCard]). + run_hook_for_host_type(set_vcard, LServer, {error, no_handler_defined}, + [User, VCard]). -spec unacknowledged_message(HostType, Acc, JID) -> Result when HostType :: binary(), @@ -399,7 +395,7 @@ set_vcard(LServer, User, VCard) -> JID :: jid:jid(), Result :: mongoose_acc:t(). unacknowledged_message(HostType, Acc, JID) -> - ejabberd_hooks:run_for_host_type(unacknowledged_message, HostType, Acc, [JID]). + run_hook_for_host_type(unacknowledged_message, HostType, Acc, [JID]). %%% @doc The `unregister_command' hook is called when a command %%% is unregistered from `mongoose_commands'. @@ -407,7 +403,7 @@ unacknowledged_message(HostType, Acc, JID) -> Command :: mongoose_commands:t(), Result :: drop. unregister_command(Command) -> - ejabberd_hooks:run_global(unregister_command, Command, []). + run_global_hook(unregister_command, Command, []). %%% @doc The `unregister_subhost' hook is called when a component %%% is unregistered from ejabberd_router. @@ -415,7 +411,7 @@ unregister_command(Command) -> LDomain :: binary(), Result :: any(). unregister_subhost(LDomain) -> - ejabberd_hooks:run_global(unregister_subhost, ok, [LDomain]). + run_global_hook(unregister_subhost, ok, [LDomain]). -spec user_available_hook(HostType, Acc, JID) -> Result when HostType :: binary(), @@ -423,7 +419,7 @@ unregister_subhost(LDomain) -> JID :: jid:jid(), Result :: mongoose_acc:t(). user_available_hook(HostType, Acc, JID) -> - ejabberd_hooks:run_for_host_type(user_available_hook, HostType, Acc, [JID]). + run_hook_for_host_type(user_available_hook, HostType, Acc, [JID]). %%% @doc The `user_ping_response' hook is called when a user responds to a ping. -spec user_ping_response(HostType, Acc, JID, Response, TDelta) -> Result when @@ -434,8 +430,8 @@ user_available_hook(HostType, Acc, JID) -> TDelta :: non_neg_integer(), Result :: mongoose_acc:t(). user_ping_response(HostType, Acc, JID, Response, TDelta) -> - ejabberd_hooks:run_for_host_type(user_ping_response, HostType, Acc, - [HostType, JID, Response, TDelta]). + run_hook_for_host_type(user_ping_response, HostType, Acc, + [HostType, JID, Response, TDelta]). %%% @doc The `user_ping_timeout' hook is called when there is a timeout %%% when waiting for a ping response from a user. @@ -444,7 +440,7 @@ user_ping_response(HostType, Acc, JID, Response, TDelta) -> JID :: jid:jid(), Result :: any(). user_ping_timeout(HostType, JID) -> - ejabberd_hooks:run_for_host_type(user_ping_timeout, HostType, ok, [JID]). + run_hook_for_host_type(user_ping_timeout, HostType, ok, [JID]). -spec user_receive_packet(HostType, Acc, JID, From, To, El) -> Result when HostType :: binary(), @@ -455,15 +451,14 @@ user_ping_timeout(HostType, JID) -> El :: exml:element(), Result :: mongoose_acc:t(). user_receive_packet(HostType, Acc, JID, From, To, El) -> - ejabberd_hooks:run_for_host_type(user_receive_packet, HostType, Acc, - [JID, From, To, El]). + run_hook_for_host_type(user_receive_packet, HostType, Acc, [JID, From, To, El]). -spec user_sent_keep_alive(HostType, JID) -> Result when HostType :: binary(), JID :: jid:jid(), Result :: any(). user_sent_keep_alive(HostType, JID) -> - ejabberd_hooks:run_for_host_type(user_sent_keep_alive, HostType, ok, [JID]). + run_hook_for_host_type(user_sent_keep_alive, HostType, ok, [JID]). %%% @doc A hook called when a user sends an XMPP stanza. %%% The hook's handler is expected to accept four parameters: @@ -477,8 +472,7 @@ user_sent_keep_alive(HostType, JID) -> Result :: mongoose_acc:t(). user_send_packet(Acc, From, To, Packet) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(user_send_packet, HostType, Acc, - [From, To, Packet]). + run_hook_for_host_type(user_send_packet, HostType, Acc, [From, To, Packet]). %%% @doc The `vcard_set' hook is called to inform that the vcard %%% has been set in mod_vcard backend. @@ -488,7 +482,7 @@ user_send_packet(Acc, From, To, Packet) -> VCard :: exml:element(), Result :: any(). vcard_set(Server, LUser, VCard) -> - ejabberd_hooks:run_for_host_type(vcard_set, Server, ok, [LUser, Server, VCard]). + run_hook_for_host_type(vcard_set, Server, ok, [LUser, Server, VCard]). -spec xmpp_send_element(HostType, Acc, El) -> Result when HostType :: binary(), @@ -496,7 +490,7 @@ vcard_set(Server, LUser, VCard) -> El :: exml:element(), Result :: mongoose_acc:t(). xmpp_send_element(HostType, Acc, El) -> - ejabberd_hooks:run_for_host_type(xmpp_send_element, HostType, Acc, [El]). + run_hook_for_host_type(xmpp_send_element, HostType, Acc, [El]). %%% @doc The `xmpp_stanza_dropped' hook is called to inform that %%% an xmpp stanza has been dropped. @@ -507,8 +501,7 @@ xmpp_send_element(HostType, Acc, El) -> Packet :: exml:element(), Result :: any(). xmpp_stanza_dropped(HostType, From, To, Packet) -> - ejabberd_hooks:run_for_host_type(xmpp_stanza_dropped, HostType, ok, - [From, To, Packet]). + run_hook_for_host_type(xmpp_stanza_dropped, HostType, ok, [From, To, Packet]). %% C2S related hooks @@ -520,8 +513,8 @@ xmpp_stanza_dropped(HostType, From, To, Packet) -> Result :: [jid:simple_jid()]. c2s_broadcast_recipients(State, Type, From, Packet) -> HostType = ejabberd_c2s_state:host_type(State), - ejabberd_hooks:run_for_host_type(c2s_broadcast_recipients, HostType, [], - [State, Type, From, Packet]). + run_hook_for_host_type(c2s_broadcast_recipients, HostType, [], + [State, Type, From, Packet]). -spec c2s_filter_packet(State, Feature, To, Packet) -> Result when State :: ejabberd_c2s:state(), @@ -531,8 +524,8 @@ c2s_broadcast_recipients(State, Type, From, Packet) -> Result :: boolean(). c2s_filter_packet(State, Feature, To, Packet) -> HostType = ejabberd_c2s_state:host_type(State), - ejabberd_hooks:run_for_host_type(c2s_filter_packet, HostType, true, - [State, Feature, To, Packet]). + run_hook_for_host_type(c2s_filter_packet, HostType, true, + [State, Feature, To, Packet]). -spec c2s_preprocessing_hook(HostType, Acc, State) -> Result when HostType :: mongooseim:host_type(), @@ -540,7 +533,7 @@ c2s_filter_packet(State, Feature, To, Packet) -> State :: ejabberd_c2s:state(), Result :: mongoose_acc:t(). c2s_preprocessing_hook(HostType, Acc, State) -> - ejabberd_hooks:run_for_host_type(c2s_preprocessing_hook, HostType, Acc, [State]). + run_hook_for_host_type(c2s_preprocessing_hook, HostType, Acc, [State]). -spec c2s_presence_in(State, From, To, Packet) -> Result when State :: ejabberd_c2s:state(), @@ -550,14 +543,14 @@ c2s_preprocessing_hook(HostType, Acc, State) -> Result :: ejabberd_c2s:state(). c2s_presence_in(State, From, To, Packet) -> HostType = ejabberd_c2s_state:host_type(State), - ejabberd_hooks:run_for_host_type(c2s_presence_in, HostType, State, [From, To, Packet]). + run_hook_for_host_type(c2s_presence_in, HostType, State, [From, To, Packet]). -spec c2s_stream_features(HostType, LServer) -> Result when HostType :: mongooseim:host_type(), LServer :: jid:lserver(), Result :: [exml:element()]. c2s_stream_features(HostType, LServer) -> - ejabberd_hooks:run_for_host_type(c2s_stream_features, HostType, [], [HostType, LServer]). + run_hook_for_host_type(c2s_stream_features, HostType, [], [HostType, LServer]). -spec c2s_unauthenticated_iq(HostType, Server, IQ, IP) -> Result when HostType :: mongooseim:host_type(), @@ -566,21 +559,20 @@ c2s_stream_features(HostType, LServer) -> IP :: {inet:ip_address(), inet:port_number()} | undefined, Result :: exml:element() | empty. c2s_unauthenticated_iq(HostType, Server, IQ, IP) -> - ejabberd_hooks:run_for_host_type(c2s_unauthenticated_iq, HostType, empty, - [Server, IQ, IP]). + run_hook_for_host_type(c2s_unauthenticated_iq, HostType, empty, [Server, IQ, IP]). -spec c2s_update_presence(HostType, Acc) -> Result when HostType :: mongooseim:host_type(), Acc :: mongoose_acc:t(), Result :: mongoose_acc:t(). c2s_update_presence(HostType, Acc) -> - ejabberd_hooks:run_for_host_type(c2s_update_presence, HostType, Acc, []). + run_hook_for_host_type(c2s_update_presence, HostType, Acc, []). -spec check_bl_c2s(IP) -> Result when IP :: inet:ip_address(), Result :: boolean(). check_bl_c2s(IP) -> - ejabberd_hooks:run_global(check_bl_c2s, false, [IP]). + run_global_hook(check_bl_c2s, false, [IP]). -spec forbidden_session_hook(HostType, Acc, JID) -> Result when HostType :: mongooseim:host_type(), @@ -588,7 +580,7 @@ check_bl_c2s(IP) -> JID :: jid:jid(), Result :: mongoose_acc:t(). forbidden_session_hook(HostType, Acc, JID) -> - ejabberd_hooks:run_for_host_type(forbidden_session_hook, HostType, Acc, [JID]). + run_hook_for_host_type(forbidden_session_hook, HostType, Acc, [JID]). -spec session_opening_allowed_for_user(HostType, JID) -> Result when HostType :: mongooseim:host_type(), @@ -596,8 +588,7 @@ forbidden_session_hook(HostType, Acc, JID) -> Result :: allow | any(). %% anything else than 'allow' is interpreted %% as not allowed session_opening_allowed_for_user(HostType, JID) -> - ejabberd_hooks:run_for_host_type(session_opening_allowed_for_user, - HostType, allow, [JID]). + run_hook_for_host_type(session_opening_allowed_for_user, HostType, allow, [JID]). %% Privacy related hooks @@ -611,8 +602,8 @@ session_opening_allowed_for_user(HostType, JID) -> privacy_check_packet(Acc, JID, PrivacyList, FromToNameType, Dir) -> HostType = mongoose_acc:host_type(Acc), AccWithRes = mongoose_acc:set(hook, result, allow, Acc), - ejabberd_hooks:run_for_host_type(privacy_check_packet, HostType, AccWithRes, - [JID, PrivacyList, FromToNameType, Dir]). + run_hook_for_host_type(privacy_check_packet, HostType, AccWithRes, + [JID, PrivacyList, FromToNameType, Dir]). -spec privacy_get_user_list(HostType, JID) -> Result when HostType :: binary(), @@ -620,7 +611,7 @@ privacy_check_packet(Acc, JID, PrivacyList, FromToNameType, Dir) -> Result :: mongoose_privacy:userlist(). privacy_get_user_list(HostType, JID) -> %% TODO: ejabberd_c2s calls this hook with host type, fix other places. - ejabberd_hooks:run_for_host_type(privacy_get_user_list, HostType, #userlist{}, [JID]). + run_hook_for_host_type(privacy_get_user_list, HostType, #userlist{}, [JID]). -spec privacy_iq_get(HostType, Acc, From, To, IQ, PrivList) -> Result when HostType :: binary(), @@ -631,8 +622,7 @@ privacy_get_user_list(HostType, JID) -> PrivList :: mongoose_privacy:userlist(), Result :: mongoose_acc:t(). privacy_iq_get(HostType, Acc, From, To, IQ, PrivList) -> - ejabberd_hooks:run_for_host_type(privacy_iq_get, HostType, Acc, - [From, To, IQ, PrivList]). + run_hook_for_host_type(privacy_iq_get, HostType, Acc, [From, To, IQ, PrivList]). -spec privacy_iq_set(HostType, Acc, From, To, IQ) -> Result when HostType :: binary(), @@ -642,8 +632,7 @@ privacy_iq_get(HostType, Acc, From, To, IQ, PrivList) -> IQ :: jlib:iq(), Result :: mongoose_acc:t(). privacy_iq_set(HostType, Acc, From, To, IQ) -> - ejabberd_hooks:run_for_host_type(privacy_iq_set, HostType, Acc, - [From, To, IQ]). + run_hook_for_host_type(privacy_iq_set, HostType, Acc, [From, To, IQ]). -spec privacy_updated_list(HostType, OldList, NewList) -> Result when HostType :: binary(), @@ -651,8 +640,7 @@ privacy_iq_set(HostType, Acc, From, To, IQ) -> NewList :: mongoose_privacy:userlist(), Result :: false | mongoose_privacy:userlist(). privacy_updated_list(HostType, OldList, NewList) -> - ejabberd_hooks:run_for_host_type(privacy_updated_list, HostType, false, - [OldList, NewList]). + run_hook_for_host_type(privacy_updated_list, HostType, false, [OldList, NewList]). %% Session management related hooks @@ -664,8 +652,8 @@ privacy_updated_list(HostType, OldList, NewList) -> Result :: mongoose_acc:t(). offline_groupchat_message_hook(Acc, From, To, Packet) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(offline_groupchat_message_hook, HostType, Acc, - [From, To, Packet]). + run_hook_for_host_type(offline_groupchat_message_hook, HostType, Acc, + [From, To, Packet]). -spec offline_message_hook(Acc, From, To, Packet) -> Result when Acc :: mongoose_acc:t(), @@ -675,18 +663,18 @@ offline_groupchat_message_hook(Acc, From, To, Packet) -> Result :: mongoose_acc:t(). offline_message_hook(Acc, From, To, Packet) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(offline_message_hook, HostType, Acc, - [From, To, Packet]). + run_hook_for_host_type(offline_message_hook, HostType, Acc, [From, To, Packet]). -spec set_presence_hook(Acc, JID, Presence) -> Result when Acc :: mongoose_acc:t(), JID :: jid:jid(), Presence :: any(), Result :: mongoose_acc:t(). -set_presence_hook(Acc, #jid{luser = LUser, lserver = LServer, lresource = LResource}, Presence) -> +set_presence_hook(Acc, JID, Presence) -> + #jid{luser = LUser, lserver = LServer, lresource = LResource} = JID, HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(set_presence_hook, HostType, Acc, - [LUser, LServer, LResource, Presence]). + run_hook_for_host_type(set_presence_hook, HostType, Acc, + [LUser, LServer, LResource, Presence]). -spec sm_broadcast(Acc, From, To, Broadcast, SessionCount) -> Result when Acc :: mongoose_acc:t(), @@ -697,8 +685,8 @@ set_presence_hook(Acc, #jid{luser = LUser, lserver = LServer, lresource = LResou Result :: mongoose_acc:t(). sm_broadcast(Acc, From, To, Broadcast, SessionCount) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(sm_broadcast, HostType, Acc, - [From, To, Broadcast, SessionCount]). + run_hook_for_host_type(sm_broadcast, HostType, Acc, + [From, To, Broadcast, SessionCount]). -spec sm_filter_offline_message(HostType, From, To, Packet) -> Result when HostType :: binary(), @@ -707,8 +695,8 @@ sm_broadcast(Acc, From, To, Broadcast, SessionCount) -> Packet :: exml:element(), Result :: boolean(). sm_filter_offline_message(HostType, From, To, Packet) -> - ejabberd_hooks:run_for_host_type(sm_filter_offline_message, HostType, false, - [From, To, Packet]). + run_hook_for_host_type(sm_filter_offline_message, HostType, false, + [From, To, Packet]). -spec sm_register_connection_hook(HostType, SID, JID, Info) -> Result when HostType :: binary(), @@ -717,8 +705,8 @@ sm_filter_offline_message(HostType, From, To, Packet) -> Info :: ejabberd_sm:info(), Result :: ok. sm_register_connection_hook(HostType, SID, JID, Info) -> - ejabberd_hooks:run_for_host_type(sm_register_connection_hook, HostType, ok, - [HostType, SID, JID, Info]). + run_hook_for_host_type(sm_register_connection_hook, HostType, ok, + [HostType, SID, JID, Info]). -spec sm_remove_connection_hook(Acc, SID, JID, Info, Reason) -> Result when Acc :: mongoose_acc:t(), @@ -729,25 +717,26 @@ sm_register_connection_hook(HostType, SID, JID, Info) -> Result :: mongoose_acc:t(). sm_remove_connection_hook(Acc, SID, JID, Info, Reason) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(sm_remove_connection_hook, HostType, Acc, - [SID, JID, Info, Reason]). + run_hook_for_host_type(sm_remove_connection_hook, HostType, Acc, + [SID, JID, Info, Reason]). -spec unset_presence_hook(Acc, JID, Status) -> Result when Acc :: mongoose_acc:t(), JID:: jid:jid(), Status :: binary(), Result :: mongoose_acc:t(). -unset_presence_hook(Acc, #jid{luser = LUser, lserver = LServer, lresource = LResource}, Status) -> +unset_presence_hook(Acc, JID, Status) -> + #jid{luser = LUser, lserver = LServer, lresource = LResource} = JID, HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(unset_presence_hook, HostType, Acc, - [LUser, LServer, LResource, Status]). + run_hook_for_host_type(unset_presence_hook, HostType, Acc, + [LUser, LServer, LResource, Status]). -spec xmpp_bounce_message(Acc) -> Result when Acc :: mongoose_acc:t(), Result :: mongoose_acc:t(). xmpp_bounce_message(Acc) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(xmpp_bounce_message, HostType, Acc, []). + run_hook_for_host_type(xmpp_bounce_message, HostType, Acc, []). %% Roster related hooks @@ -758,14 +747,14 @@ xmpp_bounce_message(Acc) -> Result :: mongoose_acc:t(). roster_get(Acc, JID) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(roster_get, HostType, Acc, [JID]). + run_hook_for_host_type(roster_get, HostType, Acc, [JID]). %%% @doc The `roster_groups' hook is called to extract roster groups. -spec roster_groups(LServer) -> Result when LServer :: jid:lserver(), Result :: list(). roster_groups(LServer) -> - ejabberd_hooks:run_for_host_type(roster_groups, LServer, [], [LServer]). + run_hook_for_host_type(roster_groups, LServer, [], [LServer]). %%% @doc The `roster_get_jid_info' hook is called to determine the %%% subscription state between a given pair of users. @@ -781,8 +770,8 @@ roster_groups(LServer) -> RemoteJID :: jid:jid() | jid:simple_jid(), Result :: {mod_roster:subscription_state(), [binary()]}. roster_get_jid_info(HostType, ToJID, RemBareJID) -> - ejabberd_hooks:run_for_host_type(roster_get_jid_info, HostType, {none, []}, - [HostType, ToJID, RemBareJID]). + run_hook_for_host_type(roster_get_jid_info, HostType, {none, []}, + [HostType, ToJID, RemBareJID]). %%% @doc The `roster_get_subscription_lists' hook is called to extract %%% user's subscription list. @@ -792,8 +781,8 @@ roster_get_jid_info(HostType, ToJID, RemBareJID) -> JID :: jid:jid(), Result :: mongoose_acc:t(). roster_get_subscription_lists(HostType, Acc, JID) -> - ejabberd_hooks:run_for_host_type(roster_get_subscription_lists, HostType, Acc, - [jid:to_bare(JID)]). + run_hook_for_host_type(roster_get_subscription_lists, HostType, Acc, + [jid:to_bare(JID)]). %%% @doc The `roster_get_versioning_feature' hook is %%% called to determine if roster versioning is enabled. @@ -801,7 +790,7 @@ roster_get_subscription_lists(HostType, Acc, JID) -> HostType :: binary(), Result :: [exml:element()]. roster_get_versioning_feature(HostType) -> - ejabberd_hooks:run_for_host_type(roster_get_versioning_feature, HostType, [], [HostType]). + run_hook_for_host_type(roster_get_versioning_feature, HostType, [], [HostType]). %%% @doc The `roster_in_subscription' hook is called to determine %%% if a subscription presence is routed to a user. @@ -814,8 +803,8 @@ roster_get_versioning_feature(HostType) -> Result :: mongoose_acc:t(). roster_in_subscription(Acc, To, From, Type, Reason) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(roster_in_subscription, HostType, Acc, - [jid:to_bare(To), From, Type, Reason]). + run_hook_for_host_type(roster_in_subscription, HostType, Acc, + [jid:to_bare(To), From, Type, Reason]). %%% @doc The `roster_out_subscription' hook is called %%% when a user sends out subscription. @@ -827,8 +816,8 @@ roster_in_subscription(Acc, To, From, Type, Reason) -> Result :: mongoose_acc:t(). roster_out_subscription(Acc, From, To, Type) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(roster_out_subscription, HostType, Acc, - [jid:to_bare(From), To, Type]). + run_hook_for_host_type(roster_out_subscription, HostType, Acc, + [jid:to_bare(From), To, Type]). %%% @doc The `roster_process_item' hook is called when a user's roster is set. -spec roster_process_item(HostType, LServer, Item) -> Result when @@ -837,7 +826,7 @@ roster_out_subscription(Acc, From, To, Type) -> Item :: mod_roster:roster(), Result :: mod_roster:roster(). roster_process_item(HostType, LServer, Item) -> - ejabberd_hooks:run_for_host_type(roster_process_item, HostType, Item, [LServer]). + run_hook_for_host_type(roster_process_item, HostType, Item, [LServer]). %%% @doc The `roster_push' hook is called when a roster item is %%% being pushed and roster versioning is not enabled. @@ -847,7 +836,7 @@ roster_process_item(HostType, LServer, Item) -> Item :: mod_roster:roster(), Result :: any(). roster_push(LServer, From, Item) -> - ejabberd_hooks:run_for_host_type(roster_push, LServer, ok, [From, Item]). + run_hook_for_host_type(roster_push, LServer, ok, [From, Item]). %%% @doc The `roster_set' hook is called when a user's roster is set through an IQ. -spec roster_set(HostType, From, To, SubEl) -> Result when @@ -857,7 +846,7 @@ roster_push(LServer, From, Item) -> SubEl :: exml:element(), Result :: any(). roster_set(HostType, From, To, SubEl) -> - ejabberd_hooks:run_for_host_type(roster_set, HostType, ok, [From, To, SubEl]). + run_hook_for_host_type(roster_set, HostType, ok, [From, To, SubEl]). %% MUC related hooks @@ -874,8 +863,7 @@ roster_set(HostType, From, To, SubEl) -> User :: jid:jid(), Result :: boolean(). is_muc_room_owner(HostType, Room, User) -> - ejabberd_hooks:run_for_host_type(is_muc_room_owner, HostType, false, - [HostType, Room, User]). + run_hook_for_host_type(is_muc_room_owner, HostType, false, [HostType, Room, User]). %%% @doc The `can_access_identity' hook is called to determine if %%% a given user can see the real identity of the people in a room. @@ -885,8 +873,7 @@ is_muc_room_owner(HostType, Room, User) -> User :: jid:jid(), Result :: boolean(). can_access_identity(HostType, Room, User) -> - ejabberd_hooks:run_for_host_type(can_access_identity, HostType, false, - [HostType, Room, User]). + run_hook_for_host_type(can_access_identity, HostType, false, [HostType, Room, User]). %%% @doc The `can_access_room' hook is called to determine %%% if a given user can access a room. @@ -896,8 +883,7 @@ can_access_identity(HostType, Room, User) -> User :: jid:jid(), Result :: boolean(). can_access_room(HostType, Room, User) -> - ejabberd_hooks:run_for_host_type(can_access_room, HostType, false, - [HostType, Room, User]). + run_hook_for_host_type(can_access_room, HostType, false, [HostType, Room, User]). %% MAM related hooks @@ -911,8 +897,7 @@ can_access_room(HostType, Room, User) -> OwnerJID :: jid:jid(), Result :: undefined | mod_mam:archive_id(). mam_archive_id(HostType, OwnerJID) -> - ejabberd_hooks:run_for_host_type(mam_archive_id, HostType, undefined, - [HostType, OwnerJID]). + run_hook_for_host_type(mam_archive_id, HostType, undefined, [HostType, OwnerJID]). %%% @doc The `mam_archive_size' hook is called to determine the size %%% of the archive for a given JID @@ -922,8 +907,8 @@ mam_archive_id(HostType, OwnerJID) -> OwnerJID :: jid:jid(), Result :: integer(). mam_archive_size(HostType, ArchiveID, OwnerJID) -> - ejabberd_hooks:run_for_host_type(mam_archive_size, HostType, 0, - [HostType, ArchiveID, OwnerJID]). + run_hook_for_host_type(mam_archive_size, HostType, 0, + [HostType, ArchiveID, OwnerJID]). %%% @doc The `mam_get_behaviour' hooks is called to determine if a message %%% should be archived or not based on a given pair of JIDs. @@ -935,8 +920,8 @@ mam_archive_size(HostType, ArchiveID, OwnerJID) -> RemoteJID :: jid:jid(), Result :: mod_mam:archive_behaviour(). mam_get_behaviour(HookServer, ArchiveID, OwnerJID, RemoteJID) -> - ejabberd_hooks:run_for_host_type(mam_get_behaviour, HookServer, always, - [HookServer, ArchiveID, OwnerJID, RemoteJID]). + run_hook_for_host_type(mam_get_behaviour, HookServer, always, + [HookServer, ArchiveID, OwnerJID, RemoteJID]). %%% @doc The `mam_set_prefs' hook is called to set a user's archive preferences. %%% @@ -951,9 +936,9 @@ mam_get_behaviour(HookServer, ArchiveID, OwnerJID, RemoteJID) -> NeverJIDs :: [jid:literel_jid()], Result :: any(). mam_set_prefs(HookServer, ArchiveID, OwnerJID, DefaultMode, AlwaysJIDs, NeverJIDs) -> - ejabberd_hooks:run_for_host_type(mam_set_prefs, HookServer, {error, not_implemented}, - [HookServer, ArchiveID, OwnerJID, - DefaultMode, AlwaysJIDs, NeverJIDs]). + run_hook_for_host_type(mam_set_prefs, HookServer, {error, not_implemented}, + [HookServer, ArchiveID, OwnerJID, + DefaultMode, AlwaysJIDs, NeverJIDs]). %%% @doc The `mam_get_prefs' hook is called to read %%% the archive settings for a given user. @@ -965,8 +950,8 @@ mam_set_prefs(HookServer, ArchiveID, OwnerJID, DefaultMode, AlwaysJIDs, NeverJI Result :: mod_mam:preference() | {error, Reason :: term()}. mam_get_prefs(HookServer, DefaultMode, ArchiveID, OwnerJID) -> InitialAccValue = {DefaultMode, [], []}, %% mod_mam:preference() type - ejabberd_hooks:run_for_host_type(mam_get_prefs, HookServer, InitialAccValue, - [HookServer, ArchiveID, OwnerJID]). + run_hook_for_host_type(mam_get_prefs, HookServer, InitialAccValue, + [HookServer, ArchiveID, OwnerJID]). %%% @doc The `mam_remove_archive' hook is called in order to %%% remove the entire archive for a particular user. @@ -975,8 +960,8 @@ mam_get_prefs(HookServer, DefaultMode, ArchiveID, OwnerJID) -> ArchiveID :: undefined | mod_mam:archive_id(), OwnerJID :: jid:jid(). mam_remove_archive(HookServer, ArchiveID, OwnerJID) -> - ejabberd_hooks:run_for_host_type(mam_remove_archive, HookServer, ok, - [HookServer, ArchiveID, OwnerJID]). + run_hook_for_host_type(mam_remove_archive, HookServer, ok, + [HookServer, ArchiveID, OwnerJID]). %%% @doc The `mam_lookup_messages' hook is to retrieve %%% archived messages for given search parameters. @@ -986,9 +971,8 @@ mam_remove_archive(HookServer, ArchiveID, OwnerJID) -> Result :: {ok, mod_mam:lookup_result()}. mam_lookup_messages(HookServer, Params) -> InitialLookupValue = {0, 0, []}, %% mod_mam:lookup_result() type - ejabberd_hooks:run_for_host_type(mam_lookup_messages, HookServer, - {ok, InitialLookupValue}, - [HookServer, Params]). + run_hook_for_host_type(mam_lookup_messages, HookServer, {ok, InitialLookupValue}, + [HookServer, Params]). %%% @doc The `mam_archive_message' hook is called in order %%% to store the message in the archive. @@ -998,8 +982,7 @@ mam_lookup_messages(HookServer, Params) -> Params :: mod_mam:archive_message_params(), Result :: ok | {error, timeout}. mam_archive_message(HookServer, Params) -> - ejabberd_hooks:run_for_host_type(mam_archive_message, HookServer, ok, - [HookServer, Params]). + run_hook_for_host_type(mam_archive_message, HookServer, ok, [HookServer, Params]). %% MAM MUC related hooks @@ -1020,8 +1003,8 @@ mam_archive_message(HookServer, Params) -> OwnerJID :: jid:jid(), Result :: undefined | mod_mam:archive_id(). mam_muc_archive_id(HookServer, OwnerJID) -> - ejabberd_hooks:run_for_host_type(mam_muc_archive_id, HookServer, undefined, - [HookServer, OwnerJID]). + run_hook_for_host_type(mam_muc_archive_id, HookServer, undefined, + [HookServer, OwnerJID]). %%% @doc The `mam_muc_archive_size' hook is called to determine %%% the archive size for a given room. @@ -1031,8 +1014,8 @@ mam_muc_archive_id(HookServer, OwnerJID) -> RoomJID :: jid:jid(), Result :: integer(). mam_muc_archive_size(HostType, ArchiveID, RoomJID) -> - ejabberd_hooks:run_for_host_type(mam_muc_archive_size, HostType, 0, - [HostType, ArchiveID, RoomJID]). + run_hook_for_host_type(mam_muc_archive_size, HostType, 0, + [HostType, ArchiveID, RoomJID]). %%% @doc The `mam_muc_get_behaviour' hooks is called to determine if a message should %%% be archived or not based on the given room and user JIDs. @@ -1045,8 +1028,8 @@ mam_muc_archive_size(HostType, ArchiveID, RoomJID) -> Result :: mod_mam:archive_behaviour(). mam_muc_get_behaviour(HostType, ArchiveID, RoomJID, RemoteJID) -> DefaultBehaviour = always, %% mod_mam:archive_behaviour() type - ejabberd_hooks:run_for_host_type(mam_muc_get_behaviour, HostType, DefaultBehaviour, - [HostType, ArchiveID, RoomJID, RemoteJID]). + run_hook_for_host_type(mam_muc_get_behaviour, HostType, DefaultBehaviour, + [HostType, ArchiveID, RoomJID, RemoteJID]). %%% @doc The `mam_muc_set_prefs' hook is called to set a room's archive preferences. %%% @@ -1062,9 +1045,9 @@ mam_muc_get_behaviour(HostType, ArchiveID, RoomJID, RemoteJID) -> Result :: any(). mam_muc_set_prefs(HostType, ArchiveID, RoomJID, DefaultMode, AlwaysJIDs, NeverJIDs) -> InitialAcc = {error, not_implemented}, - ejabberd_hooks:run_for_host_type(mam_muc_set_prefs, HostType, InitialAcc, - [HostType, ArchiveID, RoomJID, DefaultMode, - AlwaysJIDs, NeverJIDs]). + run_hook_for_host_type(mam_muc_set_prefs, HostType, InitialAcc, + [HostType, ArchiveID, RoomJID, DefaultMode, + AlwaysJIDs, NeverJIDs]). %%% @doc The `mam_muc_get_prefs' hook is called to read %%% the archive settings for a given room. @@ -1076,8 +1059,8 @@ mam_muc_set_prefs(HostType, ArchiveID, RoomJID, DefaultMode, AlwaysJIDs, NeverJI Result :: mod_mam:preference() | {error, Reason :: term()}. mam_muc_get_prefs(HostType, DefaultMode, ArchiveID, RoomJID) -> InitialAcc = {DefaultMode, [], []}, %% mod_mam:preference() type - ejabberd_hooks:run_for_host_type(mam_muc_get_prefs, HostType, InitialAcc, - [HostType, ArchiveID, RoomJID]). + run_hook_for_host_type(mam_muc_get_prefs, HostType, InitialAcc, + [HostType, ArchiveID, RoomJID]). %%% @doc The `mam_muc_remove_archive' hook is called in order to remove the entire %%% archive for a particular user. @@ -1086,8 +1069,8 @@ mam_muc_get_prefs(HostType, DefaultMode, ArchiveID, RoomJID) -> ArchiveID :: undefined | mod_mam:archive_id(), RoomJID :: jid:jid(). mam_muc_remove_archive(HostType, ArchiveID, RoomJID) -> - ejabberd_hooks:run_for_host_type(mam_muc_remove_archive, HostType, ok, - [HostType, ArchiveID, RoomJID]). + run_hook_for_host_type(mam_muc_remove_archive, HostType, ok, + [HostType, ArchiveID, RoomJID]). %%% @doc The `mam_muc_lookup_messages' hook is to retrieve archived %%% MUC messages for any given search parameters. @@ -1097,9 +1080,8 @@ mam_muc_remove_archive(HostType, ArchiveID, RoomJID) -> Result :: {ok, mod_mam:lookup_result()}. mam_muc_lookup_messages(HostType, Params) -> InitialLookupValue = {0, 0, []}, %% mod_mam:lookup_result() type - ejabberd_hooks:run_for_host_type(mam_muc_lookup_messages, HostType, - {ok, InitialLookupValue}, - [HostType, Params]). + run_hook_for_host_type(mam_muc_lookup_messages, HostType, {ok, InitialLookupValue}, + [HostType, Params]). %%% @doc The `mam_muc_archive_message' hook is called in order %%% to store the MUC message in the archive. @@ -1108,16 +1090,15 @@ mam_muc_lookup_messages(HostType, Params) -> Params :: mod_mam:archive_message_params(), Result :: ok | {error, timeout}. mam_muc_archive_message(HostType, Params) -> - ejabberd_hooks:run_for_host_type(mam_muc_archive_message, HostType, ok, - [HostType, Params]). + run_hook_for_host_type(mam_muc_archive_message, HostType, ok, [HostType, Params]). %%% @doc The `mam_muc_flush_messages' hook is run after the async bulk write %%% happens for MUC messages despite the result of the write. -spec mam_muc_flush_messages(HookServer :: jid:lserver(), MessageCount :: integer()) -> ok. mam_muc_flush_messages(HookServer, MessageCount) -> - ejabberd_hooks:run_for_host_type(mam_muc_flush_messages, HookServer, ok, - [HookServer, MessageCount]). + run_hook_for_host_type(mam_muc_flush_messages, HookServer, ok, + [HookServer, MessageCount]). %% GDPR related hooks @@ -1128,8 +1109,7 @@ mam_muc_flush_messages(HookServer, MessageCount) -> JID :: jid:jid(), Result :: ejabberd_gen_mam_archive:mam_pm_gdpr_data(). get_mam_pm_gdpr_data(HostType, JID) -> - ejabberd_hooks:run_for_host_type(get_mam_pm_gdpr_data, HostType, [], - [HostType, JID]). + run_hook_for_host_type(get_mam_pm_gdpr_data, HostType, [], [HostType, JID]). %%% @doc `get_mam_muc_gdpr_data' hook is called to provide %%% a user's archive for GDPR purposes. @@ -1138,8 +1118,7 @@ get_mam_pm_gdpr_data(HostType, JID) -> JID :: jid:jid(), Result :: ejabberd_gen_mam_archive:mam_muc_gdpr_data(). get_mam_muc_gdpr_data(HostType, JID) -> - ejabberd_hooks:run_for_host_type(get_mam_muc_gdpr_data, HostType, [], - [HostType, JID]). + run_hook_for_host_type(get_mam_muc_gdpr_data, HostType, [], [HostType, JID]). %%% @doc `get_personal_data' hook is called to retrieve %%% a user's personal data for GDPR purposes. @@ -1148,7 +1127,7 @@ get_mam_muc_gdpr_data(HostType, JID) -> JID :: jid:jid(), Result :: gdpr:personal_data(). get_personal_data(HostType, JID) -> - ejabberd_hooks:run_for_host_type(get_personal_data, HostType, [], [HostType, JID]). + run_hook_for_host_type(get_personal_data, HostType, [], [HostType, JID]). %% S2S related hooks @@ -1159,7 +1138,7 @@ get_personal_data(HostType, JID) -> Server :: jid:server(), Result :: any(). find_s2s_bridge(Name, Server) -> - ejabberd_hooks:run_global(find_s2s_bridge, undefined, [Name, Server]). + run_global_hook(find_s2s_bridge, undefined, [Name, Server]). %%% @doc `s2s_allow_host' hook is called to check whether a server %%% should be allowed to be connected to. @@ -1171,7 +1150,7 @@ find_s2s_bridge(Name, Server) -> S2SHost :: jid:server(), Result :: allow | deny. s2s_allow_host(MyHost, S2SHost) -> - ejabberd_hooks:run_global(s2s_allow_host, allow, [MyHost, S2SHost]). + run_global_hook(s2s_allow_host, allow, [MyHost, S2SHost]). %%% @doc `s2s_connect_hook' hook is called when a s2s connection is established. -spec s2s_connect_hook(Name, Server) -> Result when @@ -1179,7 +1158,7 @@ s2s_allow_host(MyHost, S2SHost) -> Server :: jid:server(), Result :: any(). s2s_connect_hook(Name, Server) -> - ejabberd_hooks:run_global(s2s_connect_hook, ok, [Name, Server]). + run_global_hook(s2s_connect_hook, ok, [Name, Server]). %%% @doc `s2s_send_packet' hook is called when a message is routed. -spec s2s_send_packet(Acc, From, To, Packet) -> Result when @@ -1189,7 +1168,7 @@ s2s_connect_hook(Name, Server) -> Packet :: exml:element(), Result :: mongoose_acc:t(). s2s_send_packet(Acc, From, To, Packet) -> - ejabberd_hooks:run_global(s2s_send_packet, Acc, [From, To, Packet]). + run_global_hook(s2s_send_packet, Acc, [From, To, Packet]). %%% @doc `s2s_stream_features' hook is used to extract %%% the stream management features supported by the server. @@ -1198,7 +1177,7 @@ s2s_send_packet(Acc, From, To, Packet) -> LServer :: jid:lserver(), Result :: [exml:element()]. s2s_stream_features(HostType, LServer) -> - ejabberd_hooks:run_for_host_type(s2s_stream_features, HostType, [], [HostType, LServer]). + run_hook_for_host_type(s2s_stream_features, HostType, [], [HostType, LServer]). %%% @doc `s2s_receive_packet' hook is called when %%% an incoming stanza is routed by the server. @@ -1206,54 +1185,55 @@ s2s_stream_features(HostType, LServer) -> Acc :: mongoose_acc:t(), Result :: mongoose_acc:t(). s2s_receive_packet(Acc) -> - ejabberd_hooks:run_global(s2s_receive_packet, Acc, []). + run_global_hook(s2s_receive_packet, Acc, []). %% Discovery related hooks %%% @doc `disco_local_identity' hook is called to get the identity of the server. --spec disco_local_identity(mongoose_disco:identity_acc()) -> mongoose_disco:identity_acc(). +-spec disco_local_identity(mongoose_disco:identity_acc()) -> + mongoose_disco:identity_acc(). disco_local_identity(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_local_identity, HostType, Acc, []). + run_hook_for_host_type(disco_local_identity, HostType, Acc, []). %%% @doc `disco_sm_identity' hook is called to get the identity of the %%% client when a discovery IQ gets to session management. -spec disco_sm_identity(mongoose_disco:identity_acc()) -> mongoose_disco:identity_acc(). disco_sm_identity(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_sm_identity, HostType, Acc, []). + run_hook_for_host_type(disco_sm_identity, HostType, Acc, []). %%% @doc `disco_local_items' hook is called to extract items associated with the server. -spec disco_local_items(mongoose_disco:item_acc()) -> mongoose_disco:item_acc(). disco_local_items(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_local_items, HostType, Acc, []). + run_hook_for_host_type(disco_local_items, HostType, Acc, []). %%% @doc `disco_sm_items' hook is called to get the items associated %%% with the client when a discovery IQ gets to session management. -spec disco_sm_items(mongoose_disco:item_acc()) -> mongoose_disco:item_acc(). disco_sm_items(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_sm_items, HostType, Acc, []). + run_hook_for_host_type(disco_sm_items, HostType, Acc, []). %%% @doc `disco_local_features' hook is called to extract features %%% offered by the server. -spec disco_local_features(mongoose_disco:feature_acc()) -> mongoose_disco:feature_acc(). disco_local_features(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_local_features, HostType, Acc, []). + run_hook_for_host_type(disco_local_features, HostType, Acc, []). %%% @doc `disco_sm_features' hook is called to get the features of the client %%% when a discovery IQ gets to session management. -spec disco_sm_features(mongoose_disco:feature_acc()) -> mongoose_disco:feature_acc(). disco_sm_features(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_sm_features, HostType, Acc, []). + run_hook_for_host_type(disco_sm_features, HostType, Acc, []). %%% @doc `disco_muc_features' hook is called to get the features %%% supported by the MUC (Light) service. -spec disco_muc_features(mongoose_disco:feature_acc()) -> mongoose_disco:feature_acc(). disco_muc_features(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_muc_features, HostType, Acc, []). + run_hook_for_host_type(disco_muc_features, HostType, Acc, []). %%% @doc `disco_info' hook is called to extract information about the server. -spec disco_info(mongoose_disco:info_acc()) -> mongoose_disco:info_acc(). disco_info(Acc = #{host_type := HostType}) -> - ejabberd_hooks:run_for_host_type(disco_info, HostType, Acc, []). + run_hook_for_host_type(disco_info, HostType, Acc, []). %% AMP related hooks @@ -1266,8 +1246,7 @@ disco_info(Acc = #{host_type := HostType}) -> Result :: mod_amp:amp_match_result(). amp_check_condition(Server, Strategy, Rule) -> InitialAcc = no_match, %% mod_amp:amp_match_result() type - ejabberd_hooks:run_for_host_type(amp_check_condition, Server, InitialAcc, - [Strategy, Rule]). + run_hook_for_host_type(amp_check_condition, Server, InitialAcc, [Strategy, Rule]). %%% @doc The `amp_determine_strategy' hook is called when checking to determine %%% which strategy will be chosen when executing AMP rules. @@ -1280,8 +1259,8 @@ amp_check_condition(Server, Strategy, Rule) -> Result :: mod_amp:amp_strategy(). amp_determine_strategy(Server, From, To, Packet, Event) -> DefaultStrategy = amp_strategy:null_strategy(), - ejabberd_hooks:run_for_host_type(amp_determine_strategy, Server, DefaultStrategy, - [From, To, Packet, Event]). + run_hook_for_host_type(amp_determine_strategy, Server, DefaultStrategy, + [From, To, Packet, Event]). %%% @doc The `amp_error_action_triggered' hook is called to inform %%% that the `error' action has been triggered. @@ -1289,7 +1268,7 @@ amp_determine_strategy(Server, From, To, Packet, Event) -> Server :: jid:server(), Result :: any(). amp_error_action_triggered(Server) -> - ejabberd_hooks:run_for_host_type(amp_error_action_triggered, Server, ok, [Server]). + run_hook_for_host_type(amp_error_action_triggered, Server, ok, [Server]). %%% @doc The `amp_notify_action_triggered' hook is called to inform %%% that the `notify' action has been triggered. @@ -1297,8 +1276,7 @@ amp_error_action_triggered(Server) -> Server :: jid:server(), Result :: any(). amp_notify_action_triggered(Server) -> - ejabberd_hooks:run_for_host_type(amp_notify_action_triggered, Server, ok, - [Server]). + run_hook_for_host_type(amp_notify_action_triggered, Server, ok, [Server]). %%% @doc The `amp_verify_support' hook is called when checking %%% whether the host supports given AMP rules. @@ -1307,7 +1285,7 @@ amp_notify_action_triggered(Server) -> Rules :: mod_amp:amp_rules(), Result :: [mod_amp:amp_rule_support()]. amp_verify_support(Server, Rules) -> - ejabberd_hooks:run_for_host_type(amp_verify_support, Server, [], [Rules]). + run_hook_for_host_type(amp_verify_support, Server, [], [Rules]). %% MUC and MUC Light related hooks @@ -1317,7 +1295,7 @@ amp_verify_support(Server, Rules) -> EventData :: mod_muc:room_event_data(), Result :: exml:element(). filter_room_packet(HostType, Packet, EventData) -> - ejabberd_hooks:run_for_host_type(filter_room_packet, HostType, Packet, [HostType, EventData]). + run_hook_for_host_type(filter_room_packet, HostType, Packet, [HostType, EventData]). %%% @doc The `forget_room' hook is called when a room is removed from the database. -spec forget_room(HostType, MucHost, Room) -> Result when @@ -1326,7 +1304,7 @@ filter_room_packet(HostType, Packet, EventData) -> Room :: jid:luser(), Result :: any(). forget_room(HostType, MucHost, Room) -> - ejabberd_hooks:run_for_host_type(forget_room, HostType, ok, [HostType, MucHost, Room]). + run_hook_for_host_type(forget_room, HostType, ok, [HostType, MucHost, Room]). -spec invitation_sent(HookServer, Host, RoomJID, From, To, Reason) -> Result when HookServer :: jid:server(), @@ -1337,8 +1315,8 @@ forget_room(HostType, MucHost, Room) -> Reason :: binary(), Result :: any(). invitation_sent(HookServer, Host, RoomJID, From, To, Reason) -> - ejabberd_hooks:run_for_host_type(invitation_sent, HookServer, ok, - [HookServer, Host, RoomJID, From, To, Reason]). + run_hook_for_host_type(invitation_sent, HookServer, ok, + [HookServer, Host, RoomJID, From, To, Reason]). %%% @doc The `join_room' hook is called when a user joins a MUC room. -spec join_room(HookServer, Room, Host, JID, MucJID) -> Result when @@ -1349,8 +1327,8 @@ invitation_sent(HookServer, Host, RoomJID, From, To, Reason) -> MucJID :: jid:jid(), Result :: any(). join_room(HookServer, Room, Host, JID, MucJID) -> - ejabberd_hooks:run_for_host_type(join_room, HookServer, ok, - [HookServer, Room, Host, JID, MucJID]). + run_hook_for_host_type(join_room, HookServer, ok, + [HookServer, Room, Host, JID, MucJID]). %%% @doc The `leave_room' hook is called when a user joins a MUC room. -spec leave_room(HookServer, Room, Host, JID, MucJID) -> Result when @@ -1361,8 +1339,8 @@ join_room(HookServer, Room, Host, JID, MucJID) -> MucJID :: jid:jid(), Result :: any(). leave_room(HookServer, Room, Host, JID, MucJID) -> - ejabberd_hooks:run_for_host_type(leave_room, HookServer, ok, - [HookServer, Room, Host, JID, MucJID]). + run_hook_for_host_type(leave_room, HookServer, ok, + [HookServer, Room, Host, JID, MucJID]). %%% @doc The `room_packet' hook is called when a message is added to room's history. -spec room_packet(Server, FromNick, FromJID, JID, Packet) -> Result when @@ -1373,15 +1351,14 @@ leave_room(HookServer, Room, Host, JID, MucJID) -> Packet :: exml:element(), Result :: any(). room_packet(Server, FromNick, FromJID, JID, Packet) -> - ejabberd_hooks:run_for_host_type(room_packet, Server, ok, - [FromNick, FromJID, JID, Packet]). + run_hook_for_host_type(room_packet, Server, ok, [FromNick, FromJID, JID, Packet]). -spec update_inbox_for_muc(HostType, Info) -> Result when HostType :: mongooseim:host_type(), Info :: mod_muc_room:update_inbox_for_muc_payload(), Result :: mod_muc_room:update_inbox_for_muc_payload(). update_inbox_for_muc(HostType, Info) -> - ejabberd_hooks:run_for_host_type(update_inbox_for_muc, HostType, Info, []). + run_hook_for_host_type(update_inbox_for_muc, HostType, Info, []). %% Caps related hooks @@ -1393,8 +1370,7 @@ update_inbox_for_muc(HostType, Info) -> Result :: mongoose_acc:t(). caps_recognised(Acc, From, Pid, Features) -> HostType = mongoose_acc:host_type(Acc), - ejabberd_hooks:run_for_host_type(caps_recognised, HostType, Acc, - [From, Pid, Features]). + run_hook_for_host_type(caps_recognised, HostType, Acc, [From, Pid, Features]). %% PubSub related hooks @@ -1408,8 +1384,8 @@ caps_recognised(Acc, From, Pid, Features) -> NodeOptions :: list(), Result :: any(). pubsub_create_node(Server, PubSubHost, NodeId, Nidx, NodeOptions) -> - ejabberd_hooks:run_for_host_type(pubsub_create_node, Server, ok, - [Server, PubSubHost, NodeId, Nidx, NodeOptions]). + run_hook_for_host_type(pubsub_create_node, Server, ok, + [Server, PubSubHost, NodeId, Nidx, NodeOptions]). %%% @doc The `pubsub_delete_node' hook is called to inform %%% that a pubsub node is deleted. @@ -1420,8 +1396,8 @@ pubsub_create_node(Server, PubSubHost, NodeId, Nidx, NodeOptions) -> Nidx :: mod_pubsub:nodeIdx(), Result :: any(). pubsub_delete_node(Server, PubSubHost, NodeId, Nidx) -> - ejabberd_hooks:run_for_host_type(pubsub_delete_node, Server, ok, - [Server, PubSubHost, NodeId, Nidx]). + run_hook_for_host_type(pubsub_delete_node, Server, ok, + [Server, PubSubHost, NodeId, Nidx]). %%% @doc The `pubsub_publish_item' hook is called to inform %%% that a pubsub item is published. @@ -1435,9 +1411,9 @@ pubsub_delete_node(Server, PubSubHost, NodeId, Nidx) -> BrPayload :: mod_pubsub:payload(), Result :: any(). pubsub_publish_item(Server, NodeId, Publisher, ServiceJID, ItemId, BrPayload) -> - ejabberd_hooks:run_for_host_type(pubsub_publish_item, Server, ok, - [Server, NodeId, Publisher, ServiceJID, - ItemId, BrPayload]). + run_hook_for_host_type(pubsub_publish_item, Server, ok, + [Server, NodeId, Publisher, ServiceJID, + ItemId, BrPayload]). %% Global distribution related hooks @@ -1450,8 +1426,8 @@ pubsub_publish_item(Server, NodeId, Publisher, ServiceJID, ItemId, BrPayload) -> LocalHost :: jid:server(), Result :: any(). mod_global_distrib_known_recipient(GlobalHost, From, To, LocalHost) -> - ejabberd_hooks:run_for_host_type(mod_global_distrib_known_recipient, - GlobalHost, ok, [From, To, LocalHost]). + run_hook_for_host_type(mod_global_distrib_known_recipient, GlobalHost, ok, + [From, To, LocalHost]). %%% @doc The `mod_global_distrib_unknown_recipient' hook is called when %%% the recipient is unknown to `global_distrib'. @@ -1460,5 +1436,28 @@ mod_global_distrib_known_recipient(GlobalHost, From, To, LocalHost) -> Info :: filter_packet_acc(), Result :: any(). mod_global_distrib_unknown_recipient(GlobalHost, Info) -> - ejabberd_hooks:run_for_host_type(mod_global_distrib_unknown_recipient, - GlobalHost, Info, []). + run_hook_for_host_type(mod_global_distrib_unknown_recipient, GlobalHost, Info, []). + + +%%%---------------------------------------------------------------------- +%%% Internal functions +%%%---------------------------------------------------------------------- + +run_global_hook(HookName, Acc, Params) when is_map(Params) -> + {_, RetValue} = gen_hook:run_fold(HookName, global, Acc, Params), + RetValue; +run_global_hook(HookName, Acc, Args) when is_list(Args) -> + ejabberd_hooks:run_fold(HookName, global, Acc, Args). + +run_hook_for_host_type(HookName, undefined, Acc, Args) -> + ?LOG_ERROR(#{what => undefined_host_type, + text => <<"Running hook for an undefined host type">>, + hook_name => HookName, hook_acc => Acc, hook_args => Args}), + Acc; +run_hook_for_host_type(HookName, HostType, Acc, Params) when is_binary(HostType), + is_map(Params) -> + {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, Params), + RetValue; +run_hook_for_host_type(HookName, HostType, Acc, Args) when is_binary(HostType), + is_list(Args) -> + ejabberd_hooks:run_fold(HookName, HostType, Acc, Args). diff --git a/test/commands_backend_SUITE.erl b/test/commands_backend_SUITE.erl index a125854fe6..013a610993 100644 --- a/test/commands_backend_SUITE.erl +++ b/test/commands_backend_SUITE.erl @@ -97,11 +97,11 @@ groups() -> setup(Module) -> meck:unload(), meck:new(supervisor, [unstick, passthrough, no_link]), - meck:new(ejabberd_hooks, []), + meck:new(gen_hook, []), meck:new(ejabberd_auth, []), %% you have to meck some stuff to get it working.... - meck:expect(ejabberd_hooks, add, fun(_, _, _, _, _) -> ok end), - meck:expect(ejabberd_hooks, run_global, fun(_, _, _) -> ok end), + meck:expect(gen_hook, add_handler, fun(_, _, _, _, _) -> ok end), + meck:expect(gen_hook, run_fold, fun(_, _, _, _) -> {ok, ok} end), meck:expect(ejabberd_config, get_local_option, fun(_) -> undefined end), spawn(fun mc_holder/0), meck:expect(supervisor, start_child, @@ -120,7 +120,7 @@ teardown() -> mongoose_commands:unregister(commands_new()), meck:unload(ejabberd_config), meck:unload(ejabberd_auth), - meck:unload(ejabberd_hooks), + meck:unload(gen_hook), meck:unload(supervisor), mc_holder_proc ! stop, ok. diff --git a/test/ejabberd_c2s_SUITE_mocks.erl b/test/ejabberd_c2s_SUITE_mocks.erl index 70f9e0ff3f..aa9cee18cf 100644 --- a/test/ejabberd_c2s_SUITE_mocks.erl +++ b/test/ejabberd_c2s_SUITE_mocks.erl @@ -35,9 +35,8 @@ setup() -> undefined end), meck:expect(mongoose_credentials, get, fun mcred_get/2), - meck:new(ejabberd_hooks), - meck:expect(ejabberd_hooks, run_global, fun hookfold/3), - meck:expect(ejabberd_hooks, run_for_host_type, fun hookfold/4), + meck:new(gen_hook), + meck:expect(gen_hook, run_fold, fun hookfold/4), meck:new(ejabberd_config), meck:expect(ejabberd_config, get_local_option, @@ -71,15 +70,14 @@ default_global_option(language) -> <<"en">>. mcred_get(dummy_creds, username) -> <<"cosmic_hippo">>; mcred_get(dummy_creds, auth_module) -> auuuthmodule. -hookfold(check_bl_c2s, _, _) -> false. - -hookfold(roster_get_versioning_feature, _, _, _) -> []; -hookfold(roster_get_subscription_lists, _, A, _) -> A; -hookfold(privacy_get_user_list, _, A, _) -> A; -hookfold(session_opening_allowed_for_user, _, _, _) -> allow; -hookfold(c2s_stream_features, _, _, _) -> []; -hookfold(xmpp_send_element, _, A, _) -> A; -hookfold(privacy_check_packet, _, _, _) -> allow. +hookfold(check_bl_c2s, _, _, _) -> {ok, false}; +hookfold(roster_get_versioning_feature, _, _, _) -> {ok, []}; +hookfold(roster_get_subscription_lists, _, A, _) -> {ok, A}; +hookfold(privacy_get_user_list, _, A, _) -> {ok, A}; +hookfold(session_opening_allowed_for_user, _, _, _) -> {ok, allow}; +hookfold(c2s_stream_features, _, _, _) -> {ok, []}; +hookfold(xmpp_send_element, _, A, _) -> {ok, A}; +hookfold(privacy_check_packet, _, _, _) -> {ok, allow}. get_host_type(<<"localhost">>) -> {ok, <<"localhost">>}; get_host_type(_) -> {error, not_found}. diff --git a/test/ejabberd_hooks_SUITE.erl b/test/ejabberd_hooks_SUITE.erl index 5f7910fd3e..aa235de514 100644 --- a/test/ejabberd_hooks_SUITE.erl +++ b/test/ejabberd_hooks_SUITE.erl @@ -66,7 +66,7 @@ hooks_run_launches_nullary_fun(_) -> given_hook_added(test_run_hook, hook_mod, fun_nullary, 1), %% when - ejabberd_hooks:run_for_host_type(test_run_hook, ?HOST, ok, []), + ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, []), %% then H = meck:history(hook_mod), @@ -78,7 +78,7 @@ hooks_run_launches_unary_fun(_) -> given_hook_added(test_run_hook, hook_mod, fun_onearg, 1), %% when - ejabberd_hooks:run_for_host_type(test_run_hook, ?HOST, ok, [oneval]), + ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, [oneval]), %% then [{_,{hook_mod,fun_onearg,[ok, oneval]}, oneval}] = meck:history(hook_mod). @@ -92,7 +92,7 @@ hooks_run_ignores_different_arity_funs(_) -> given_hook_added(test_run_hook, hook_mod, fun_twoarg, 1), %% when - ejabberd_hooks:run_for_host_type(test_run_hook, ?HOST, ok, [one, two]), + ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, [one, two]), %% then [{_,{hook_mod, fun_twoarg, [ok, one, two]}, success2}] = meck:history(hook_mod). @@ -106,7 +106,7 @@ hooks_run_stops_when_fun_returns_stop(_) -> given_hook_added(test_run_hook, hook_mod, another_fun, 2), %% when - ejabberd_hooks:run_for_host_type(test_run_hook, ?HOST, ok, []), + ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, []), %% then [{_,{hook_mod,a_fun,[ok]}, stop}] = meck:history(hook_mod). @@ -118,7 +118,7 @@ hooks_run_fold_folds_with_unary_fun(_) -> given_hook_added(test_fold_hook, hook_mod, unary_folder, 1), %% when - ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, initial, []), + ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), %% then [{_,{hook_mod,unary_folder,[initial]}, done}] = meck:history(hook_mod). @@ -129,7 +129,7 @@ hooks_run_fold_folds_with_binary_fun(_) -> given_hook_added(test_fold_hook, hook_mod, binary_folder, 1), %% when - ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, initial, [arg1]), + ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, [arg1]), %% then [{_,{hook_mod,binary_folder,[initial, arg1]}, done}] = meck:history(hook_mod). @@ -143,7 +143,7 @@ hooks_run_fold_passes_acc_along(_) -> given_hook_added(test_fold_hook, hook_mod2, second_folder, 2), %% when - R = ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, 0, [10]), + R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, 0, [10]), %% then -10 = R. @@ -157,7 +157,7 @@ hooks_run_fold_stops_when_fun_returns_stop(_) -> given_hook_added(test_fold_hook, hook_mod2, folder, 2), %% when - R = ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, continue, []), + R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, continue, []), %% then [{_,{hook_mod1,stopper,[continue]}, stop}] = meck:history(hook_mod1), @@ -174,7 +174,7 @@ hooks_run_fold_preserves_order(_) -> given_hook_added(test_fold_hook, hook_mod2, second_folder, 2), %% when - R = ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, 0, []), + R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, 0, []), %% then 2 = R. @@ -190,7 +190,7 @@ error_in_run_fold_is_ignored(_) -> given_hook_added(test_fold_hook, working_mod, good, 2), %% when - R = ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, initial, []), + R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), %% then i_was_run = R, @@ -208,7 +208,7 @@ throw_in_run_fold_is_ignored(_) -> given_hook_added(test_fold_hook, working_mod, good, 2), %% when - R = ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, initial, []), + R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), %% then initial = R, @@ -227,7 +227,7 @@ exit_in_run_fold_is_ignored(_) -> given_hook_added(test_fold_hook, working_mod, good, 2), %% when - R = ejabberd_hooks:run_for_host_type(test_fold_hook, ?HOST, initial, []), + R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), %% then initial = R, diff --git a/test/ejabberd_sm_SUITE.erl b/test/ejabberd_sm_SUITE.erl index 3e2be1ee5f..6074dc4c1b 100644 --- a/test/ejabberd_sm_SUITE.erl +++ b/test/ejabberd_sm_SUITE.erl @@ -367,7 +367,7 @@ unique_count_while_removing_entries(C) -> unload_meck() -> meck:unload(acl), meck:unload(ejabberd_config), - meck:unload(ejabberd_hooks), + meck:unload(gen_hook), meck:unload(ejabberd_commands), meck:unload(mongoose_domain_api). @@ -376,8 +376,8 @@ set_test_case_meck(MaxUserSessions) -> meck:expect(ejabberd_config, get_local_option, fun(_) -> undefined end), meck:new(acl, []), meck:expect(acl, match_rule, fun(_, _, _) -> MaxUserSessions end), - meck:new(ejabberd_hooks, []), - meck:expect(ejabberd_hooks, run_for_host_type, fun(_, _, Acc, _) -> Acc end), + meck:new(gen_hook, []), + meck:expect(gen_hook, run_fold, fun(_, _, Acc, _) -> {ok, Acc} end), meck:new(mongoose_domain_api, []), meck:expect(mongoose_domain_api, get_domain_host_type, fun(H) -> {ok, H} end). @@ -606,8 +606,7 @@ set_meck(SMBackend) -> (host_types, Default) -> Default end), meck:expect(ejabberd_config, get_local_option, fun(_) -> undefined end), - meck:expect(ejabberd_hooks, add, fun(_) -> ok end), - meck:expect(ejabberd_hooks, add, fun(_, _, _, _, _) -> ok end), + meck:expect(gen_hook, add_handler, fun(_, _, _, _, _) -> ok end), meck:new(ejabberd_commands, []), meck:expect(ejabberd_commands, register_commands, fun(_) -> ok end), From 8badc482a7b960a817814ccb4d986d82a2a0dc33 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Tue, 6 Jul 2021 23:28:23 +0200 Subject: [PATCH 05/13] making dialyzer happy --- src/mongoose_hooks.erl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mongoose_hooks.erl b/src/mongoose_hooks.erl index 2a13c7e8c2..a633aee1b9 100644 --- a/src/mongoose_hooks.erl +++ b/src/mongoose_hooks.erl @@ -1443,9 +1443,9 @@ mod_global_distrib_unknown_recipient(GlobalHost, Info) -> %%% Internal functions %%%---------------------------------------------------------------------- -run_global_hook(HookName, Acc, Params) when is_map(Params) -> - {_, RetValue} = gen_hook:run_fold(HookName, global, Acc, Params), - RetValue; +%% run_global_hook(HookName, Acc, Params) when is_map(Params) -> +%% {_, RetValue} = gen_hook:run_fold(HookName, global, Acc, Params), +%% RetValue; run_global_hook(HookName, Acc, Args) when is_list(Args) -> ejabberd_hooks:run_fold(HookName, global, Acc, Args). @@ -1454,10 +1454,10 @@ run_hook_for_host_type(HookName, undefined, Acc, Args) -> text => <<"Running hook for an undefined host type">>, hook_name => HookName, hook_acc => Acc, hook_args => Args}), Acc; -run_hook_for_host_type(HookName, HostType, Acc, Params) when is_binary(HostType), - is_map(Params) -> - {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, Params), - RetValue; +%% run_hook_for_host_type(HookName, HostType, Acc, Params) when is_binary(HostType), +%% is_map(Params) -> +%% {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, Params), +%% RetValue; run_hook_for_host_type(HookName, HostType, Acc, Args) when is_binary(HostType), is_list(Args) -> ejabberd_hooks:run_fold(HookName, HostType, Acc, Args). From 69f755cb78f061190d45bc5611df7ab1782f9c1d Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Fri, 9 Jul 2021 01:57:17 +0200 Subject: [PATCH 06/13] allowing only external function references in gen_hook interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for OTP versions prior to 23, local function references in format like fun some_fun/2 behave in the same way as anonymous functions. different places in code generate different references. in addition to that local fun references are not code-reload safe, so it’s better to use external fun references only. It's still a good idea to use function references, because it allows dialyzer to check the handler function specs. --- src/ejabberd_hooks.erl | 6 +- src/gen_hook.erl | 147 ++++++++++++++++++++-------------- test/ejabberd_hooks_SUITE.erl | 5 +- test/muc_light_SUITE.erl | 5 +- 4 files changed, 98 insertions(+), 65 deletions(-) diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 440c7e7f67..4f86f12be2 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -34,6 +34,8 @@ -export([add/1, delete/1]). +-export([gen_hook_fn_wrapper/3]). + -include("mongoose.hrl"). -type hook() :: {HookName :: atom(), @@ -96,14 +98,14 @@ run_fold(HookName, HostType, Acc, Args) when is_binary(HostType); HostType =:= g -spec add_hook(hook()) -> ok. add_hook({HookName, HostType, Module, Function, Priority}) when is_atom(Function) -> gen_hook:add_handler(HookName, HostType, - fun gen_hook_fn_wrapper/3, + fun ?MODULE:gen_hook_fn_wrapper/3, #{module => Module, function =>Function}, Priority). -spec delete_hook(hook()) -> ok. delete_hook({HookName, HostType, Module, Function, Priority}) when is_atom(Function) -> gen_hook:delete_handler(HookName, HostType, - fun gen_hook_fn_wrapper/3, + fun ?MODULE:gen_hook_fn_wrapper/3, #{module => Module, function => Function}, Priority). diff --git a/src/gen_hook.erl b/src/gen_hook.erl index 61c35ee3c6..ad60d9457e 100644 --- a/src/gen_hook.erl +++ b/src/gen_hook.erl @@ -40,15 +40,24 @@ -type key() :: {HookName :: atom(), Tag :: any()}. +-type hook_tuple() :: {HookName :: hook_name(), + Tag :: hook_tag(), + Function :: hook_fn(), + Extra :: hook_extra(), + Priority :: pos_integer()}. + +-type hook_list() :: [hook_tuple()]. + +-export_type([hook_fn/0, hook_list/0]). + -record(hook_handler, {key :: key(), %% 'prio' field must go right after the 'key', %% this is required for the proper sorting. prio :: pos_integer(), - fn :: hook_fn(), + module :: module(), + function :: atom(), %% function name extra :: map()}). --export_type([hook_fn/0]). - -define(TABLE, ?MODULE). %%%---------------------------------------------------------------------- %%% API @@ -63,16 +72,17 @@ start_link() -> Function :: hook_fn(), Extra :: hook_extra(), Priority :: pos_integer()) -> ok. -add_handler(HookName, Tag, Function, Extra, Priority) when is_atom(HookName), - is_function(Function, 3), - is_map(Extra), - is_integer(Priority), - Priority > 0 -> - NewExtra = extend_extra(HookName, Tag, Extra), - Handler = #hook_handler{key = hook_key(HookName, Tag), - prio = Priority, - fn = Function, - extra = NewExtra}, +add_handler(HookName, Tag, Function, Extra, Priority) -> + add_handler({HookName, Tag, Function, Extra, Priority}). + +-spec add_handlers(hook_list()) -> ok. +add_handlers(List) -> + [add_handler(HookTuple) || HookTuple <- List], + ok. + +-spec add_handler(hook_tuple()) -> ok. +add_handler(HookTuple) -> + Handler = make_hook_handler(HookTuple), gen_server:call(?MODULE, {add_handler, Handler}). %% @doc Delete a hook handler. @@ -82,46 +92,19 @@ add_handler(HookName, Tag, Function, Extra, Priority) when is_atom(HookName), Function :: hook_fn(), Extra :: hook_extra(), Priority :: pos_integer()) -> ok. -delete_handler(HookName, Tag, Function, Extra, Priority) when is_atom(HookName), - is_function(Function, 3), - is_map(Extra), - is_integer(Priority), - Priority > 0 -> - NewExtra = extend_extra(HookName, Tag, Extra), - Handler = #hook_handler{key = hook_key(HookName, Tag), - prio = Priority, - fn = Function, - extra = NewExtra}, - gen_server:call(?MODULE, {delete_handler, Handler}). +delete_handler(HookName, Tag, Function, Extra, Priority) -> + delete_handler({HookName, Tag, Function, Extra, Priority}). --spec add_handlers([{HookName :: hook_name(), - Tag :: hook_tag(), - Function :: hook_fn(), - Extra :: hook_extra(), - Priority :: pos_integer()}]) -> ok. -add_handlers(List) -> - [add_handler(HookName, Tag, Function, Extra, Priority) || - {HookName, Tag, Function, Extra, Priority} <- List, is_atom(HookName), - is_function(Function, 3), - is_map(Extra), - is_integer(Priority), - Priority > 0], - ok. - --spec delete_handlers([{HookName :: hook_name(), - Tag :: hook_tag(), - Function :: hook_fn(), - Extra :: hook_extra(), - Priority :: pos_integer()}]) -> ok. +-spec delete_handlers(hook_list()) -> ok. delete_handlers(List) -> - [delete_handler(HookName, Tag, Function, Extra, Priority) || - {HookName, Tag, Function, Extra, Priority} <- List, is_atom(HookName), - is_function(Function, 3), - is_map(Extra), - is_integer(Priority), - Priority > 0], + [delete_handler(HookTuple) || HookTuple <- List], ok. +-spec delete_handler(hook_tuple()) -> ok. +delete_handler(HookTuple) -> + Handler = make_hook_handler(HookTuple), + gen_server:call(?MODULE, {delete_handler, Handler}). + %% @doc Run hook handlers in order of priority (lower number means higher priority). %% * if hook handler returns {ok, NewAcc}, the NewAcc value is used %% as an accumulator parameter for the following hook handler. @@ -208,8 +191,8 @@ code_change(_OldVsn, State, _Extra) -> -spec run_hook([#hook_handler{}], hook_acc(), hook_params()) -> hook_fn_ret_value(). run_hook([], Acc, _Params) -> {ok, Acc}; -run_hook([#hook_handler{fn = Function, extra = Extra} = Handler | Ls], Acc, Params) -> - case apply_hook_function(Function, Acc, Params, Extra) of +run_hook([Handler | Ls], Acc, Params) -> + case apply_hook_function(Handler, Acc, Params) of {'EXIT', Reason} -> ?MODULE:error_running_hook(Reason, Handler, Acc, Params), run_hook(Ls, Acc, Params); @@ -219,10 +202,11 @@ run_hook([#hook_handler{fn = Function, extra = Extra} = Handler | Ls], Acc, Para run_hook(Ls, NewAcc, Params) end. --spec apply_hook_function(hook_fn(), hook_acc(), hook_params(), hook_extra()) -> +-spec apply_hook_function(#hook_handler{}, hook_acc(), hook_params()) -> hook_fn_ret_value() | {'EXIT', Reason :: any()}. -apply_hook_function(Function, Acc, Params, Extra) -> - safely:apply(Function, [Acc, Params, Extra]). +apply_hook_function(#hook_handler{module = Module, function = Function, extra = Extra}, + Acc, Params) -> + safely:apply(Module, Function, [Acc, Params, Extra]). error_running_hook(Reason, Handler, Acc, Params) -> ?LOG_ERROR(#{what => hook_failed, @@ -232,15 +216,58 @@ error_running_hook(Reason, Handler, Acc, Params) -> params => Params, reason => Reason}). --spec hook_key(hook_name(), hook_tag()) -> key(). -hook_key(HookName, Tag) -> {HookName, Tag}. +-spec make_hook_handler(hook_tuple()) -> #hook_handler{}. +make_hook_handler({HookName, Tag, Function, Extra, Priority} = HookTuple) + when is_atom(HookName), is_function(Function, 3), is_map(Extra), + is_integer(Priority), Priority > 0 -> + NewExtra = extend_extra(HookTuple), + {Module, FunctionName} = check_hook_function(Function), + #hook_handler{key = hook_key(HookName, Tag), + prio = Priority, + module = Module, + function = FunctionName, + extra = NewExtra}. + +-spec check_hook_function(hook_fn()) -> {module(), atom()}. +check_hook_function(Function) when is_function(Function, 3) -> + case erlang:fun_info(Function, type) of + {type, external} -> + {module, Module} = erlang:fun_info(Function, module), + {name, FunctionName} = erlang:fun_info(Function, name), + case code:ensure_loaded(Module) of + {module, Module} -> ok; + Error -> + throw_error(#{what => module_is_not_loaded, + module => Module, error => Error}) + end, + case erlang:function_exported(Module, FunctionName, 3) of + true -> ok; + false -> + throw_error(#{what => function_is_not_exported, + function => Function}) + end, + {Module, FunctionName}; + {type, local} -> + throw_error(#{what => only_external_function_references_allowed, + function => Function}) + end. + +-spec throw_error(map()) -> no_return(). +throw_error(ErrorMap) -> + ?LOG_ERROR(ErrorMap), + error(ErrorMap). + +-spec hook_key(HookName :: hook_name(), Tag :: hook_tag()) -> key(). +hook_key(HookName, Tag) -> + {HookName, Tag}. -extend_extra(HookName, Tag, OriginalExtra) -> - ExtendedExtra = #{hook_name => HookName, hook_tag => Tag}, +-spec extend_extra(hook_tuple()) -> hook_extra(). +extend_extra({HookName, Tag, _Function, OriginalExtra, _Priority}) -> + ExtraExtension = #{hook_name => HookName, hook_tag => Tag}, %% KV pairs of the OriginalExtra map will remain unchanged, - %% only the new keys from the ExtendedExtra map will be added + %% only the new keys from the ExtraExtension map will be added %% to the NewExtra map - maps:merge(ExtendedExtra, OriginalExtra). + maps:merge(ExtraExtension, OriginalExtra). -spec create_hook_metric(Key :: key()) -> any(). create_hook_metric({HookName, Tag}) -> diff --git a/test/ejabberd_hooks_SUITE.erl b/test/ejabberd_hooks_SUITE.erl index aa235de514..d7907083c3 100644 --- a/test/ejabberd_hooks_SUITE.erl +++ b/test/ejabberd_hooks_SUITE.erl @@ -45,8 +45,9 @@ a_module_fun_can_be_added(_) -> % then [{{test_run_hook,<<"localhost">>}, - [{hook_handler, {test_run_hook,<<"localhost">>}, - 1,_FN,#{function := fun_a, module := hook_mod}}]}] = get_hooks(). + [{hook_handler, {test_run_hook,<<"localhost">>}, 1, + ejabberd_hooks, gen_hook_fn_wrapper, + #{function := fun_a, module := hook_mod}}]}] = get_hooks(). a_module_fun_can_be_removed(_) -> given_hooks_started(), diff --git a/test/muc_light_SUITE.erl b/test/muc_light_SUITE.erl index e8dc9c88f4..23cafbbcfa 100644 --- a/test/muc_light_SUITE.erl +++ b/test/muc_light_SUITE.erl @@ -119,7 +119,7 @@ codec_calls(_Config) -> HandleFun = fun(_, _, _) -> count_call(handler) end, gen_hook:add_handler(filter_room_packet, <<"localhost">>, - fun(Acc, _Params, _Extra) -> count_call(hook), {ok, Acc} end, + fun ?MODULE:filter_room_packet_handler/3, #{}, 50), @@ -154,6 +154,9 @@ codec_calls(_Config) -> check_count(1, 2), ok. +filter_room_packet_handler(Acc, _Params, _Extra) -> + count_call(hook), + {ok, Acc}. %% ----------------- Room config schema ---------------------- simple_config_items_are_parsed(_Config) -> From 25d267962504210de44ec436a33a7c3e8d7501d4 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Mon, 12 Jul 2021 23:22:54 +0200 Subject: [PATCH 07/13] adding unit tests for gen_hook --- test/gen_hook_SUITE.erl | 348 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 test/gen_hook_SUITE.erl diff --git a/test/gen_hook_SUITE.erl b/test/gen_hook_SUITE.erl new file mode 100644 index 0000000000..13ac4d6d91 --- /dev/null +++ b/test/gen_hook_SUITE.erl @@ -0,0 +1,348 @@ +-module(gen_hook_SUITE). +-compile([export_all]). + +-include_lib("eunit/include/eunit.hrl"). + +-define(HOOK_TAG1, some_tag). +-define(HOOK_TAG2, another_tag). + +-define(assertEqualLists(L1, L2), ?assertEqual(lists:sort(L1), lists:sort(L2))). + +all() -> + [single_handler_can_be_added_and_removed, + multiple_handlers_can_be_added_and_removed, + + local_fun_references_causes_error, + anonymous_fun_references_causes_error, + not_exported_external_fun_references_causes_error, + invalid_hook_handler_parameters_causes_error, + + run_fold_executes_handlers_in_the_right_order, + run_fold_stops_when_handler_returns_stop, + + errors_in_handlers_are_reported_but_ignored]. + +init_per_suite(Config) -> + application:ensure_all_started(exometer_core), + Config. + +end_per_suite(Config) -> + application:stop(exometer_core), + Config. + +init_per_testcase(_,Config) -> + Fun = fun(all_metrics_are_global) -> false end, + meck:new(ejabberd_config), + meck:expect(ejabberd_config, get_local_option, Fun), + gen_hook:start_link(), + Config. + +end_per_testcase(_, Config) -> + meck:unload(), + Config. + + +%%---------------------------------------------------------------- +%% test cases +%%---------------------------------------------------------------- +single_handler_can_be_added_and_removed(_) -> + mock_modules([mod1, mod2]), + PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), + MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + %% check that there are no hook handlers added yet + ?assertEqual([],get_handlers_for_all_hooks()), + %% add various hook handlers + ?assertEqual(ok, gen_hook:add_handler(calculate, ?HOOK_TAG1, MultiplyHandlerFn, + #{id => 2}, 2)), + ?assertEqual(ok, gen_hook:add_handler(calculate, ?HOOK_TAG1, PlusHandlerFn, + #{id => 1}, 1)), + ?assertEqual(ok, gen_hook:add_handler(calculate, ?HOOK_TAG2, PlusHandlerFn, + #{id => 1}, 1)), + %% check that hook handlers are added + Tag1Handlers = [%% this list must be sorted by priority + {hook_handler, {calculate, ?HOOK_TAG1}, 1, mod1, plus, + #{hook_name => calculate, hook_tag => ?HOOK_TAG1, id => 1}}, + {hook_handler, {calculate, ?HOOK_TAG1}, 2, mod2, multiply, + #{hook_name => calculate, hook_tag => ?HOOK_TAG1, id => 2}}], + AllHandlers = [{{calculate, ?HOOK_TAG1}, Tag1Handlers}, + {{calculate, ?HOOK_TAG2}, + [{hook_handler, {calculate, ?HOOK_TAG2}, 1, mod1, plus, + #{hook_name => calculate, hook_tag => ?HOOK_TAG2, id => 1}}]}], + ?assertEqualLists(AllHandlers, get_handlers_for_all_hooks()), + %% try to add some hook handler second time and check that nothing has changed + ?assertEqual(ok, gen_hook:add_handler(calculate, ?HOOK_TAG1, MultiplyHandlerFn, + #{id => 2}, 2)), + ?assertEqualLists(AllHandlers, get_handlers_for_all_hooks()), + %% try to remove hook handler for ?HOOK_TAG2 and check that it's removed + ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG2, PlusHandlerFn, + #{id => 1}, 1)), + ?assertEqualLists([], get_handlers(calculate, ?HOOK_TAG2)), + ?assertEqualLists(Tag1Handlers, get_handlers(calculate, ?HOOK_TAG1)), + %% try to remove hook handler for ?HOOK_TAG2 second time + %% and check that nothing has changed + ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG2, PlusHandlerFn, + #{id => 1}, 1)), + ?assertEqualLists([], get_handlers(calculate, ?HOOK_TAG2)), + ?assertEqualLists(Tag1Handlers, get_handlers(calculate, ?HOOK_TAG1)), + %% try to remove hook handlers for ?HOOK_TAG1 and check that they are removed + ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG1, MultiplyHandlerFn, + #{id => 2}, 2)), + ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG1, PlusHandlerFn, + #{id => 1}, 1)), + ?assertEqualLists([], get_handlers(calculate, ?HOOK_TAG1)). + +multiple_handlers_can_be_added_and_removed(_) -> + mock_modules([mod1, mod2]), + PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), + MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% add various hook handlers + HookHandlers = [{calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{id => 2}, 2}, + {calculate, ?HOOK_TAG2, PlusHandlerFn, #{id => 1}, 1}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{id => 1}, 1}], + ?assertEqual(ok, gen_hook:add_handlers(HookHandlers)), + %% check that hook handlers are added + Tag1Handlers = [%% this list must be sorted by priority + {hook_handler, {calculate, ?HOOK_TAG1}, 1, mod1, plus, + #{hook_name => calculate, hook_tag => ?HOOK_TAG1, id => 1}}, + {hook_handler, {calculate, ?HOOK_TAG1}, 2, mod2, multiply, + #{hook_name => calculate, hook_tag => ?HOOK_TAG1, id => 2}}], + AllHandlers = [{{calculate, ?HOOK_TAG1}, Tag1Handlers}, + {{calculate, ?HOOK_TAG2}, + [{hook_handler, {calculate, ?HOOK_TAG2}, 1, mod1, plus, + #{hook_name => calculate, hook_tag => ?HOOK_TAG2, id => 1}}]}], + ?assertEqualLists(AllHandlers, get_handlers_for_all_hooks()), + %% try to add hook handlers second time and check that nothing has changed + ?assertEqual(ok, gen_hook:add_handlers(HookHandlers)), + ?assertEqualLists(AllHandlers, get_handlers_for_all_hooks()), + %% try to remove hook handlers and check that they are removed + ?assertEqual(ok, gen_hook:delete_handlers(HookHandlers)), + ?assertEqualLists([{{calculate, ?HOOK_TAG1}, []}, {{calculate, ?HOOK_TAG2}, []}], + get_handlers_for_all_hooks()), + %% try to remove hook handlers second time and check that nothing has changed + ?assertEqual(ok, gen_hook:delete_handlers(HookHandlers)), + ?assertEqualLists([{{calculate, ?HOOK_TAG1}, []}, {{calculate, ?HOOK_TAG2}, []}], + get_handlers_for_all_hooks()). + +local_fun_references_causes_error(_) -> + mock_modules([mod1, mod2]), + PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), + MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% try to add multiple hook handlers, when one of them uses local function reference + LocalFunctionReference = fun hook_handler_plus/3, + HookHandlers = [{calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{id => 2}, 2}, + {calculate, ?HOOK_TAG2, LocalFunctionReference, #{id => 1}, 1}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{id => 1}, 1}], + ?assertError(#{what := only_external_function_references_allowed, + function := LocalFunctionReference}, + gen_hook:add_handlers(HookHandlers)), + %% check that handlers in the list are partially added (till error occurs) + ?assertEqual([{{calculate, ?HOOK_TAG1}, + [{hook_handler, {calculate, ?HOOK_TAG1}, 2, mod2, multiply, + #{hook_name => calculate, hook_tag => ?HOOK_TAG1, id => 2}}]}], + get_handlers_for_all_hooks()), + %% try to remove the same list of handlers + ?assertError(#{what := only_external_function_references_allowed, + function := LocalFunctionReference}, + gen_hook:delete_handlers(HookHandlers)), + %% check that partially added handlers are removed + ?assertEqual([{{calculate, ?HOOK_TAG1}, []}], get_handlers_for_all_hooks()). + +anonymous_fun_references_causes_error(_) -> + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% try to add hook handler using anonymous function reference + AnonymousFunctionReference = fun(Acc, _, _) -> {ok, Acc} end, + ?assertError(#{what := only_external_function_references_allowed, + function := AnonymousFunctionReference}, + gen_hook:add_handler(calculate, ?HOOK_TAG1, AnonymousFunctionReference, + #{id => 2}, 2)), + %% check that nothing is added + ?assertEqual([], get_handlers_for_all_hooks()). + +not_exported_external_fun_references_causes_error(_) -> + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% try to add hook handler using function reference for a missing module + NotExportedExternalFunctionReference1 = fun missing_module:missing_function/3, + ?assertError(#{what := module_is_not_loaded, module := missing_module}, + gen_hook:add_handler(calculate, ?HOOK_TAG1, + NotExportedExternalFunctionReference1, + #{id => 2}, 2)), + %% try to add hook handler using function reference for a missing module + NotExportedExternalFunctionReference2 = fun ?MODULE:missing_function/3, + ?assertError(#{what := function_is_not_exported, + function := NotExportedExternalFunctionReference2}, + gen_hook:add_handler(calculate, ?HOOK_TAG1, + NotExportedExternalFunctionReference2, + #{id => 2}, 2)), + %% check that nothing is added + ?assertEqual([], get_handlers_for_all_hooks()). + +invalid_hook_handler_parameters_causes_error(_) -> + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + HandlerFn = fun ?MODULE:hook_handler_stop/3, + InvalidHookHandlers = [{calculate, ?HOOK_TAG1, HandlerFn, invalid_extra_param, 2}, + {<<"invalid hook name">>, ?HOOK_TAG1, HandlerFn, #{}, 2}, + {calculate, ?HOOK_TAG1, HandlerFn, #{}, invalid_priority}], + [?assertError(function_clause, gen_hook:add_handlers([HookHandler])) + || HookHandler <- InvalidHookHandlers], + ?assertEqual([], get_handlers_for_all_hooks()). + +run_fold_executes_handlers_in_the_right_order(_) -> + mock_modules([mod1, mod2]), + PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), + MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% add various hook handlers + HookHandlers = [{calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{n => 5}, 5}, + {calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{}, 2}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{n => 3}, 1}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{}, 4}], + ?assertEqual(ok, gen_hook:add_handlers(HookHandlers)), + %% run the hook + N = (((0 + 3) * 2) + 2) * 5, %% 40 + ?assertEqual({ok, N}, gen_hook:run_fold(calculate, ?HOOK_TAG1, 0, #{n => 2})), + Self = self(), + ?assertEqual([{Self, + {mod1, plus, [0, #{n => 2}, #{hook_name => calculate, n => 3, + hook_tag => ?HOOK_TAG1}]}, + {ok, 3}}, + {Self, + {mod1, plus, [6, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {ok, 8}}], + meck:history(mod1)), + ?assertEqual([{Self, + {mod2, multiply, [3, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {ok, 6}}, + {Self, + {mod2, multiply, [8, #{n => 2}, #{hook_name => calculate, n => 5, + hook_tag => ?HOOK_TAG1}]}, + {ok, 40}}], + meck:history(mod2)), + ok. + +run_fold_stops_when_handler_returns_stop(_) -> + mock_modules([mod1, mod2]), + PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), + StopHandlerFn = get_hook_handler(mod1, stop, fun hook_handler_stop/3), + MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% add various hook handlers + HookHandlers = [{calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{n => 5}, 5}, + {calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{}, 2}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{n => 3}, 1}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{}, 4}, + {calculate, ?HOOK_TAG1, StopHandlerFn, #{}, 3}], + ?assertEqual(ok, gen_hook:add_handlers(HookHandlers)), + %% run the hook + N = ((0 + 3) * 2), %% 6 + ?assertEqual({stop, N}, gen_hook:run_fold(calculate, ?HOOK_TAG1, 0, #{n => 2})), + Self = self(), + ?assertEqual([{Self, + {mod1, plus, [0, #{n => 2}, #{hook_name => calculate, n => 3, + hook_tag => ?HOOK_TAG1}]}, + {ok, 3}}, + {Self, + {mod1, stop, [6, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {stop, 6}}], + meck:history(mod1)), + ?assertEqual([{Self, + {mod2, multiply, [3, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {ok, 6}}], + meck:history(mod2)), + ok. + +errors_in_handlers_are_reported_but_ignored(_) -> + mock_modules([mod1, mod2]), + meck:new(gen_hook, [passthrough]), + PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), + ErrorHandlerFn = get_hook_handler(mod1, error, fun hook_handler_error/3), + MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + %% check that there are no hook handlers added yet + ?assertEqual([], get_handlers_for_all_hooks()), + %% add various hook handlers + HookHandlers = [{calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{n => 5}, 5}, + {calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{}, 2}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{n => 3}, 1}, + {calculate, ?HOOK_TAG1, PlusHandlerFn, #{}, 4}, + {calculate, ?HOOK_TAG1, ErrorHandlerFn, #{}, 3}], + ?assertEqual(ok, gen_hook:add_handlers(HookHandlers)), + %% run the hook + N = (((0 + 3) * 2) + 2) * 5, %% 40 + ?assertEqual({ok, N}, gen_hook:run_fold(calculate, ?HOOK_TAG1, 0, #{n => 2})), + Self = self(), + ct:pal("~n!!! ~p~n", [meck:history(gen_hook)]), + ?assertEqual(true, meck:called(gen_hook, error_running_hook, + [{some_error, '_'}, + {hook_handler, {calculate, ?HOOK_TAG1}, 3, mod1, error, + #{hook_name => calculate, hook_tag => some_tag}}, + 6, #{n => 2}])), + ?assertMatch([{Self, + {mod1, plus, [0, #{n := 2}, #{hook_name := calculate, n := 3, + hook_tag := ?HOOK_TAG1}]}, + {ok, 3}}, + {Self, + {mod1, error, [6, #{n := 2}, #{hook_name := calculate, + hook_tag := ?HOOK_TAG1}]}, + error, some_error, _}, + {Self, + {mod1, plus, [6, #{n := 2}, #{hook_name := calculate, + hook_tag := ?HOOK_TAG1}]}, + {ok, 8}}], + meck:history(mod1)), + ?assertEqual([{Self, + {mod2, multiply, [3, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {ok, 6}}, + {Self, + {mod2, multiply, [8, #{n => 2}, #{hook_name => calculate, n => 5, + hook_tag => ?HOOK_TAG1}]}, + {ok, 40}}], + meck:history(mod2)), + ok. + +%%---------------------------------------------------------------- +%% helper functions +%%---------------------------------------------------------------- +hook_handler_plus(Acc, _, #{n := N}) -> + {ok, Acc + N}; +hook_handler_plus(Acc, #{n := N}, _) -> + {ok, Acc + N}. + +hook_handler_multiply(Acc, _, #{n := N}) -> + {ok, Acc * N}; +hook_handler_multiply(Acc, #{n := N}, _) -> + {ok, Acc * N}. + +hook_handler_stop(Acc, _, _) -> + {stop, Acc}. + +hook_handler_error(_, _, _) -> + error(some_error). + +mock_modules(Modules) when is_list(Modules) -> + meck:new(Modules, [non_strict]). + +get_hook_handler(ModName, FunName, Fun) when is_function(Fun, 3) -> + meck:expect(ModName, FunName, Fun), + fun ModName:FunName/3. + +get_handlers(HookName, HookTag) -> + case ets:lookup(gen_hook, {HookName, HookTag}) of + [{_, Ls}] -> Ls; + [] -> [] + end. + +get_handlers_for_all_hooks() -> + ets:tab2list(gen_hook). From b2404f270242f76eda394421ab585df6a8f27ac7 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Tue, 13 Jul 2021 00:01:25 +0200 Subject: [PATCH 08/13] cleaning up gen_hook_SUITE --- test/gen_hook_SUITE.erl | 93 +++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/test/gen_hook_SUITE.erl b/test/gen_hook_SUITE.erl index 13ac4d6d91..cde8a36e23 100644 --- a/test/gen_hook_SUITE.erl +++ b/test/gen_hook_SUITE.erl @@ -46,7 +46,7 @@ end_per_testcase(_, Config) -> %% test cases %%---------------------------------------------------------------- single_handler_can_be_added_and_removed(_) -> - mock_modules([mod1, mod2]), + meck:new([mod1, mod2], [non_strict]), PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet @@ -76,23 +76,26 @@ single_handler_can_be_added_and_removed(_) -> %% try to remove hook handler for ?HOOK_TAG2 and check that it's removed ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG2, PlusHandlerFn, #{id => 1}, 1)), - ?assertEqualLists([], get_handlers(calculate, ?HOOK_TAG2)), - ?assertEqualLists(Tag1Handlers, get_handlers(calculate, ?HOOK_TAG1)), + ?assertEqualLists([{{calculate, ?HOOK_TAG1}, Tag1Handlers}, + {{calculate, ?HOOK_TAG2}, []}], + get_handlers_for_all_hooks()), %% try to remove hook handler for ?HOOK_TAG2 second time %% and check that nothing has changed ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG2, PlusHandlerFn, #{id => 1}, 1)), - ?assertEqualLists([], get_handlers(calculate, ?HOOK_TAG2)), - ?assertEqualLists(Tag1Handlers, get_handlers(calculate, ?HOOK_TAG1)), + ?assertEqualLists([{{calculate, ?HOOK_TAG1}, Tag1Handlers}, + {{calculate, ?HOOK_TAG2}, []}], + get_handlers_for_all_hooks()), %% try to remove hook handlers for ?HOOK_TAG1 and check that they are removed ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{id => 2}, 2)), ?assertEqual(ok, gen_hook:delete_handler(calculate, ?HOOK_TAG1, PlusHandlerFn, #{id => 1}, 1)), - ?assertEqualLists([], get_handlers(calculate, ?HOOK_TAG1)). + ?assertEqualLists([{{calculate, ?HOOK_TAG1}, []}, {{calculate, ?HOOK_TAG2}, []}], + get_handlers_for_all_hooks()). multiple_handlers_can_be_added_and_removed(_) -> - mock_modules([mod1, mod2]), + meck:new([mod1, mod2], [non_strict]), PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet @@ -126,7 +129,7 @@ multiple_handlers_can_be_added_and_removed(_) -> get_handlers_for_all_hooks()). local_fun_references_causes_error(_) -> - mock_modules([mod1, mod2]), + meck:new([mod1, mod2], [non_strict]), PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet @@ -194,9 +197,9 @@ invalid_hook_handler_parameters_causes_error(_) -> ?assertEqual([], get_handlers_for_all_hooks()). run_fold_executes_handlers_in_the_right_order(_) -> - mock_modules([mod1, mod2]), + meck:new(mod1, [non_strict]), PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), - MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + MultiplyHandlerFn = get_hook_handler(mod1, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet ?assertEqual([], get_handlers_for_all_hooks()), %% add various hook handlers @@ -208,32 +211,31 @@ run_fold_executes_handlers_in_the_right_order(_) -> %% run the hook N = (((0 + 3) * 2) + 2) * 5, %% 40 ?assertEqual({ok, N}, gen_hook:run_fold(calculate, ?HOOK_TAG1, 0, #{n => 2})), + %% check hook handlers execution sequence Self = self(), ?assertEqual([{Self, {mod1, plus, [0, #{n => 2}, #{hook_name => calculate, n => 3, hook_tag => ?HOOK_TAG1}]}, {ok, 3}}, {Self, - {mod1, plus, [6, #{n => 2}, #{hook_name => calculate, - hook_tag => ?HOOK_TAG1}]}, - {ok, 8}}], - meck:history(mod1)), - ?assertEqual([{Self, - {mod2, multiply, [3, #{n => 2}, #{hook_name => calculate, + {mod1, multiply, [3, #{n => 2}, #{hook_name => calculate, hook_tag => ?HOOK_TAG1}]}, {ok, 6}}, {Self, - {mod2, multiply, [8, #{n => 2}, #{hook_name => calculate, n => 5, + {mod1, plus, [6, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {ok, 8}}, + {Self, + {mod1, multiply, [8, #{n => 2}, #{hook_name => calculate, n => 5, hook_tag => ?HOOK_TAG1}]}, {ok, 40}}], - meck:history(mod2)), - ok. + meck:history(mod1)). run_fold_stops_when_handler_returns_stop(_) -> - mock_modules([mod1, mod2]), + meck:new(mod1, [non_strict]), PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), StopHandlerFn = get_hook_handler(mod1, stop, fun hook_handler_stop/3), - MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + MultiplyHandlerFn = get_hook_handler(mod1, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet ?assertEqual([], get_handlers_for_all_hooks()), %% add various hook handlers @@ -246,29 +248,28 @@ run_fold_stops_when_handler_returns_stop(_) -> %% run the hook N = ((0 + 3) * 2), %% 6 ?assertEqual({stop, N}, gen_hook:run_fold(calculate, ?HOOK_TAG1, 0, #{n => 2})), + %% check hook handlers execution sequence Self = self(), ?assertEqual([{Self, {mod1, plus, [0, #{n => 2}, #{hook_name => calculate, n => 3, hook_tag => ?HOOK_TAG1}]}, {ok, 3}}, + {Self, + {mod1, multiply, [3, #{n => 2}, #{hook_name => calculate, + hook_tag => ?HOOK_TAG1}]}, + {ok, 6}}, {Self, {mod1, stop, [6, #{n => 2}, #{hook_name => calculate, hook_tag => ?HOOK_TAG1}]}, {stop, 6}}], - meck:history(mod1)), - ?assertEqual([{Self, - {mod2, multiply, [3, #{n => 2}, #{hook_name => calculate, - hook_tag => ?HOOK_TAG1}]}, - {ok, 6}}], - meck:history(mod2)), - ok. + meck:history(mod1)). errors_in_handlers_are_reported_but_ignored(_) -> - mock_modules([mod1, mod2]), + meck:new(mod1, [non_strict]), meck:new(gen_hook, [passthrough]), PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), ErrorHandlerFn = get_hook_handler(mod1, error, fun hook_handler_error/3), - MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), + MultiplyHandlerFn = get_hook_handler(mod1, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet ?assertEqual([], get_handlers_for_all_hooks()), %% add various hook handlers @@ -281,17 +282,22 @@ errors_in_handlers_are_reported_but_ignored(_) -> %% run the hook N = (((0 + 3) * 2) + 2) * 5, %% 40 ?assertEqual({ok, N}, gen_hook:run_fold(calculate, ?HOOK_TAG1, 0, #{n => 2})), - Self = self(), - ct:pal("~n!!! ~p~n", [meck:history(gen_hook)]), + %% check that error is reported ?assertEqual(true, meck:called(gen_hook, error_running_hook, [{some_error, '_'}, {hook_handler, {calculate, ?HOOK_TAG1}, 3, mod1, error, #{hook_name => calculate, hook_tag => some_tag}}, 6, #{n => 2}])), + %% check hook handlers execution sequence + Self = self(), ?assertMatch([{Self, {mod1, plus, [0, #{n := 2}, #{hook_name := calculate, n := 3, hook_tag := ?HOOK_TAG1}]}, {ok, 3}}, + {Self, + {mod1, multiply, [3, #{n := 2}, #{hook_name := calculate, + hook_tag := ?HOOK_TAG1}]}, + {ok, 6}}, {Self, {mod1, error, [6, #{n := 2}, #{hook_name := calculate, hook_tag := ?HOOK_TAG1}]}, @@ -299,18 +305,12 @@ errors_in_handlers_are_reported_but_ignored(_) -> {Self, {mod1, plus, [6, #{n := 2}, #{hook_name := calculate, hook_tag := ?HOOK_TAG1}]}, - {ok, 8}}], - meck:history(mod1)), - ?assertEqual([{Self, - {mod2, multiply, [3, #{n => 2}, #{hook_name => calculate, - hook_tag => ?HOOK_TAG1}]}, - {ok, 6}}, + {ok, 8}}, {Self, - {mod2, multiply, [8, #{n => 2}, #{hook_name => calculate, n => 5, - hook_tag => ?HOOK_TAG1}]}, + {mod1, multiply, [8, #{n := 2}, #{hook_name := calculate, n := 5, + hook_tag := ?HOOK_TAG1}]}, {ok, 40}}], - meck:history(mod2)), - ok. + meck:history(mod1)). %%---------------------------------------------------------------- %% helper functions @@ -331,18 +331,9 @@ hook_handler_stop(Acc, _, _) -> hook_handler_error(_, _, _) -> error(some_error). -mock_modules(Modules) when is_list(Modules) -> - meck:new(Modules, [non_strict]). - get_hook_handler(ModName, FunName, Fun) when is_function(Fun, 3) -> meck:expect(ModName, FunName, Fun), fun ModName:FunName/3. -get_handlers(HookName, HookTag) -> - case ets:lookup(gen_hook, {HookName, HookTag}) of - [{_, Ls}] -> Ls; - [] -> [] - end. - get_handlers_for_all_hooks() -> ets:tab2list(gen_hook). From 75b93b102fecfcad99cbbcdbd1c269008b3b53a3 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Tue, 13 Jul 2021 01:49:23 +0200 Subject: [PATCH 09/13] getting rid of ejabberd_hooks:run_fold/4 interface and converting a few hooks used in testing --- big_tests/tests/mod_ping_SUITE.erl | 2 +- big_tests/tests/push_SUITE.erl | 2 +- src/ejabberd_hooks.erl | 16 ++++------- src/mongoose_hooks.erl | 46 +++++++++++++++++++----------- test/ejabberd_hooks_SUITE.erl | 28 ++++++++++-------- test/mongoose_cleanup_SUITE.erl | 2 +- 6 files changed, 54 insertions(+), 42 deletions(-) diff --git a/big_tests/tests/mod_ping_SUITE.erl b/big_tests/tests/mod_ping_SUITE.erl index 9df29433bb..ed793f775d 100644 --- a/big_tests/tests/mod_ping_SUITE.erl +++ b/big_tests/tests/mod_ping_SUITE.erl @@ -116,7 +116,7 @@ setup_pong_hook(HostType, Pid) -> #{pid => Pid}, 50). pong_hook_handler(Acc, - #{args := [_HostType, JID, _Response, _TDelta]} = _Params, + #{jid := JID} = _Params, #{pid := Pid} = _Extra) -> Pid ! {pong, jid:to_binary(jid:to_lower(JID))}, {ok, Acc}. diff --git a/big_tests/tests/push_SUITE.erl b/big_tests/tests/push_SUITE.erl index 5b78982eb0..0b872b8bc0 100644 --- a/big_tests/tests/push_SUITE.erl +++ b/big_tests/tests/push_SUITE.erl @@ -763,7 +763,7 @@ rpc_start_hook_handler(TestCasePid, PubSubJID) -> #{pid => TestCasePid, jid => PubSubJID}, 50). hook_handler_fn(Acc, - #{args := [_Host, [PayloadMap], OptionMap]} = _Params, + #{notification_forms := [PayloadMap], options := OptionMap} = _Params, #{pid := TestCasePid, jid := PubSubJID} = _Extra) -> try jid:to_binary(mongoose_acc:get(push_notifications, pubsub_jid, Acc)) of PubSubJIDBin when PubSubJIDBin =:= PubSubJID -> diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 4f86f12be2..49fb908703 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -29,7 +29,7 @@ %% External exports -export([add/5, delete/5, - run_fold/4]). + add_args/2]). -export([add/1, delete/1]). @@ -80,16 +80,10 @@ delete(Hooks) when is_list(Hooks) -> [delete_hook(Hook) || Hook <- Hooks], ok. - -%% @doc run the hook. --spec run_fold(HookName :: atom(), - HostType :: mongooseim:host_type() | global, - Acc :: term(), - Args :: [term()]) -> - NewAcc :: term() | stopped. -run_fold(HookName, HostType, Acc, Args) when is_binary(HostType); HostType =:= global -> - {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, #{args => Args}), - RetValue. +-spec add_args(HookParams :: map(), LegacyArgsList :: [term()]) -> + HookParamsWithArgs :: map(). +add_args(HookParams, LegacyArgsList) -> + HookParams#{args => LegacyArgsList}. %%%---------------------------------------------------------------------- %%% Internal functions diff --git a/src/mongoose_hooks.erl b/src/mongoose_hooks.erl index a633aee1b9..cb83854825 100644 --- a/src/mongoose_hooks.erl +++ b/src/mongoose_hooks.erl @@ -225,7 +225,10 @@ remove_domain(HostType, Domain) -> -spec node_cleanup(Node :: node()) -> Acc :: map(). node_cleanup(Node) -> - run_global_hook(node_cleanup, #{}, [Node]). + Params = #{node => Node}, + Args = [Node], + ParamsWithLegacyArgs = ejabberd_hooks:add_args(Params, Args), + run_global_hook(node_cleanup, #{}, ParamsWithLegacyArgs). -spec ejabberd_ctl_process(Acc, Args) -> Result when Acc :: any(), @@ -306,8 +309,11 @@ presence_probe_hook(HostType, Acc, From, To, Pid) -> Options :: #{atom() => binary()}, Result :: ok | {error, any()}. push_notifications(Server, Acc, NotificationForms, Options) -> - run_hook_for_host_type(push_notifications, Server, Acc, - [Server, NotificationForms, Options]). + Params = #{server => Server, options => Options, + notification_forms => NotificationForms}, + Args = [Server, NotificationForms, Options], + ParamsWithLegacyArgs = ejabberd_hooks:add_args(Params, Args), + run_hook_for_host_type(push_notifications, Server, Acc, ParamsWithLegacyArgs). %%% @doc The `register_command' hook is called when a command %%% is registered in `mongoose_commands'. @@ -395,7 +401,10 @@ set_vcard(LServer, User, VCard) -> JID :: jid:jid(), Result :: mongoose_acc:t(). unacknowledged_message(HostType, Acc, JID) -> - run_hook_for_host_type(unacknowledged_message, HostType, Acc, [JID]). + Params = #{jid => JID}, + Args = [JID], + ParamsWithLegacyArgs = ejabberd_hooks:add_args(Params, Args), + run_hook_for_host_type(unacknowledged_message, HostType, Acc, ParamsWithLegacyArgs). %%% @doc The `unregister_command' hook is called when a command %%% is unregistered from `mongoose_commands'. @@ -430,8 +439,10 @@ user_available_hook(HostType, Acc, JID) -> TDelta :: non_neg_integer(), Result :: mongoose_acc:t(). user_ping_response(HostType, Acc, JID, Response, TDelta) -> - run_hook_for_host_type(user_ping_response, HostType, Acc, - [HostType, JID, Response, TDelta]). + Params = #{jid => JID, response => Response, time_delta => TDelta}, + Args = [HostType, JID, Response, TDelta], + ParamsWithLegacyArgs = ejabberd_hooks:add_args(Params, Args), + run_hook_for_host_type(user_ping_response, HostType, Acc, ParamsWithLegacyArgs). %%% @doc The `user_ping_timeout' hook is called when there is a timeout %%% when waiting for a ping response from a user. @@ -1442,22 +1453,25 @@ mod_global_distrib_unknown_recipient(GlobalHost, Info) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- - -%% run_global_hook(HookName, Acc, Params) when is_map(Params) -> -%% {_, RetValue} = gen_hook:run_fold(HookName, global, Acc, Params), -%% RetValue; +run_global_hook(HookName, Acc, Params) when is_map(Params) -> + run_fold(HookName, global, Acc, Params); run_global_hook(HookName, Acc, Args) when is_list(Args) -> - ejabberd_hooks:run_fold(HookName, global, Acc, Args). + ParamsWithLegacyArgs = ejabberd_hooks:add_args(#{}, Args), + run_fold(HookName, global, Acc, ParamsWithLegacyArgs). run_hook_for_host_type(HookName, undefined, Acc, Args) -> ?LOG_ERROR(#{what => undefined_host_type, text => <<"Running hook for an undefined host type">>, hook_name => HookName, hook_acc => Acc, hook_args => Args}), Acc; -%% run_hook_for_host_type(HookName, HostType, Acc, Params) when is_binary(HostType), -%% is_map(Params) -> -%% {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, Params), -%% RetValue; +run_hook_for_host_type(HookName, HostType, Acc, Params) when is_binary(HostType), + is_map(Params) -> + run_fold(HookName, HostType, Acc, Params); run_hook_for_host_type(HookName, HostType, Acc, Args) when is_binary(HostType), is_list(Args) -> - ejabberd_hooks:run_fold(HookName, HostType, Acc, Args). + ParamsWithLegacyArgs = ejabberd_hooks:add_args(#{}, Args), + run_fold(HookName, HostType, Acc, ParamsWithLegacyArgs). + +run_fold(HookName, HostType, Acc, Params) when is_map(Params) -> + {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, Params), + RetValue. diff --git a/test/ejabberd_hooks_SUITE.erl b/test/ejabberd_hooks_SUITE.erl index d7907083c3..efc1646031 100644 --- a/test/ejabberd_hooks_SUITE.erl +++ b/test/ejabberd_hooks_SUITE.erl @@ -67,7 +67,7 @@ hooks_run_launches_nullary_fun(_) -> given_hook_added(test_run_hook, hook_mod, fun_nullary, 1), %% when - ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, []), + run_fold(test_run_hook, ?HOST, ok, []), %% then H = meck:history(hook_mod), @@ -79,7 +79,7 @@ hooks_run_launches_unary_fun(_) -> given_hook_added(test_run_hook, hook_mod, fun_onearg, 1), %% when - ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, [oneval]), + run_fold(test_run_hook, ?HOST, ok, [oneval]), %% then [{_,{hook_mod,fun_onearg,[ok, oneval]}, oneval}] = meck:history(hook_mod). @@ -93,7 +93,7 @@ hooks_run_ignores_different_arity_funs(_) -> given_hook_added(test_run_hook, hook_mod, fun_twoarg, 1), %% when - ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, [one, two]), + run_fold(test_run_hook, ?HOST, ok, [one, two]), %% then [{_,{hook_mod, fun_twoarg, [ok, one, two]}, success2}] = meck:history(hook_mod). @@ -107,7 +107,7 @@ hooks_run_stops_when_fun_returns_stop(_) -> given_hook_added(test_run_hook, hook_mod, another_fun, 2), %% when - ejabberd_hooks:run_fold(test_run_hook, ?HOST, ok, []), + run_fold(test_run_hook, ?HOST, ok, []), %% then [{_,{hook_mod,a_fun,[ok]}, stop}] = meck:history(hook_mod). @@ -119,7 +119,7 @@ hooks_run_fold_folds_with_unary_fun(_) -> given_hook_added(test_fold_hook, hook_mod, unary_folder, 1), %% when - ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), + run_fold(test_fold_hook, ?HOST, initial, []), %% then [{_,{hook_mod,unary_folder,[initial]}, done}] = meck:history(hook_mod). @@ -130,7 +130,7 @@ hooks_run_fold_folds_with_binary_fun(_) -> given_hook_added(test_fold_hook, hook_mod, binary_folder, 1), %% when - ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, [arg1]), + run_fold(test_fold_hook, ?HOST, initial, [arg1]), %% then [{_,{hook_mod,binary_folder,[initial, arg1]}, done}] = meck:history(hook_mod). @@ -144,7 +144,7 @@ hooks_run_fold_passes_acc_along(_) -> given_hook_added(test_fold_hook, hook_mod2, second_folder, 2), %% when - R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, 0, [10]), + R = run_fold(test_fold_hook, ?HOST, 0, [10]), %% then -10 = R. @@ -158,7 +158,7 @@ hooks_run_fold_stops_when_fun_returns_stop(_) -> given_hook_added(test_fold_hook, hook_mod2, folder, 2), %% when - R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, continue, []), + R = run_fold(test_fold_hook, ?HOST, continue, []), %% then [{_,{hook_mod1,stopper,[continue]}, stop}] = meck:history(hook_mod1), @@ -175,7 +175,7 @@ hooks_run_fold_preserves_order(_) -> given_hook_added(test_fold_hook, hook_mod2, second_folder, 2), %% when - R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, 0, []), + R = run_fold(test_fold_hook, ?HOST, 0, []), %% then 2 = R. @@ -191,7 +191,7 @@ error_in_run_fold_is_ignored(_) -> given_hook_added(test_fold_hook, working_mod, good, 2), %% when - R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), + R = run_fold(test_fold_hook, ?HOST, initial, []), %% then i_was_run = R, @@ -209,7 +209,7 @@ throw_in_run_fold_is_ignored(_) -> given_hook_added(test_fold_hook, working_mod, good, 2), %% when - R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), + R = run_fold(test_fold_hook, ?HOST, initial, []), %% then initial = R, @@ -228,7 +228,7 @@ exit_in_run_fold_is_ignored(_) -> given_hook_added(test_fold_hook, working_mod, good, 2), %% when - R = ejabberd_hooks:run_fold(test_fold_hook, ?HOST, initial, []), + R = run_fold(test_fold_hook, ?HOST, initial, []), %% then initial = R, @@ -258,6 +258,10 @@ given_module(ModName, FunName, Fun) -> given_fun(ModName, FunName, Fun) -> meck:expect(ModName, FunName, Fun). +run_fold(HookName, HostType, Acc, Args) -> + Params = ejabberd_hooks:add_args(#{}, Args), + {_, RetValue} = gen_hook:run_fold(HookName, HostType, Acc, Params), + RetValue. get_hooks() -> ets:tab2list(gen_hook). diff --git a/test/mongoose_cleanup_SUITE.erl b/test/mongoose_cleanup_SUITE.erl index 42104a1235..8ecd2b9e70 100644 --- a/test/mongoose_cleanup_SUITE.erl +++ b/test/mongoose_cleanup_SUITE.erl @@ -80,7 +80,7 @@ cleaner_runs_hook_on_nodedown(_Config) -> ?assertEqual(false, meck:called(gen_hook, error_running_hook, ['_', '_', '_', '_'])). -notify_self_hook(Acc, #{args := [Node]}, #{self := Self}) -> +notify_self_hook(Acc, #{node := Node}, #{self := Self}) -> Self ! {got_nodedown, Node}, {ok, Acc}. From 2ec4c5d3140400d72a80166ebd1ec9b96e51e0ae Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Tue, 13 Jul 2021 02:01:12 +0200 Subject: [PATCH 10/13] cleaning up ejabberd_hooks_SUITE --- test/ejabberd_hooks_SUITE.erl | 6 ------ test/gen_hook_SUITE.erl | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/test/ejabberd_hooks_SUITE.erl b/test/ejabberd_hooks_SUITE.erl index efc1646031..5b36665247 100644 --- a/test/ejabberd_hooks_SUITE.erl +++ b/test/ejabberd_hooks_SUITE.erl @@ -31,11 +31,6 @@ init_per_suite(C) -> end_per_suite(_C) -> application:stop(exometer_core). -init_per_testcase(_, C) -> - gen_hook:start_link(), - catch ets:new(local_config, [named_table]), - C. - a_module_fun_can_be_added(_) -> given_hooks_started(), given_module(hook_mod, fun_a, fun(_) -> ok end), @@ -242,7 +237,6 @@ exit_in_run_fold_is_ignored(_) -> const(N) -> fun(_) -> N end. given_hooks_started() -> - error_logger:tty(false), Fun = fun(all_metrics_are_global) -> false end, given_module(ejabberd_config, get_local_option, Fun), gen_hook:start_link(). diff --git a/test/gen_hook_SUITE.erl b/test/gen_hook_SUITE.erl index cde8a36e23..2f8a0e3431 100644 --- a/test/gen_hook_SUITE.erl +++ b/test/gen_hook_SUITE.erl @@ -30,7 +30,7 @@ end_per_suite(Config) -> application:stop(exometer_core), Config. -init_per_testcase(_,Config) -> +init_per_testcase(_, Config) -> Fun = fun(all_metrics_are_global) -> false end, meck:new(ejabberd_config), meck:expect(ejabberd_config, get_local_option, Fun), @@ -50,7 +50,7 @@ single_handler_can_be_added_and_removed(_) -> PlusHandlerFn = get_hook_handler(mod1, plus, fun hook_handler_plus/3), MultiplyHandlerFn = get_hook_handler(mod2, multiply, fun hook_handler_multiply/3), %% check that there are no hook handlers added yet - ?assertEqual([],get_handlers_for_all_hooks()), + ?assertEqual([], get_handlers_for_all_hooks()), %% add various hook handlers ?assertEqual(ok, gen_hook:add_handler(calculate, ?HOOK_TAG1, MultiplyHandlerFn, #{id => 2}, 2)), From 9e2d73cb2a1e19088bff7cbca94d605a0d8e51b3 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Wed, 14 Jul 2021 14:37:04 +0200 Subject: [PATCH 11/13] restricting hook_tag() type --- src/gen_hook.erl | 12 +++++++++--- test/gen_hook_SUITE.erl | 15 +++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/gen_hook.erl b/src/gen_hook.erl index ad60d9457e..0fd4b72f25 100644 --- a/src/gen_hook.erl +++ b/src/gen_hook.erl @@ -24,7 +24,7 @@ -include("mongoose.hrl"). -type hook_name() :: atom(). --type hook_tag() :: any(). +-type hook_tag() :: mongoose:host_type() | global. %% while Accumulator is not limited to any type, it's recommended to use maps. -type hook_acc() :: any(). @@ -218,7 +218,8 @@ error_running_hook(Reason, Handler, Acc, Params) -> -spec make_hook_handler(hook_tuple()) -> #hook_handler{}. make_hook_handler({HookName, Tag, Function, Extra, Priority} = HookTuple) - when is_atom(HookName), is_function(Function, 3), is_map(Extra), + when is_atom(HookName), is_binary(Tag) or (Tag =:= global), + is_function(Function, 3), is_map(Extra), is_integer(Priority), Priority > 0 -> NewExtra = extend_extra(HookTuple), {Module, FunctionName} = check_hook_function(Function), @@ -263,7 +264,12 @@ hook_key(HookName, Tag) -> -spec extend_extra(hook_tuple()) -> hook_extra(). extend_extra({HookName, Tag, _Function, OriginalExtra, _Priority}) -> - ExtraExtension = #{hook_name => HookName, hook_tag => Tag}, + ExtraExtension = case Tag of + global -> #{hook_name => HookName, hook_tag => Tag}; + HostType when is_binary(HostType) -> + #{hook_name => HookName, hook_tag => Tag, + host_type => HostType} + end, %% KV pairs of the OriginalExtra map will remain unchanged, %% only the new keys from the ExtraExtension map will be added %% to the NewExtra map diff --git a/test/gen_hook_SUITE.erl b/test/gen_hook_SUITE.erl index 2f8a0e3431..13123a91b9 100644 --- a/test/gen_hook_SUITE.erl +++ b/test/gen_hook_SUITE.erl @@ -3,8 +3,8 @@ -include_lib("eunit/include/eunit.hrl"). --define(HOOK_TAG1, some_tag). --define(HOOK_TAG2, another_tag). +-define(HOOK_TAG1, global). +-define(HOOK_TAG2, <<"some tag">>). -define(assertEqualLists(L1, L2), ?assertEqual(lists:sort(L1), lists:sort(L2))). @@ -67,7 +67,8 @@ single_handler_can_be_added_and_removed(_) -> AllHandlers = [{{calculate, ?HOOK_TAG1}, Tag1Handlers}, {{calculate, ?HOOK_TAG2}, [{hook_handler, {calculate, ?HOOK_TAG2}, 1, mod1, plus, - #{hook_name => calculate, hook_tag => ?HOOK_TAG2, id => 1}}]}], + #{hook_name => calculate, hook_tag => ?HOOK_TAG2, + host_type =>?HOOK_TAG2, id => 1}}]}], ?assertEqualLists(AllHandlers, get_handlers_for_all_hooks()), %% try to add some hook handler second time and check that nothing has changed ?assertEqual(ok, gen_hook:add_handler(calculate, ?HOOK_TAG1, MultiplyHandlerFn, @@ -114,7 +115,8 @@ multiple_handlers_can_be_added_and_removed(_) -> AllHandlers = [{{calculate, ?HOOK_TAG1}, Tag1Handlers}, {{calculate, ?HOOK_TAG2}, [{hook_handler, {calculate, ?HOOK_TAG2}, 1, mod1, plus, - #{hook_name => calculate, hook_tag => ?HOOK_TAG2, id => 1}}]}], + #{hook_name => calculate, hook_tag => ?HOOK_TAG2, + host_type =>?HOOK_TAG2, id => 1}}]}], ?assertEqualLists(AllHandlers, get_handlers_for_all_hooks()), %% try to add hook handlers second time and check that nothing has changed ?assertEqual(ok, gen_hook:add_handlers(HookHandlers)), @@ -191,7 +193,8 @@ invalid_hook_handler_parameters_causes_error(_) -> HandlerFn = fun ?MODULE:hook_handler_stop/3, InvalidHookHandlers = [{calculate, ?HOOK_TAG1, HandlerFn, invalid_extra_param, 2}, {<<"invalid hook name">>, ?HOOK_TAG1, HandlerFn, #{}, 2}, - {calculate, ?HOOK_TAG1, HandlerFn, #{}, invalid_priority}], + {calculate, ?HOOK_TAG1, HandlerFn, #{}, invalid_priority}, + {calculate, invalid_hook_tag, HandlerFn, #{}, 2}], [?assertError(function_clause, gen_hook:add_handlers([HookHandler])) || HookHandler <- InvalidHookHandlers], ?assertEqual([], get_handlers_for_all_hooks()). @@ -286,7 +289,7 @@ errors_in_handlers_are_reported_but_ignored(_) -> ?assertEqual(true, meck:called(gen_hook, error_running_hook, [{some_error, '_'}, {hook_handler, {calculate, ?HOOK_TAG1}, 3, mod1, error, - #{hook_name => calculate, hook_tag => some_tag}}, + #{hook_name => calculate, hook_tag => ?HOOK_TAG1}}, 6, #{n => 2}])), %% check hook handlers execution sequence Self = self(), From 43a40647bd72f60b9a567aaee0a80d6ab301db38 Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Fri, 16 Jul 2021 15:08:16 +0200 Subject: [PATCH 12/13] changes according to the review comment. This branch introduces initial rework of the hooks framework The key changes: * hook handler functions now have fixed number of arguments: - Acc - the same meaning as before - Parameters map - input parameters are now provided in a form of map instead of variable number of handler function arguments - Extra map - every hook handler now can have a static context, in the same way as packet handlers. This map is automatically extended with 'hook_name' and 'hook_tag' ('global' or HostType) parameters on hook registration, so there is no need to add HostType into Parameters map any more. * the old format of hook handlers is still supported (until the full conversion of all the hook handlers is done) * conversion of the hooks can be done hook by hook, the following steps must be done to convert the hook: - convert hook execution function at 'mongoose_hooks' module. - convert all the handlers of the hook (they must be registered using gen_hook interface instead of ejabberd_hook). - also, it's possible to mix old & new hook handlers formats (see example at mongoose_hooks:push_notifications/4). * note that 'gen_hook' accepts only external function references (in format "fun Module:Function/Arity', e.g. "fun erlang:is_function/1") as hook handler function parameter. --- big_tests/tests/sm_SUITE.erl | 7 ++++--- src/ejabberd_hooks.erl | 2 +- src/gen_hook.erl | 7 +++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/big_tests/tests/sm_SUITE.erl b/big_tests/tests/sm_SUITE.erl index 21df63604c..bfb24245bb 100644 --- a/big_tests/tests/sm_SUITE.erl +++ b/big_tests/tests/sm_SUITE.erl @@ -1327,11 +1327,12 @@ stop_hook_listener(HookExtra) -> rpc(mim(), ?MODULE, rpc_stop_hook_handler, [HookExtra, host_type()]). rpc_start_hook_handler(TestCasePid, User, HostType) -> - LUser=jid:nodeprep(User), + LUser = jid:nodeprep(User), + Extra = #{luser => LUser, pid => TestCasePid}, gen_hook:add_handler(unacknowledged_message, HostType, fun ?MODULE:hook_handler_fn/3, - #{luser => LUser, pid => TestCasePid}, 50), - #{luser => LUser, pid => TestCasePid}. + Extra, 50), + Extra. rpc_stop_hook_handler(HookExtra, HostType) -> gen_hook:delete_handler(unacknowledged_message, HostType, diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 329ae543f0..58d53353cc 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -95,7 +95,7 @@ add_args(HookParams, LegacyArgsList) -> add_hook({HookName, HostType, Module, Function, Priority}) when is_atom(Function) -> gen_hook:add_handler(HookName, HostType, fun ?MODULE:gen_hook_fn_wrapper/3, - #{module => Module, function =>Function}, + #{module => Module, function => Function}, Priority). -spec delete_hook(hook()) -> ok. diff --git a/src/gen_hook.erl b/src/gen_hook.erl index 0fd4b72f25..e3a7f6b7f1 100644 --- a/src/gen_hook.erl +++ b/src/gen_hook.erl @@ -106,13 +106,13 @@ delete_handler(HookTuple) -> gen_server:call(?MODULE, {delete_handler, Handler}). %% @doc Run hook handlers in order of priority (lower number means higher priority). -%% * if hook handler returns {ok, NewAcc}, the NewAcc value is used +%% * if a hook handler returns {ok, NewAcc}, the NewAcc value is used %% as an accumulator parameter for the following hook handler. %% * if a hook handler returns {stop, NewAcc}, execution stops immediately %% without invoking lower priority hook handlers. -%% * if hook handler crashes, the error is logged and the next hook handler +%% * if a hook handler crashes, the error is logged and the next hook handler %% is executed. -%% Note that every hook handler MUST return a valid Acc. If hook handler is not +%% Note that every hook handler MUST return a valid Acc. If a hook handler is not %% interested in changing Acc parameter (or even if Acc is not used for a hook %% at all), it must return (pass through) an unchanged input accumulator value. -spec run_fold(HookName :: hook_name(), @@ -255,7 +255,6 @@ check_hook_function(Function) when is_function(Function, 3) -> -spec throw_error(map()) -> no_return(). throw_error(ErrorMap) -> - ?LOG_ERROR(ErrorMap), error(ErrorMap). -spec hook_key(HookName :: hook_name(), Tag :: hook_tag()) -> key(). From 9463958899ba5014c57c17a020fd889bd088c8ff Mon Sep 17 00:00:00 2001 From: DenysGonchar Date: Fri, 16 Jul 2021 16:00:56 +0200 Subject: [PATCH 13/13] fixing xref issues --- src/gen_hook.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gen_hook.erl b/src/gen_hook.erl index e3a7f6b7f1..ad896f6c98 100644 --- a/src/gen_hook.erl +++ b/src/gen_hook.erl @@ -21,6 +21,8 @@ %% exported for unit tests only -export([error_running_hook/4]). +-ignore_xref([start_link/0, add_handlers/1, delete_handlers/1]). + -include("mongoose.hrl"). -type hook_name() :: atom().