-
Notifications
You must be signed in to change notification settings - Fork 428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/xep 357 push notifications #1178
Conversation
apps/ejabberd/src/ejabberd_sm.erl
Outdated
@@ -130,9 +131,9 @@ route(From, To, Packet) -> | |||
case (catch do_route(From, To, Packet)) of | |||
{'EXIT', Reason} -> | |||
?ERROR_MSG("error when routing from=~ts to=~ts in module=~p, reason=~p, packet=~ts, stack_trace=~p", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Elvis:
Line 133 is too long: ?ERROR_MSG("error when routing from=~ts to=~ts in module=~p, reason=~p, packet=~ts, stack_trace=~p",.
@@ -819,7 +820,7 @@ get_user_present_pids(LUser, LServer) -> | |||
|
|||
-spec get_user_present_resources(LUser :: ejabberd:user(), | |||
LServer :: ejabberd:server() | |||
) -> [{priority(), binary()}]. | |||
) -> [{priority(), binary()}]. | |||
get_user_present_resources(LUser, LServer) -> | |||
Ss = ?SM_BACKEND:get_sessions(LUser, LServer), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Elvis:
Don't use macros (like SM_BACKEND on line 825) as module names.
Node :: mod_push:pubsub_node()) -> ok | {error, Reason :: term()}. | ||
disable(User, undefined, undefined) -> | ||
delete(key(User)); | ||
disable(User, undefined, undefined) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Compiler:
Warning: this clause cannot match because a previous clause at line 61 always matches
%%% @end | ||
%%%------------------------------------------------------------------- | ||
-module(mod_push_plugin). | ||
-behavior(mod_push_plugin). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Compiler:
Warning: behaviour mod_push_plugin undefined
da3e73c
to
69b126a
Compare
@@ -819,7 +821,7 @@ get_user_present_pids(LUser, LServer) -> | |||
|
|||
-spec get_user_present_resources(LUser :: ejabberd:user(), | |||
LServer :: ejabberd:server() | |||
) -> [{priority(), binary()}]. | |||
) -> [{priority(), binary()}]. | |||
get_user_present_resources(LUser, LServer) -> | |||
Ss = ?SM_BACKEND:get_sessions(LUser, LServer), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Elvis:
Don't use macros (like SM_BACKEND on line 826) as module names.
69b126a
to
b4e2c1b
Compare
doc/modules/mod_push.md
Outdated
### Module Description | ||
This module implements [XEP-0357: Push Notifications](https://xmpp.org/extensions/xep-0357.html). | ||
It enables a service that notifies `PubSub` of user's choice about every message that he could | ||
miss while being offline. There are two control stanzas that clinet may send to this module: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: clinet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
apps/ejabberd/src/ejabberd_sm.erl
Outdated
do_route_no_resource(<<"broadcast">>, _, From, To, Packet) -> | ||
% Backward compatibility | ||
% Backward compatibility |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indent glitch? :)
apps/ejabberd/src/ejabberd_sm.erl
Outdated
@@ -744,7 +746,7 @@ route_message(From, To, Packet) -> | |||
%% Route messages to all priority that equals the max, if | |||
%% positive | |||
fun({Prio, Pid}) when Prio == Priority -> | |||
% we will lose message if PID is not alive | |||
% we will lose message if PID is not alive |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indent glitch? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... My formatter (emacs) assumes that comments with single '%' have fixed indentation because of reasons. I'm gonna revert all those changes.
apps/ejabberd/src/ejabberd_sm.erl
Outdated
|
||
% Backward compatibility | ||
% Backward compatibility |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indent glitch? :)
apps/ejabberd/src/ejabberd_sm.erl
Outdated
@@ -976,19 +978,19 @@ user_resources(UserStr, ServerStr) -> | |||
sm_backend(Backend) -> | |||
lists:flatten( | |||
["-module(ejabberd_sm_backend). | |||
-export([backend/0]). | |||
-export([backend/0]). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken indent
apps/ejabberd/src/ejabberd_sm.erl
Outdated
_ -> | ||
0 | ||
end. | ||
case mongoose_metrics:get_metric_value(global, ?UNIQUE_COUNT_CACHE) of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken indent.
<<"chat">> -> | ||
jid:to_binary(jid:to_bare(jid:to_lower(From))); | ||
<<"groupchat">> -> | ||
LResource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case LResource
is the message sender. Important information in case of groupchat
notifications is also the room name. How this will be delivered in the push notification?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Room name will be stripped and the user will get only sender JID. If you think it shouldn't, I'll add LUser
to sender_id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it's mandatory to deliver the room name for groupchat notifications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that room's luser
should be included as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done :)
doc/modules/mod_push.md
Outdated
filter messages that shall not be published to `PubSub` node. | ||
|
||
|
||
[aws-virtual-host]: https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear to me why do we need this and following links in this doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a copy-paste error. Removed.
-define(NS_XDATA, <<"jabber:x:data">>). | ||
-define(NS_PUBSUB_PUB_OPTIONS, <<"http://jabber.org/protocol/pubsub#publish-options">>). | ||
-define(PUSH_FORM_TYPE, <<"urn:xmpp:push:summary">>). | ||
-define(MUCHOST, <<"muclight.localhost">>). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should avoid hardcoding the main XMPP domain served by the target server. You can easily read it from tests configuration via:
ct:get_config({hosts, mim, domain})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
-define(PUSH_FORM_TYPE, <<"urn:xmpp:push:summary">>). | ||
-define(MUCHOST, <<"muclight.localhost">>). | ||
|
||
-define(MUC_HOST, <<"muc.localhost">>). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another hardcoded localhost
.
init_per_group(muclight_msg_notifications, Config) -> | ||
Host = ct:get_config({hosts, mim, domain}), | ||
dynamic_modules:start(Host, mod_push, ?PUSH_OPTS), | ||
dynamic_modules:start(<<"localhost">>, mod_muc_light, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded localhost
while one line above domain read from config was used.
apps/ejabberd/src/mod_push.erl
Outdated
start(Host, Opts) -> | ||
?INFO_MSG("mod_push starting on host ~p", [Host]), | ||
|
||
ok = application:ensure_started(worker_pool), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd avoid command that could start worker_pool
here, as it should be done during VM boot. I think it would be better to check for wpool:start_sup_pool
return value to not only verify that worker_pool
is running but also that pool creation was indeed successful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
{group, muclight_msg_notifications} | ||
]. | ||
|
||
groups() -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This set of test cases looks impressive. I have two general comments:
- This sute is not executed on travis as it is not added to
default.spec
- I encourage to run all groups in parallel.
escalus:fresh_story
is your friend here, also you can take a look atsm_SUITE
or any other suite usingfresh_story
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'm gonna try enabling parallel groups.
ok. | ||
|
||
-spec stop(Host :: ejabberd:server()) -> ok. | ||
stop(Host) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lacks worker pool shutdown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
form = Form | ||
}. | ||
|
||
-spec key(ejabberd:jid()) -> key() | no_return(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't have no_return()
, can it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, indeed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, there was explicit throw
in early implementation but its gone now, I just forgot to change spec.
|
||
-record(route, {from, to, packet}). | ||
|
||
-define(assertReceivedMatch(Expect), ?assertReceivedMatch(Expect, 0)). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it used anywhere actually?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, sorry about that.
Server = escalus_client:server(Alice), | ||
escalus:send(Alice, escalus_stanza:disco_info(Server)), | ||
Stanza = escalus:wait_for_stanza(Alice), | ||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason for using these try..catch
es in test cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess for better error readability. I saw something like that in other test suite in disco checks so I thought thats a thing. If its not I'm just gonna remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those checks in other suite were probably implemented when escalus wasn't reporting full stanza log upon error yet. Now there is no need to manually log stanza. Which suite is it BTW?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several try..catch
(11) like that in mam_SUITE
and muc_SUITE
.
Anyway, I'm gonna remove it from here.
end]), | ||
Config. | ||
|
||
-spec rpc(M :: atom(), F :: atom(), A :: [term()]) -> term(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already implemented in https://github.com/esl/escalus/blob/master/src/escalus_ejabberd.erl#L55
Unless it's about the timeout value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No its not, just forgot about that.
Cookie = escalus_ct:get_config(ejabberd_cookie), | ||
escalus_ct:rpc_call(Node, M, F, A, 10000, Cookie). | ||
|
||
create_room(Room, [Owner | Members]) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe using https://github.com/esl/MongooseIM/blob/master/test.disabled/ejabberd_tests/tests/muc_light_SUITE.erl#L271 would be easier, faster and would require less imports?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try this way. Somehow I prefer initialising via XMPP.
start_publish_listener(Config) -> | ||
TestCasePid = self(), | ||
rpc(meck, new, [ejabberd_router, [no_link, passthrough]]), | ||
rpc(meck, expect, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the tampering with ejabberd_router
here. Have you considered declaring e.g. push.localhost
as JID in enable
request and registering CT process as domain handler with register_route
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I just wasn't aware there is such option. I'll try that, thanks.
transaction(F). | ||
|
||
-spec transaction(fun(() -> any())) -> Result :: any(). | ||
transaction(F) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need transactions in case of mod_push
? I believe that conflicts or race conditions won't occur without them and it's always less work for Mnesia. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just reduces the change of race condition with poorly written clients. If no one have an objection I will remove those transactions.
-spec should_publish(From :: ejabberd:jid(), To :: ejabberd:jid(), Packet :: jlib:xmlel()) -> | ||
boolean(). | ||
should_publish(_From, To = #jid{luser = LUser, lserver = LServer}, _Packet) -> | ||
?WARNING_MSG("should_publish ~p", [{LUser, LServer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Elvis:
Missing space right "," on line 53
should_publish(_From, To = #jid{luser = LUser, lserver = LServer}, _Packet) -> | ||
?WARNING_MSG("should_publish ~p", [{LUser, LServer, | ||
ejabberd_users:does_user_exist(LUser, LServer), | ||
catch lists:max(ejabberd_sm:get_user_present_pids(LUser, LServer))}]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Elvis:
Line 55 is too long: catch lists:max(ejabberd_sm:get_user_present_pids(LUser, LServer))}]),
.
%%% @end | ||
%%%------------------------------------------------------------------- | ||
-module(mod_push_plugin). | ||
-behavior(mod_push_plugin). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Compiler:
Warning: behaviour mod_push_plugin undefined
76f5a03
to
3791c48
Compare
3791c48
to
a34a6ea
Compare
Thanks! |
This PR features XEP-0357 implementation. All needed informations can be found in
mod_push.md
. Right now only PM and MUCLight messages are supported.Also pleas note that this code requires a custom PubSub node that will handle notifications from this module and pass them to external Push Notifications Service.
Tis PR also adds
worker_pool
as pooler used inmod_push
. This pooler is faster and more configurable than others likepoolboy
. There are several pending PRs that use this pooler, so maybe someday we are gonna switch fully toworker_pool
.