Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,5 @@ doc/mongooseim.doap
doc/user-guide/Supported-XEPs.md
big_tests/.DS_Store
.vscode
.venv/
.tool-versions
2 changes: 2 additions & 0 deletions big_tests/dynamic_domains.spec
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
{suites, "tests", metrics_roster_SUITE}.
{suites, "tests", metrics_session_SUITE}.
{suites, "tests", mod_blocking_SUITE}.
{suites, "tests", mod_event_pusher_http_SUITE}.
{suites, "tests", mod_http_upload_SUITE}.
{suites, "tests", mod_ping_SUITE}.
{suites, "tests", mod_time_SUITE}.
Expand All @@ -90,6 +91,7 @@
{suites, "tests", presence_SUITE}.
{suites, "tests", privacy_SUITE}.
{suites, "tests", private_SUITE}.
{suites, "tests", push_SUITE}.
{suites, "tests", race_conditions_SUITE}.
{suites, "tests", rdbms_SUITE}.
{suites, "tests", rest_SUITE}.
Expand Down
27 changes: 26 additions & 1 deletion big_tests/tests/domain_removal_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ all() ->
{group, markers_removal},
{group, vcard_removal},
{group, last_removal},
{group, push_removal},
{group, removal_failures}
].

Expand All @@ -50,6 +51,7 @@ groups() ->
{markers_removal, [], [markers_removal]},
{vcard_removal, [], [vcard_removal]},
{last_removal, [], [last_removal]},
{push_removal, [], [push_removal]},
{removal_failures, [], [removal_stops_if_handler_fails]}
].

Expand Down Expand Up @@ -143,7 +145,10 @@ group_to_modules(markers_removal) ->
group_to_modules(vcard_removal) ->
[{mod_vcard, mod_config(mod_vcard, #{backend => rdbms})}];
group_to_modules(last_removal) ->
[{mod_last, mod_config(mod_last, #{backend => rdbms})}].
[{mod_last, mod_config(mod_last, #{backend => rdbms})}];
group_to_modules(push_removal) ->
PushOpts = #{backend => rdbms},
[{mod_event_pusher, #{push => config_parser_helper:config([modules, mod_event_pusher, push], PushOpts)}}].

is_internal_or_rdbms() ->
AuthMods = mongoose_helper:auth_modules(),
Expand Down Expand Up @@ -454,6 +459,26 @@ last_removal(Config0) ->
end,
escalus:fresh_story_with_config(Config0, [{alice, 1}, {bob, 1}], F).

push_removal(Config) ->
escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
%% Alice enables push notifications
PubsubJID = <<"pubsub.localhost">>,
Node = <<"test_node">>,
EnableStanza = push_helper:enable_stanza(PubsubJID, Node),
escalus:send(Alice, EnableStanza),
escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)),
%% Check that the subscription exists in the database
AliceJid = jid:from_binary(escalus_client:short_jid(Alice)),
{ok, Services} = rpc(mim(), mod_event_pusher_push_backend, get_publish_services,
[host_type(), AliceJid]),
?assertMatch([_], Services),
%% Remove domain and check that push subscriptions are removed
run_remove_domain(),
{ok, ServicesAfter} = rpc(mim(), mod_event_pusher_push_backend, get_publish_services,
[host_type(), AliceJid]),
?assertMatch([], ServicesAfter)
end).

removal_stops_if_handler_fails(Config0) ->
mongoose_helper:inject_module(?MODULE),
F = fun(Config, Alice) ->
Expand Down
2 changes: 1 addition & 1 deletion big_tests/tests/mod_event_pusher_http_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ proper_http_message_encode_decode(Config) ->
fun(Alice, Bob) ->
Sender = jid:nameprep(escalus_client:username(Alice)),
Receiver = jid:nameprep(escalus_client:username(Bob)),
Server = jid:nodeprep(escalus_users:get_host(Config, alice)),
Server = domain_helper:domain(),
Message = <<"Hi Test!&escape=Hello">>,

Stanza = escalus_stanza:chat_to(Bob, Message),
Expand Down
18 changes: 10 additions & 8 deletions big_tests/tests/push_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -710,18 +710,20 @@ valid_ns_if_defined(NS, FormProplist) ->
start_hook_listener(Config) ->
TestCasePid = self(),
PubSubJID = pubsub_jid(Config),
rpc(?MODULE, rpc_start_hook_handler, [TestCasePid, PubSubJID]),
HostType = host_type(),
rpc(?MODULE, rpc_start_hook_handler, [TestCasePid, PubSubJID, HostType]),
[{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]).
HostType = host_type(),
rpc(?MODULE, rpc_stop_hook_handler, [TestCasePid, PubSubJID, HostType]).

rpc_start_hook_handler(TestCasePid, PubSubJID) ->
gen_hook:add_handler(push_notifications, <<"localhost">>,
rpc_start_hook_handler(TestCasePid, PubSubJID, HostType) ->
gen_hook:add_handler(push_notifications, HostType,
fun ?MODULE:hook_handler_fn/3,
#{pid => TestCasePid, jid => PubSubJID}, 50).
#{pid => TestCasePid, jid => PubSubJID, host_type => HostType}, 50).

hook_handler_fn(Acc,
#{notification_forms := [PayloadMap], options := OptionMap} = _Params,
Expand All @@ -741,10 +743,10 @@ hook_handler_fn(Acc,
end,
{ok, Acc}.

rpc_stop_hook_handler(TestCasePid, PubSubJID) ->
gen_hook:delete_handler(push_notifications, <<"localhost">>,
rpc_stop_hook_handler(TestCasePid, PubSubJID, HostType) ->
gen_hook:delete_handler(push_notifications, HostType,
fun ?MODULE:hook_handler_fn/3,
#{pid => TestCasePid, jid => PubSubJID}, 50).
#{pid => TestCasePid, jid => PubSubJID, host_type => HostType}, 50).

%%--------------------------------------------------------------------
%% Test helpers
Expand Down
1 change: 0 additions & 1 deletion doc/configuration/Modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ This module provides the functionality specified in [XEP-0092: Software Version]
There are some modules that don't support dynamic domains for now.
These must **not** be enabled when using host types in `modules` or [`host_config.modules`](./host_config.md#host_configmodules) sections:

* [mod_event_pusher](../modules/mod_event_pusher.md)
* [mod_global_distrib](../modules/mod_global_distrib.md)
* [mod_jingle_sip](../modules/mod_jingle_sip.md)
* [mod_pubsub](../modules/mod_pubsub.md)
Expand Down
3 changes: 0 additions & 3 deletions doc/modules/mod_event_pusher.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ The events include presence updates and incoming/outgoing messages.
Currently supported backends include [http], [push], [rabbit] and [sns].
Refer to their specific documentation to learn more about their functions and configuration options.

!!! Warning
This module does not support [dynamic domains](../configuration/general.md#generalhost_types).

## Configuration

Each backend is configured in a corresponding subsection.
Expand Down
6 changes: 5 additions & 1 deletion src/event_pusher/mod_event_pusher.erl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
-type push_event_acc() :: #{acc := mongoose_acc:t(), metadata := metadata()}.
-export_type([event/0, metadata/0, push_event_acc/0, push_event_params/0]).

-export([deps/2, start/2, stop/1, config_spec/0, push_event/2]).
-export([deps/2, start/2, stop/1, config_spec/0, push_event/2, supported_features/0]).

-export([config_metrics/1]).

Expand Down Expand Up @@ -89,3 +89,7 @@ backend_module(sns) -> mod_event_pusher_sns.

all_backends() ->
[http, push, rabbit, sns].

-spec supported_features() -> [atom()].
supported_features() ->
[dynamic_domains].
6 changes: 5 additions & 1 deletion src/event_pusher/mod_event_pusher_http.erl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
-include("jlib.hrl").

%% API
-export([start/2, stop/1, hooks/1, config_spec/0, instrumentation/1]).
-export([start/2, stop/1, hooks/1, config_spec/0, instrumentation/1, supported_features/0]).

%% hook handlers
-export([push_event/3]).
Expand All @@ -60,6 +60,10 @@ start(_HostType, _Opts) ->
stop(_HostType) ->
ok.

-spec supported_features() -> [atom()].
supported_features() ->
[dynamic_domains].

-spec hooks(mongooseim:host_type()) -> gen_hook:hook_list().
hooks(HostType) ->
[{push_event, HostType, fun ?MODULE:push_event/3, #{}, 50}].
Expand Down
48 changes: 31 additions & 17 deletions src/event_pusher/mod_event_pusher_push.erl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
%%--------------------------------------------------------------------

%% gen_mod behaviour
-export([start/2, stop/1, hooks/1, config_spec/0]).
-export([start/2, stop/1, hooks/1, config_spec/0, supported_features/0]).

%% mongoose_module_metrics behaviour
-export([config_metrics/1]).
Expand All @@ -37,15 +37,16 @@
-export([push_event/3]).

%% Hooks and IQ handlers
-export([iq_handler/4,
remove_user/3]).
-export([iq_handler/5,
remove_user/3,
remove_domain/3]).

%% Plugin utils
-export([cast/3]).
-export([is_virtual_pubsub_host/3]).
-export([disable_node/4]).

-ignore_xref([iq_handler/4]).
-ignore_xref([iq_handler/5]).

%% Types
-type publish_service() :: {PubSub :: jid:jid(), Node :: pubsub_node(), Form :: form()}.
Expand All @@ -71,22 +72,23 @@ start_pool(HostType, #{wpool := WpoolOpts}) ->
{ok, _} = mongoose_wpool:start(generic, HostType, pusher_push, maps:to_list(WpoolOpts)).

init_iq_handlers(HostType, #{iqdisc := IQDisc}) ->
gen_iq_handler:add_iq_handler(ejabberd_local, HostType, ?NS_PUSH, ?MODULE,
iq_handler, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, HostType, ?NS_PUSH, ?MODULE,
iq_handler, IQDisc).
gen_iq_handler:add_iq_handler_for_domain(
HostType, ?NS_PUSH, ejabberd_local, fun ?MODULE:iq_handler/5, #{}, IQDisc),
gen_iq_handler:add_iq_handler_for_domain(
HostType, ?NS_PUSH, ejabberd_sm, fun ?MODULE:iq_handler/5, #{}, IQDisc).

-spec stop(mongooseim:host_type()) -> ok.
stop(HostType) ->
gen_iq_handler:remove_iq_handler(ejabberd_sm, HostType, ?NS_PUSH),
gen_iq_handler:remove_iq_handler(ejabberd_local, HostType, ?NS_PUSH),
gen_iq_handler:remove_iq_handler_for_domain(HostType, ?NS_PUSH, ejabberd_sm),
gen_iq_handler:remove_iq_handler_for_domain(HostType, ?NS_PUSH, ejabberd_local),

mongoose_wpool:stop(generic, HostType, pusher_push),
ok.

-spec hooks(mongooseim:host_type()) -> gen_hook:hook_list().
hooks(HostType) ->
[{remove_user, HostType, fun ?MODULE:remove_user/3, #{}, 90},
{remove_domain, HostType, fun ?MODULE:remove_domain/3, #{}, 50},
{push_event, HostType, fun ?MODULE:push_event/3, #{}, 50}].

-spec config_spec() -> mongoose_config_spec:config_section().
Expand Down Expand Up @@ -115,12 +117,24 @@ wpool_spec() ->
-spec remove_user(Acc, Params, Extra) -> {ok, Acc} when
Acc :: mongoose_acc:t(),
Params :: #{jid := jid:jid()},
Extra :: map().
remove_user(Acc, #{jid := #jid{luser = LUser, lserver = LServer}}, _) ->
R = mod_event_pusher_push_backend:disable(LServer, jid:make_noprep(LUser, LServer, <<>>)),
Extra :: gen_hook:extra().
remove_user(Acc, #{jid := #jid{luser = LUser, lserver = LServer}}, #{host_type := HostType}) ->
R = mod_event_pusher_push_backend:disable(HostType, jid:make_noprep(LUser, LServer, <<>>)),
mongoose_lib:log_if_backend_error(R, ?MODULE, ?LINE, {Acc, LUser, LServer}),
{ok, Acc}.

-spec supported_features() -> [atom()].
supported_features() ->
[dynamic_domains].

-spec remove_domain(Acc, Params, Extra) -> {ok, Acc} when
Acc :: mongoose_domain_api:remove_domain_acc(),
Params :: #{domain := jid:lserver()},
Extra :: gen_hook:extra().
remove_domain(Acc, #{domain := Domain}, #{host_type := HostType}) ->
mod_event_pusher_push_backend:remove_domain(HostType, Domain),
{ok, Acc}.

-spec push_event(mod_event_pusher:push_event_acc(), mod_event_pusher:push_event_params(),
gen_hook:extra()) -> {ok, mod_event_pusher:push_event_acc()}.
push_event(HookAcc, #{event := Event = #chat_event{direction = out, to = To, type = Type}}, _Extra)
Expand All @@ -138,12 +152,12 @@ push_event(HookAcc = #{acc := Acc}, #{event := Event = #unack_msg_event{to = To}
push_event(HookAcc, _Params, _Extra) ->
{ok, HookAcc}.

-spec iq_handler(From :: jid:jid(), To :: jid:jid(), Acc :: mongoose_acc:t(),
IQ :: jlib:iq()) ->
-spec iq_handler(Acc :: mongoose_acc:t(), From :: jid:jid(), To :: jid:jid(),
IQ :: jlib:iq(), Extra :: gen_hook:extra()) ->
{mongoose_acc:t(), jlib:iq() | ignore}.
iq_handler(_From, _To, Acc, IQ = #iq{type = get, sub_el = SubEl}) ->
iq_handler(Acc, _From, _To, IQ = #iq{type = get, sub_el = SubEl}, _Extra) ->
{Acc, IQ#iq{type = error, sub_el = [SubEl, mongoose_xmpp_errors:not_allowed()]}};
iq_handler(From, _To, Acc, IQ = #iq{type = set, sub_el = Request}) ->
iq_handler(Acc, From, _To, IQ = #iq{type = set, sub_el = Request}, _Extra) ->
HostType = mongoose_acc:host_type(Acc),
Res = case parse_request(Request) of
{enable, BarePubSubJID, Node, FormFields} ->
Expand Down
10 changes: 9 additions & 1 deletion src/event_pusher/mod_event_pusher_push_backend.erl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
enable/5,
disable/2,
disable/4,
get_publish_services/2]).
get_publish_services/2,
remove_domain/2]).

-define(MAIN_MODULE, mod_event_pusher_push).

Expand All @@ -36,6 +37,8 @@
-callback get_publish_services(mongooseim:host_type(), UserJID :: jid:jid()) ->
{ok, [mod_event_pusher_push:publish_service()]} | {error, Reason :: term()}.

-callback remove_domain(mongooseim:host_type(), jid:lserver()) -> ok.

%% API

-spec init(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
Expand Down Expand Up @@ -72,3 +75,8 @@ disable(HostType, UserJID, PubsubJID, Node) ->
get_publish_services(HostType, User) ->
Args = [HostType, User],
mongoose_backend:call_tracked(HostType, ?MAIN_MODULE, ?FUNCTION_NAME, Args).

-spec remove_domain(mongooseim:host_type(), jid:lserver()) -> ok.
remove_domain(HostType, Domain) ->
Args = [HostType, Domain],
mongoose_backend:call(HostType, ?MAIN_MODULE, ?FUNCTION_NAME, Args).
22 changes: 21 additions & 1 deletion src/event_pusher/mod_event_pusher_push_mnesia.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
-export([enable/5,
disable/2,
disable/4,
get_publish_services/2]).
get_publish_services/2,
remove_domain/2]).

%%--------------------------------------------------------------------
%% Definitions
Expand Down Expand Up @@ -148,3 +149,22 @@ make_record(UserJID, PubsubJID, Node, Form) ->
-spec key(jid:jid()) -> key().
key(JID) ->
jid:to_lus(JID).

-spec remove_domain(mongooseim:host_type(), jid:lserver()) -> ok.
remove_domain(_HostType, Domain) ->
%% Iterate through all push subscriptions and delete those belonging to the removed domain
%% User JID is stored as {LUser, LServer} tuple, we match on LServer
F = fun() ->
mnesia:foldl(
fun(#push_subscription{user_jid = {_, UserDomain}} = Sub, Acc) ->
case UserDomain of
Domain -> mnesia:delete_object(Sub);
_ -> ok
end,
Acc
end,
ok,
push_subscription)
end,
{atomic, ok} = mnesia:transaction(F),
ok.
15 changes: 14 additions & 1 deletion src/event_pusher/mod_event_pusher_push_rdbms.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
-export([enable/5,
disable/2,
disable/4,
get_publish_services/2]).
get_publish_services/2,
remove_domain/2]).

%%--------------------------------------------------------------------
%% Backend callbacks
Expand Down Expand Up @@ -111,6 +112,10 @@ prepare_queries() ->
[owner_jid, node, pubsub_jid],
<<"DELETE FROM event_pusher_push_subscription "
"WHERE owner_jid = ? AND node = ? AND pubsub_jid = ?">>),
mongoose_rdbms:prepare(event_pusher_push_delete_domain, event_pusher_push_subscription,
[owner_jid],
<<"DELETE FROM event_pusher_push_subscription "
"WHERE owner_jid LIKE ?">>),
ok.

-spec execute_insert(mongooseim:host_type(), jid:literal_jid(), mod_event_pusher_push:pubsub_node(),
Expand Down Expand Up @@ -140,3 +145,11 @@ execute_delete(HostType, OwnerJid, PubSubJid) ->
execute_delete(HostType, OwnerJid, Node, PubSubJid) ->
mongoose_rdbms:execute_successfully(HostType, event_pusher_push_delete_node,
[OwnerJid, Node, PubSubJid]).

-spec remove_domain(mongooseim:host_type(), jid:lserver()) -> ok.
remove_domain(HostType, Domain) ->
%% Match all subscriptions owned by users of the given domain
%% Users are stored as 'user@domain' in owner_jid, so we use LIKE '%@domain'
LikePattern = <<"%@", Domain/binary>>,
mongoose_rdbms:execute_successfully(HostType, event_pusher_push_delete_domain, [LikePattern]),
ok.
6 changes: 5 additions & 1 deletion src/event_pusher/mod_event_pusher_rabbit.erl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
%%%===================================================================

%% MIM module callbacks
-export([start/2, stop/1, hooks/1, config_spec/0]).
-export([start/2, stop/1, hooks/1, config_spec/0, supported_features/0]).

%% hook handlers
-export([push_event/3]).
Expand All @@ -63,6 +63,10 @@ start(HostType, Opts) ->
stop(_HostType) ->
ok.

-spec supported_features() -> [atom()].
supported_features() ->
[dynamic_domains].

-spec hooks(mongooseim:host_type()) -> gen_hook:hook_list().
hooks(HostType) ->
[{push_event, HostType, fun ?MODULE:push_event/3, #{}, 50}].
Expand Down
Loading