Skip to content
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/amazon sns support #1149

Merged
merged 18 commits into from
Feb 16, 2017
Merged

Feature/amazon sns support #1149

merged 18 commits into from
Feb 16, 2017

Conversation

rslota
Copy link
Contributor

@rslota rslota commented Jan 12, 2017

This PR introduces Amazon SNS support for message and users' presence change notifications.

-module(mod_aws_sns_defaults).
-author("Rafal Slota").

-behavior(mod_aws_sns).

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_aws_sns undefined

@rslota rslota force-pushed the feature/amazon_sns_support branch from f5fc1f7 to ca6a208 Compare January 12, 2017 12:42
-module(mod_aws_sns).
-author("Rafal Slota").

-behavior(gen_mod).

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 gen_mod undefined

@rslota rslota force-pushed the feature/amazon_sns_support branch 2 times, most recently from de7db75 to 4beb9da Compare January 12, 2017 13:36
%% @doc Returns AWS SNS handle base on configured AWS credentials
-spec aws_handle(Host :: ejabberd:lserver()) -> erlcloud:sns_handle().
aws_handle(Host) ->
AccessKeyId = [_ | _] = opt(Host, access_key_id),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it checked here if the access_key_id is a list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gen_mod's API doesn't crash with exception when we ask for the module option that is required. This is to ensure this option is set and to crash when it doesn't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't mind that check, I'll leave it here while adding a comment to make it clear :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to validate it on every push to AWS? Can we move the validation to module's start and crash when the option doesn't validate? This will get feedback to the devops that sth is misconfigured earlier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done.

escalus:end_per_suite(Config).

init_per_group(_, Config) ->
dynamic_modules:start(<<"localhost">>, mod_aws_sns, ?SNS_OPTS),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The domain in big tests shouldn't be hardcoded. This is configurable and can be read like adhoc_SUITE:58

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, done.

@rslota rslota force-pushed the feature/amazon_sns_support branch from cf11ee1 to e5b28a4 Compare January 13, 2017 08:34
%% Tests

handles_unicode_messages(Config) ->
expect_message_entry(<<"message">>, <<"❤☀☆☂☻♞☯☭☢€"/utf8>>),

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 39

%% Tests

handles_unicode_messages(Config) ->
expect_message_entry(<<"message">>, <<"❤☀☆☂☻♞☯☭☢€"/utf8>>),

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 42


-define(assertReceivedMatch(Expect), ?assertReceivedMatch(Expect, 0)).

-define(assertReceivedMatch(Expect, Timeout),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Invalid macro name assertReceivedMatch on line 36. Use UPPER_CASE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this as well.

config
}).

-define(assertReceivedMatch(Expect), ?assertReceivedMatch(Expect, 0)).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Invalid macro name assertReceivedMatch on line 34. Use UPPER_CASE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can Elvis config be change to accept such macro names in tests only?

@rslota rslota force-pushed the feature/amazon_sns_support branch 3 times, most recently from 5dfb4e8 to f2def99 Compare January 17, 2017 11:21
ejabberd_hooks:add(user_available_hook, Host, ?MODULE, user_present, 90),
ejabberd_hooks:add(unset_presence_hook, Host, ?MODULE, user_not_present, 90),

application:ensure_all_started(erlcloud),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this here? Can we run erlcloud app while starting the node?

Copy link
Contributor Author

@rslota rslota Jan 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When on start? Our reltool.config does not start applications listed by configure script. Anyway, theres just no need for loading all those apps until this module is started.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I forgot about the configure script.

user_send_packet(From = #jid{lserver = Host}, To, Packet) ->
?DEBUG("SNS Packet handle~n from ~p ~n to ~p~n packet ~p.", [From, To, Packet]),

case {get_topic(Host, Packet), xml:get_subtag(Packet, <<"body">>)} of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly encourage use of exml_query module instead of xml. Especially in new code.

FromGUID = user_guid(Host, From),
ToGUID = user_guid(Host, To),

MessageBody = xml:get_tag_cdata(BodyTag),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one can also be replaced with an equivalent from exml_query.

%% @doc Returns message type
-spec message_type(Packet :: jlib:xmlel()) -> pm | muc | undefined.
message_type(Packet) ->
case xml:get_tag_attr_s(<<"type">>, Packet) of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another candidate to replace with exml_query.

config
}).

-define(assertReceivedMatch(Expect), ?assertReceivedMatch(Expect, 0)).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can Elvis config be change to accept such macro names in tests only?


-define(assertReceivedMatch(Expect), ?assertReceivedMatch(Expect, 0)).

-define(assertReceivedMatch(Expect, Timeout),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this as well.

@mentels
Copy link

mentels commented Jan 17, 2017

@rslota @kzemek when I'm running "big tests" I'm getting the following error:

[error] <0.12290.0>@ejabberd_hooks:run1:241 {{sns_error,"InvalidClientTokenId","The security token included in the request is invalid."},[{erlcloud_sns,sns_xml_request,3,[{file,"src/erlcloud_sns.erl"},{line,649}]},{erlcloud_sns,publish,6,[{file,"src/erlcloud_sns.erl"},{line,452}]},{mod_aws_sns,user_presence_changed,2,[{file,"src/mod_aws_sns.erl"},{line,155}]},{safely,apply,3,[{file,"src/safely.erl"},{line,19}]},{ejabberd_hooks,run1,3,[{file,"src/ejabberd_hooks.erl"},{line,237}]},{ejabberd_c2s,presence_update,3,[{file,"src/ejabberd_c2s.erl"},{line,1862}]},{ejabberd_c2s,process_outgoing_stanza,2,[{file,"src/ejabberd_c2s.erl"},{line,960}]},{p1_fsm_old,handle_msg,10,[{file,"src/p1_fsm_old.erl"},{line,576}]}]}
    Running hook: {user_available_hook,[{jid,<<"bOb">>,<<"localhost">>,<<"res1">>,<<"bob">>,<<"localhost">>,<<"res1">>}]}
    Callback: mod_aws_sns:user_present

It looks like the credentials are incorrect.

@rslota rslota force-pushed the feature/amazon_sns_support branch from ba74a4c to c71ddb2 Compare January 17, 2017 16:12
@mentels
Copy link

mentels commented Jan 18, 2017

As the publishing to Amazon SNS is synchronous, if the ercloud_sns:publish/X fails, then the whole C2S process fails. I suggest using the catch to prevent that and log the error without crashing:

publish(Host, TopicARN, Content, Attributes) ->
    EncodedContent = jiffy:encode(Content),
    case (catch erlcloud_sns:publish(topic,
                                     TopicARN,
                                     unicode:characters_to_list(EncodedContent),
                                     undefined,
                                     maps:to_list(Attributes),
                                     aws_handle(Host))) of
        {'EXIT', Error} ->
            ?ERROR_MSG("Failed publishing to Amazon SNS: ~p", [Error]);
        MessageId ->
            MessageId
    end.

I believe that the end goal will be to make a pool of connections for that. How that sounds for you?

@kzemek
Copy link
Contributor

kzemek commented Jan 18, 2017

@mentels

As the publishing to Amazon SNS is synchronous, if the ercloud_sns:publish/X fails, then the whole C2S process fails.

Hooks are already ran with catch (in ejabberd_hooks via safely module) and in case of failure they are skipped. I agree that a pool is needed as an end goal because talking with SNS can slow down message processing, though.

@mentels
Copy link

mentels commented Jan 18, 2017

@kzemek cool. I didn't know that, thanks.

@mentels
Copy link

mentels commented Jan 18, 2017

@kzemek when I'm running the big tests I'm getting this error:

=== Ended at 2017-01-18 13:15:35
=== Location: [{escalus_new_assert,assert_true,84},
              {escalus_story,'-drop_presences/2-lc$^0/1-0-',144},
              {escalus_story,drop_presences,144},
              {escalus_story,'-start_ready_clients/2-fun-0-',97},
              {lists,foldl,1262},
              {escalus_story,start_ready_clients,90},
              {lists,flatmap,1249},
              {lists,flatmap,1249}]
=== Reason: {assertion_failed,assert,is_presence,
                     {xmlel,<<"message">>,
                         [{<<"from">>,<<"bOb@localhost/res1">>},
                          {<<"to">>,<<"alicE@localhost/res1">>},
                          {<<"xml:lang">>,<<"en">>},
                          {<<"type">>,<<"chat">>}],
                         [{xmlel,<<"body">>,[],
                              [{xmlcdata,<<"How are you?">>}]},
                          {xmlel,<<"delay">>,
                              [{<<"xmlns">>,<<"urn:xmpp:delay">>},
                               {<<"from">>,<<"localhost">>},
                               {<<"stamp">>,
                                <<"2017-01-18T12:15:32.976994Z">>}],
                              [{xmlcdata,<<"Offline Storage">>}]}]},
                     "<message from='bOb@localhost/res1' to='alicE@localhost/res1' xml:lang='en' type='chat'><body>How are you?</body><delay xmlns='urn:xmpp:delay' from='localhost' stamp='2017-01-18T12:15:32.976994Z'>Offline Storage</delay></message>"}
  in function  escalus_new_assert:assert_true/2 (src/escalus_new_assert.erl, line 84)
  in call from escalus_story:'-drop_presences/2-lc$^0/1-0-'/1 (src/escalus_story.erl, line 144)
  in call from escalus_story:drop_presences/2 (src/escalus_story.erl, line 144)
  in call from escalus_story:'-start_ready_clients/2-fun-0-'/3 (src/escalus_story.erl, line 97)
  in call from lists:foldl/3 (lists.erl, line 1262)
  in call from escalus_story:start_ready_clients/2 (src/escalus_story.erl, line 90)
  in call from lists:flatmap/2 (lists.erl, line 1249)
  in call from lists:flatmap/2 (lists.erl, line 1249)

I'll look into it after lunch but maybe you have a clue straight away.

@mentels
Copy link

mentels commented Jan 18, 2017

And the config was:

=== Test case: mod_aws_sns_SUITE:muc_messages/1 (click for source code)

=== Config value:

    [{sns_config,[{access_key_id,"AKIAIH54ALYGMZTESTID"},
                  {secret_access_key,"buRqHOxXCFUQkiuYgdUAy+XoGKt0Ec6DTESTKEY+"},
                  {region,"eu-west-1"},
                  {account_id,"123456789012"},
                  {sns_host,"sns.eu-west-1.amazonaws.com"},
                  {plugin_module,mod_aws_sns_defaults},
                  {presence_updates_topic,"user_presence_updated-dev-1"},
                  {pm_messages_topic,"user_message_sent-dev-1"},
                  {muc_messages_topic,"user_messagegroup_sent-dev-1"},
                  {muc_host,"muc.@HOST@"}]},
     {watchdog,<0.1945.0>},
     {preset,undefined},
     {tc_logfile,"/Users/szymonmentel/dev/faceit/sns/faceit_mim/test/ejabberd_tests/ct_report/ct_run.test@szm-mac.2017-01-18_13.15.24/ejabberd_tests.tests.mod_aws_sns_SUITE.logs/run.2017-01-18_13.15.26/mod_aws_sns_suite.muc_messages.html"},
     {tc_group_properties,[{name,message_publish}]},
     {tc_group_path,[]},
     {data_dir,"/Users/szymonmentel/dev/faceit/sns/faceit_mim/test/ejabberd_tests/tests/mod_aws_sns_SUITE_data/"},
     {priv_dir,"/Users/szymonmentel/dev/faceit/sns/faceit_mim/test/ejabberd_tests/ct_report/ct_run.test@szm-mac.2017-01-18_13.15.24/ejabberd_tests.tests.mod_aws_sns_SUITE.logs/run.2017-01-18_13.15.26/log_private/"},
     {escalus_users,[{bob,[{username,<<"bOb">>},
                           {server,<<"localhost">>},
                           {password,<<"makrolika">>}]},
                     {alice,[{username,<<"alicE">>},
                             {server,<<"localhost">>},
                             {password,<<"matygrysa">>}]}]}]

@rslota rslota force-pushed the feature/amazon_sns_support branch 3 times, most recently from 86407ad to ce7fc5c Compare January 20, 2017 13:54
@rslota rslota added ready and removed to-discuss labels Jan 24, 2017
@kzemek kzemek closed this Feb 6, 2017
@kzemek kzemek reopened this Feb 6, 2017
@rslota rslota force-pushed the feature/amazon_sns_support branch from 18046e5 to 31706ca Compare February 14, 2017 13:02
%% Tests

handles_unicode_messages(Config) ->
expect_message_entry(<<"message">>, <<"❤☀☆☂☻♞☯☭☢€"/utf8>>),

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 42

%% Tests

handles_unicode_messages(Config) ->
expect_message_entry(<<"message">>, <<"❤☀☆☂☻♞☯☭☢€"/utf8>>),

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 42

@michalwski
Copy link
Contributor

All right, I'm merging this.
@bartekgorny your general remark is valid, thanks for that. The implementation most likely end up in such a shape when there is a need for that. Currently this is the only place where MongooseIM talks to SNS.

@michalwski michalwski merged commit 04c4e4d into master Feb 16, 2017
@michalwski michalwski deleted the feature/amazon_sns_support branch February 16, 2017 14:54
@michalwski michalwski restored the feature/amazon_sns_support branch February 17, 2017 07:24
@michalwski michalwski deleted the feature/amazon_sns_support branch February 17, 2017 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants