Current section

Files

Jump to
nextroll_erlcloud src erlcloud_sns.erl
Raw

src/erlcloud_sns.erl

%%% Amazon SNS.
%%% Events are parsed according to http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.html
%%% TODO add all the missing functions for the different actions
-module(erlcloud_sns).
-author('elbrujohalcon@inaka.net').
-export([set_sns_host/1,
add_permission/3, add_permission/4,
create_platform_endpoint/2, create_platform_endpoint/3,
create_platform_endpoint/4, create_platform_endpoint/5,
create_platform_endpoint/6,
create_topic/1, create_topic/2,
delete_endpoint/1, delete_endpoint/2, delete_endpoint/3,
delete_topic/1, delete_topic/2,
list_topics/0, list_topics/1, list_topics/2,
list_topics_all/0, list_topics_all/1,
list_subscriptions/0,
list_subscriptions/1,
list_subscriptions/2,
list_subscriptions_all/0,
list_subscriptions_all/1,
list_subscriptions_by_topic/1,
list_subscriptions_by_topic/2,
list_subscriptions_by_topic/3,
list_subscriptions_by_topic_all/1,
list_subscriptions_by_topic_all/2,
list_endpoints_by_platform_application/1,
list_endpoints_by_platform_application/2,
list_endpoints_by_platform_application/3,
list_endpoints_by_platform_application/4,
get_endpoint_attributes/1,
get_endpoint_attributes/2,
get_endpoint_attributes/3,
set_endpoint_attributes/2,
set_endpoint_attributes/3,
publish_to_topic/2, publish_to_topic/3, publish_to_topic/4,
publish_to_topic/5, publish_to_target/2, publish_to_target/3,
publish_to_target/4, publish_to_target/5, publish_to_phone/2,
publish_to_phone/3, publish_to_phone/4, publish/5, publish/6,
list_platform_applications/0, list_platform_applications/1,
list_platform_applications/2, list_platform_applications/3,
confirm_subscription/1, confirm_subscription/2, confirm_subscription/3,
confirm_subscription2/2, confirm_subscription2/3, confirm_subscription2/4,
set_topic_attributes/3, set_topic_attributes/4,
get_topic_attributes/1, get_topic_attributes/2,
set_subscription_attributes/3, set_subscription_attributes/4,
get_subscription_attributes/1, get_subscription_attributes/2,
subscribe/3, subscribe/4,
unsubscribe/1, unsubscribe/2
]).
-export([parse_event/1, get_event_type/1, parse_event_message/1,
get_notification_attribute/2]).
-export([new/2, new/3, configure/2, configure/3]).
-include("erlcloud.hrl").
-include("erlcloud_aws.hrl").
-define(API_VERSION, "2010-03-31").
-opaque sns_event() :: jsx:json_term().
-opaque sns_notification() :: sns_message().
-type sns_event_type() :: subscription_confirmation | notification.
-export_type([sns_event/0, sns_event_type/0, sns_notification/0]).
-type sns_endpoint_attribute() :: custom_user_data
| enabled
| token.
-type sns_message_attributes() :: [{string(), string() | binary() | number()}].
-type sns_endpoint() :: [{arn, string()} | {attributes, [{arn|sns_endpoint_attribute(), string()}]}].
-type sns_permission() :: all
| add_permission
| confirm_subscription
| create_platform_application
| create_platform_endpoint
| create_topic
| delete_endpoint
| delete_platform_application
| delete_topic
| get_endpoint_attributes
| get_platform_application_attributes
| get_subscription_attributes
| get_topic_attributes
| list_endpoints_by_platform_application
| list_platform_applications
| list_subscriptions
| list_subscriptions_by_topic
| list_topics
| publish
| remove_permission
| set_endpoint_attributes
| set_platform_application_attributes
| set_subscription_attributes
| set_topic_attributes
| subscribe
| unsubscribe.
-type sns_acl() :: [{string(), sns_permission()}].
-type sns_message() :: string() | jsx:json_term().
-type sns_application_attribute() :: event_endpoint_created
| event_endpoint_deleted
| event_endpoint_updated
| event_delivery_failure.
-type sns_application() :: [{arn, string()} | {attributes, [{arn|sns_application_attribute(), string()}]}].
-type(sns_topic_attribute_name () :: 'Policy' | 'DisplayName' | 'DeliveryPolicy').
-type(sns_subscription_attribute_name () :: 'DeliveryPolicy' | 'RawMessageDelivery' | 'FilterPolicy').
-type(sns_subscribe_protocol_type () :: http | https | email | 'email-json' | sms | sqs | application).
-export_type([sns_acl/0, sns_endpoint_attribute/0, sns_message_attributes/0,
sns_message/0, sns_application/0, sns_endpoint/0]).
-spec add_permission(string(), string(), sns_acl()) -> ok | no_return().
add_permission(TopicArn, Label, Permissions) ->
add_permission(TopicArn, Label, Permissions, default_config()).
-spec add_permission(string(), string(), sns_acl(), aws_config()) -> ok | no_return().
add_permission(TopicArn, Label, Permissions, Config)
when is_list(TopicArn),
is_list(Label), length(Label) =< 80,
is_list(Permissions) ->
sns_simple_request(Config, "AddPermission",
[{"Label", Label}, {"TopicArn", TopicArn}
| erlcloud_aws:param_list(
encode_permissions(Permissions),
{"AWSAccountId.member", "ActionName.member"})]).
-spec create_platform_endpoint(string(), string()) -> string() | no_return().
create_platform_endpoint(PlatformApplicationArn, Token) ->
create_platform_endpoint(PlatformApplicationArn, Token, "").
-spec create_platform_endpoint(string(), string(), string()) -> string() | no_return().
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData) ->
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, []).
-spec create_platform_endpoint(string(), string(), string(), [{sns_endpoint_attribute(), string()}]) -> string() | no_return().
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, Attributes) ->
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, Attributes, default_config()).
-spec create_platform_endpoint(string(), string(), string(), [{sns_endpoint_attribute(), string()}], aws_config()) -> string() | no_return().
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, Attributes, Config) ->
Doc =
sns_xml_request(
Config, "CreatePlatformEndpoint",
[{"PlatformApplicationArn", PlatformApplicationArn},
{"Token", Token},
{"CustomUserData", CustomUserData}
| encode_attributes(Attributes)
]),
erlcloud_xml:get_text(
"CreatePlatformEndpointResult/EndpointArn", Doc).
-spec create_platform_endpoint(string(), string(), string(), [{sns_endpoint_attribute(), string()}], string(), string()) -> string() | no_return().
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, Attributes, AccessKeyID, SecretAccessKey) ->
create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, Attributes, new_config(AccessKeyID, SecretAccessKey)).
-spec create_topic(string()) -> string() | no_return().
create_topic(TopicName) ->
create_topic(TopicName, default_config()).
-spec create_topic(string(), aws_config()) -> string() | no_return().
create_topic(TopicName, Config)
when is_record(Config, aws_config) ->
Doc = sns_xml_request(Config, "CreateTopic", [{"Name", TopicName}]),
erlcloud_xml:get_text("/CreateTopicResponse/CreateTopicResult/TopicArn", Doc).
-spec confirm_subscription(sns_event()) -> string() | no_return().
confirm_subscription(SnsEvent) ->
confirm_subscription(SnsEvent, default_config()).
-spec confirm_subscription(sns_event(), aws_config()) -> string() | no_return().
confirm_subscription(SnsEvent, Config) ->
Token = binary_to_list(proplists:get_value(<<"Token">>, SnsEvent, <<>>)),
TopicArn = binary_to_list(proplists:get_value(<<"TopicArn">>, SnsEvent, <<>>)),
confirm_subscription2(Token, TopicArn, Config).
-spec confirm_subscription(sns_event(), string(), string()) -> string() | no_return().
confirm_subscription(SnsEvent, AccessKeyID, SecretAccessKey) ->
confirm_subscription(SnsEvent, new_config(AccessKeyID, SecretAccessKey)).
-spec confirm_subscription2(string(), string()) -> string() | no_return().
confirm_subscription2(Token, TopicArn) ->
confirm_subscription2(Token, TopicArn, default_config()).
-spec confirm_subscription2(string(), string(), aws_config()) -> string() | no_return().
confirm_subscription2(Token, TopicArn, Config) ->
Doc =
sns_xml_request(
Config, "ConfirmSubscription",
[{"Token", Token},
{"TopicArn", TopicArn}
]),
erlcloud_xml:get_text(
"ConfirmSubscriptionResult/SubscriptionArn", Doc).
-spec confirm_subscription2(string(), string(), string(), string()) -> string() | no_return().
confirm_subscription2(Token, TopicArn, AccessKeyID, SecretAccessKey) ->
confirm_subscription2(Token, TopicArn, new_config(AccessKeyID, SecretAccessKey)).
-spec delete_endpoint(string()) -> ok | no_return().
delete_endpoint(EndpointArn) ->
delete_endpoint(EndpointArn, default_config()).
-spec delete_endpoint(string(), aws_config()) -> ok | no_return().
delete_endpoint(EndpointArn, Config) ->
sns_simple_request(Config, "DeleteEndpoint", [{"EndpointArn", EndpointArn}]).
-spec delete_endpoint(string(), string(), string()) -> ok | no_return().
delete_endpoint(EndpointArn, AccessKeyID, SecretAccessKey) ->
delete_endpoint(EndpointArn, new_config(AccessKeyID, SecretAccessKey)).
-spec delete_topic(string()) -> ok | no_return().
delete_topic(TopicArn) ->
delete_topic(TopicArn, default_config()).
-spec delete_topic(string(), aws_config()) -> ok | no_return().
delete_topic(TopicArn, Config)
when is_record(Config, aws_config) ->
sns_simple_request(Config, "DeleteTopic", [{"TopicArn", TopicArn}]).
-spec get_endpoint_attributes(string()) -> sns_endpoint() | no_return().
get_endpoint_attributes(EndpointArn) ->
get_endpoint_attributes(EndpointArn, default_config()).
-spec get_endpoint_attributes(string(), aws_config()) -> sns_endpoint() | no_return().
get_endpoint_attributes(EndpointArn, Config) ->
Params = [{"EndpointArn", EndpointArn}],
Doc = sns_xml_request(Config, "GetEndpointAttributes", Params),
Decoded =
erlcloud_xml:decode(
[{attributes, "GetEndpointAttributesResult/Attributes/entry",
fun extract_attribute/1
}],
Doc),
[{arn, EndpointArn} | Decoded].
-spec get_endpoint_attributes(string(), string(), string()) -> sns_endpoint() | no_return().
get_endpoint_attributes(EndpointArn, AccessKeyID, SecretAccessKey) ->
get_endpoint_attributes(EndpointArn, new_config(AccessKeyID, SecretAccessKey)).
-spec set_endpoint_attributes(string(), [{sns_endpoint_attribute(), string()}]) -> string() | no_return().
set_endpoint_attributes(EndpointArn, Attributes) ->
set_endpoint_attributes(EndpointArn, Attributes, default_config()).
-spec set_endpoint_attributes(string(), [{sns_endpoint_attribute(), string()}], aws_config()) -> string() | no_return().
set_endpoint_attributes(EndpointArn, Attributes, Config) ->
Doc = sns_xml_request(Config, "SetEndpointAttributes", [{"EndpointArn", EndpointArn} |
encode_attributes(Attributes)]),
erlcloud_xml:get_text("ResponseMetadata/RequestId", Doc).
-spec list_endpoints_by_platform_application(string()) -> [{endpoints, [sns_endpoint()]} | {next_token, string()}] | no_return().
list_endpoints_by_platform_application(PlatformApplicationArn) ->
list_endpoints_by_platform_application(PlatformApplicationArn, undefined).
-spec list_endpoints_by_platform_application(string(), undefined|string()) -> [{endpoints, [sns_endpoint()]} | {next_token, string()}] | no_return().
list_endpoints_by_platform_application(PlatformApplicationArn, NextToken) ->
list_endpoints_by_platform_application(PlatformApplicationArn, NextToken, default_config()).
-spec list_endpoints_by_platform_application(string(), undefined|string(), aws_config()) -> [{endpoints, [sns_endpoint()]} | {next_token, string()}] | no_return().
list_endpoints_by_platform_application(PlatformApplicationArn, NextToken, Config) ->
Params =
case NextToken of
undefined -> [{"PlatformApplicationArn", PlatformApplicationArn}];
NextToken -> [{"PlatformApplicationArn", PlatformApplicationArn}, {"NextToken", NextToken}]
end,
Doc = sns_xml_request(Config, "ListEndpointsByPlatformApplication", Params),
Decoded =
erlcloud_xml:decode(
[{endpoints, "ListEndpointsByPlatformApplicationResult/Endpoints/member",
fun extract_endpoint/1
},
{next_token, "ListEndpointsByPlatformApplicationResult/NextToken", text}],
Doc),
Decoded.
-spec list_endpoints_by_platform_application(string(), undefined|string(), string(), string()) -> [{endpoints, [sns_endpoint()]} | {next_token, string()}] | no_return().
list_endpoints_by_platform_application(PlatformApplicationArn, NextToken, AccessKeyID, SecretAccessKey) ->
list_endpoints_by_platform_application(PlatformApplicationArn, NextToken, new_config(AccessKeyID, SecretAccessKey)).
-spec list_topics() -> [{topics, [[{arn, string()}]]} | {next_token, string()}] | no_return().
list_topics() ->
list_topics(default_config()).
-spec list_topics(undefined | string() | aws_config()) -> [{topics, [[{arn, string()}]]} | {next_token, string()}] | no_return().
list_topics(Config) when is_record(Config, aws_config) ->
list_topics(undefined, Config);
list_topics(NextToken) ->
list_topics(NextToken, default_config()).
-spec list_topics(undefined | string(), aws_config()) -> [{topics, [[{arn, string()}]]} | {next_token, string()}] | no_return().
list_topics(NextToken, Config) ->
Params =
case NextToken of
undefined -> [];
NextToken -> [{"NextToken", NextToken}]
end,
Doc = sns_xml_request(Config, "ListTopics", Params),
Decoded =
erlcloud_xml:decode(
[{topics, "ListTopicsResult/Topics/member",
fun extract_topic_arn/1
},
{next_token, "ListTopicsResult/NextToken", text}],
Doc),
Decoded.
-spec list_topics_all() -> [[{arn, string()}]] | no_return().
list_topics_all() ->
list_topics_all(default_config()).
-spec list_topics_all(aws_config()) -> [[{arn, string()}]] | no_return().
list_topics_all(Config) ->
list_all(fun list_topics/2, topics, Config, undefined, []).
-spec list_subscriptions() -> proplist().
list_subscriptions() ->
list_subscriptions(default_config()).
-spec list_subscriptions(string() | aws_config()) -> proplist().
list_subscriptions(Config) when is_record(Config, aws_config) ->
list_subscriptions(undefined, Config);
list_subscriptions(NextToken) when is_list(NextToken) ->
list_subscriptions(NextToken, default_config()).
-spec list_subscriptions(undefined | string(), aws_config()) -> proplist().
list_subscriptions(NextToken, Config) when is_record(Config, aws_config) ->
Params =
case NextToken of
undefined -> [];
NextToken -> [{"NextToken", NextToken}]
end,
Doc = sns_xml_request(Config, "ListSubscriptions", Params),
Decoded =
erlcloud_xml:decode(
[{subscriptions, "ListSubscriptionsResult/Subscriptions/member",
fun extract_subscription/1
},
{next_token, "ListSubscriptionsResult/NextToken", text}],
Doc),
Decoded.
-spec list_subscriptions_all() -> proplist().
list_subscriptions_all() ->
list_subscriptions_all(default_config()).
-spec list_subscriptions_all(aws_config()) -> proplist().
list_subscriptions_all(Config) ->
list_all(fun (Token, Cfg) ->
list_subscriptions(Token, Cfg) end,
subscriptions, Config, undefined, []).
-spec list_subscriptions_by_topic(string()) -> proplist() | no_return().
list_subscriptions_by_topic(TopicArn) when is_list(TopicArn) ->
list_subscriptions_by_topic(TopicArn, default_config()).
-spec list_subscriptions_by_topic(string(), string() | aws_config()) -> proplist() | no_return().
list_subscriptions_by_topic(TopicArn, Config) when is_record(Config, aws_config) ->
list_subscriptions_by_topic(TopicArn, undefined, Config);
list_subscriptions_by_topic(TopicArn, NextToken) when is_list(NextToken) ->
list_subscriptions_by_topic(TopicArn, NextToken, default_config()).
-spec list_subscriptions_by_topic(string(), undefined | string(), aws_config()) -> proplist() | no_return().
list_subscriptions_by_topic(TopicArn, NextToken, Config) when is_record(Config, aws_config) ->
Params =
case NextToken of
undefined -> [];
NextToken -> [{"NextToken", NextToken}]
end,
Doc = sns_xml_request(Config, "ListSubscriptionsByTopic", [{"TopicArn", TopicArn}| Params]),
Decoded =
erlcloud_xml:decode(
[{subscriptions, "ListSubscriptionsByTopicResult/Subscriptions/member",
fun extract_subscription/1
},
{next_token, "ListSubscriptionsByTopicResult/NextToken", text}],
Doc),
Decoded.
-spec list_subscriptions_by_topic_all(string()) -> proplist() | no_return().
list_subscriptions_by_topic_all(TopicArn) ->
list_subscriptions_by_topic_all(TopicArn, default_config()).
-spec list_subscriptions_by_topic_all(string(), aws_config()) -> proplist() | no_return().
list_subscriptions_by_topic_all(TopicArn, Config) ->
list_all(fun (Token, Cfg) ->
list_subscriptions_by_topic(TopicArn, Token, Cfg) end,
subscriptions, Config, undefined, []).
-spec list_platform_applications() -> [sns_application()] | no_return().
list_platform_applications() ->
list_platform_applications(undefined).
-spec list_platform_applications(undefined|string()) -> [sns_application()] | no_return().
list_platform_applications(NextToken) ->
list_platform_applications(NextToken, default_config()).
-spec list_platform_applications(undefined|string(), aws_config()) -> [sns_application()] | no_return().
list_platform_applications(NextToken, Config) ->
Params =
case NextToken of
undefined -> [];
NextToken -> [{"NextToken", NextToken}]
end,
Doc = sns_xml_request(Config, "ListPlatformApplications", Params),
Decoded =
erlcloud_xml:decode(
[{applications, "ListPlatformApplicationsResult/PlatformApplications/member",
fun extract_application/1
}],
Doc),
proplists:get_value(applications, Decoded, []).
-spec list_platform_applications(undefined|string(), string(), string()) -> [sns_application()] | no_return().
list_platform_applications(NextToken, AccessKeyID, SecretAccessKey) ->
list_platform_applications(NextToken, new_config(AccessKeyID, SecretAccessKey)).
-spec publish_to_topic(string(), sns_message()) -> string() | no_return().
publish_to_topic(TopicArn, Message) ->
publish_to_topic(TopicArn, Message, undefined).
-spec publish_to_topic(string(), sns_message(), undefined|string()) -> string() | no_return().
publish_to_topic(TopicArn, Message, Subject) ->
publish_to_topic(TopicArn, Message, Subject, default_config()).
-spec publish_to_topic(string(), sns_message(), undefined|string(), aws_config()) -> string() | no_return().
publish_to_topic(TopicArn, Message, Subject, Config) ->
publish(topic, TopicArn, Message, Subject, Config).
-spec publish_to_topic(string(), sns_message(), undefined|string(), string(), string()) -> string() | no_return().
publish_to_topic(TopicArn, Message, Subject, AccessKeyID, SecretAccessKey) ->
publish_to_topic(TopicArn, Message, Subject, new_config(AccessKeyID, SecretAccessKey)).
-spec publish_to_target(string(), sns_message()) -> string() | no_return().
publish_to_target(TargetArn, Message) ->
publish_to_target(TargetArn, Message, undefined).
-spec publish_to_target(string(), sns_message(), undefined|string()) -> string() | no_return().
publish_to_target(TargetArn, Message, Subject) ->
publish_to_target(TargetArn, Message, Subject, default_config()).
-spec publish_to_target(string(), sns_message(), undefined|string(), aws_config()) -> string() | no_return().
publish_to_target(TargetArn, Message, Subject, Config) ->
publish(target, TargetArn, Message, Subject, Config).
-spec publish_to_target(string(), sns_message(), undefined|string(), string(), string()) -> string() | no_return().
publish_to_target(TargetArn, Message, Subject, AccessKeyID, SecretAccessKey) ->
publish_to_target(TargetArn, Message, Subject, new_config(AccessKeyID, SecretAccessKey)).
%% TargetArn can be a phone number string, e.g. "+55 (11) 9999-7777"
-spec publish_to_phone(string(), sns_message()) -> string() | no_return().
publish_to_phone(TargetArn, Message) ->
publish_to_phone(TargetArn, Message, default_config()).
-spec publish_to_phone(string(), sns_message(), aws_config()) -> string() | no_return().
publish_to_phone(TargetArn, Message, Config) ->
publish(phone, TargetArn, Message, undefined, Config).
-spec publish_to_phone(string(), sns_message(), string(), string()) -> string() | no_return().
publish_to_phone(TargetArn, Message, AccessKeyID, SecretAccessKey) ->
publish(phone, TargetArn, Message, undefined, new_config(AccessKeyID, SecretAccessKey)).
%% @doc
%% Publish API:
%% [http://docs.aws.amazon.com/sns/latest/api/API_Publish.html]
-spec publish(topic|target|phone, string(), sns_message(), undefined|string(), aws_config()) -> string() | no_return().
publish(Type, RecipientArn, Message, Subject, Config) ->
publish(Type, RecipientArn, Message, Subject, [], Config).
-spec publish(topic|target|phone, string(), sns_message(), undefined|string(), sns_message_attributes(), aws_config()) -> string() | no_return().
publish(Type, RecipientArn, Message, Subject, Attributes, Config) ->
RecipientParam =
case Type of
topic -> [{"TopicArn", RecipientArn}];
target -> [{"TargetArn", RecipientArn}];
phone -> [{"PhoneNumber", RecipientArn}]
end,
MessageParams =
case Message of
[{_,_} |_] ->
EncodedMessage = jsx:encode(Message),
[{"Message", EncodedMessage},
{"MessageStructure", "json"}];
Message ->
[{"Message", Message}]
end,
SubjectParam =
case Subject of
undefined -> [];
Subject -> [{"Subject", Subject}]
end,
AttributesParam = message_attributes(Attributes),
Doc =
sns_xml_request(
Config, "Publish",
RecipientParam ++ MessageParams ++ SubjectParam ++ AttributesParam),
erlcloud_xml:get_text(
"PublishResult/MessageId", Doc).
-spec parse_event(iodata()) -> sns_event().
parse_event(EventSource) ->
jsx:decode(EventSource, [{return_maps, false}]).
-spec get_event_type(sns_event()) -> sns_event_type().
get_event_type(Event) ->
case proplists:get_value(<<"Type">>, Event) of
<<"SubscriptionConfirmation">> -> subscription_confirmation;
<<"Notification">> -> notification
end.
-spec parse_event_message(sns_event()) -> sns_notification() | binary().
parse_event_message(Event) ->
Message = proplists:get_value(<<"Message">>, Event, <<>>),
case get_event_type(Event) of
subscription_confirmation -> Message;
notification -> jsx:decode(Message, [{return_maps, false}])
end.
-spec get_notification_attribute(binary(), sns_notification()) -> sns_application_attribute() | binary().
get_notification_attribute(<<"EventType">>, Notification) ->
case proplists:get_value(<<"EventType">>, Notification) of
<<"EndpointCreated">> -> event_endpoint_created;
<<"EndpointDeleted">> -> event_endpoint_deleted;
<<"EndpointUpdated">> -> event_endpoint_updated;
<<"DeliveryFailure">> -> event_delivery_failure
end;
get_notification_attribute(Attribute, Notification) ->
proplists:get_value(Attribute, Notification).
-spec set_topic_attributes(sns_topic_attribute_name(), string()|binary(), string()) -> ok | no_return().
set_topic_attributes(AttributeName, AttributeValue, TopicArn) ->
set_topic_attributes(AttributeName, AttributeValue, TopicArn, default_config()).
-spec set_topic_attributes(sns_topic_attribute_name(), string()|binary(), string(), aws_config()) -> ok | no_return().
set_topic_attributes(AttributeName, AttributeValue, TopicArn, Config)
when is_record(Config, aws_config) ->
sns_simple_request(Config, "SetTopicAttributes", [
{"AttributeName", AttributeName},
{"AttributeValue", AttributeValue},
{"TopicArn", TopicArn}]).
-spec get_topic_attributes (string()) -> [{attributes, [{atom(), string()}]}] | no_return().
get_topic_attributes(TopicArn) ->
get_topic_attributes(TopicArn, default_config()).
-spec get_topic_attributes(string(), aws_config()) -> [{attributes, [{atom(), string()}]}] | no_return().
get_topic_attributes(TopicArn, Config)
when is_record(Config, aws_config) ->
Params = [{"TopicArn", TopicArn}],
Doc = sns_xml_request(Config, "GetTopicAttributes", Params),
Decoded =
erlcloud_xml:decode(
[{attributes, "GetTopicAttributesResult/Attributes/entry",
fun extract_attribute/1
}],
Doc),
Decoded.
-spec set_subscription_attributes(sns_subscription_attribute_name(), string()|binary(), string()) -> ok | no_return().
set_subscription_attributes(AttributeName, AttributeValue, SubscriptionArn) ->
set_subscription_attributes(AttributeName, AttributeValue, SubscriptionArn, default_config()).
-spec set_subscription_attributes(sns_subscription_attribute_name(), string()|binary(), string(), aws_config()) -> ok | no_return().
set_subscription_attributes(AttributeName, AttributeValue, SubscriptionArn, Config)
when is_record(Config, aws_config) ->
sns_simple_request(Config, "SetSubscriptionAttributes", [
{"AttributeName", AttributeName},
{"AttributeValue", AttributeValue},
{"SubscriptionArn", SubscriptionArn}]).
-spec get_subscription_attributes (string()) -> [{attributes, [{sns_subscription_attribute_name() | atom(), string()}]}] | no_return().
get_subscription_attributes(SubscriptionArn) ->
get_subscription_attributes(SubscriptionArn, default_config()).
-spec get_subscription_attributes(string(), aws_config()) -> [{attributes, [{sns_subscription_attribute_name() | atom(), string()}]}] | no_return().
get_subscription_attributes(SubscriptionArn, Config)
when is_record(Config, aws_config) ->
Params = [{"SubscriptionArn", SubscriptionArn}],
Doc = sns_xml_request(Config, "GetSubscriptionAttributes", Params),
Decoded =
erlcloud_xml:decode(
[{attributes, "GetSubscriptionAttributesResult/Attributes/entry",
fun extract_attribute/1
}],
Doc),
Decoded.
-spec subscribe(string(), sns_subscribe_protocol_type(), string()) -> Arn::string() | no_return().
subscribe(Endpoint, Protocol, TopicArn) ->
subscribe(Endpoint, Protocol, TopicArn, default_config()).
-spec subscribe(string(), sns_subscribe_protocol_type(), string(), aws_config()) -> Arn::string() | no_return().
subscribe(Endpoint, Protocol, TopicArn, Config)
when is_record(Config, aws_config) ->
Doc = sns_xml_request(Config, "Subscribe", [
{"Endpoint", Endpoint},
{"Protocol", atom_to_list(Protocol)},
{"TopicArn", TopicArn}]),
erlcloud_xml:get_text("/SubscribeResponse/SubscribeResult/SubscriptionArn", Doc).
-spec unsubscribe(string()) -> ok | no_return().
unsubscribe(SubArn) ->
unsubscribe(SubArn, default_config()).
-spec unsubscribe(string(), aws_config()) -> ok | no_return().
unsubscribe(SubArn, Config)
when is_record(Config, aws_config) ->
sns_simple_request(Config, "Unsubscribe", [{"SubscriptionArn", SubArn}]).
-spec new(string(), string()) -> aws_config().
new(AccessKeyID, SecretAccessKey) ->
#aws_config{
access_key_id=AccessKeyID,
secret_access_key=SecretAccessKey
}.
-spec new(string(), string(), string()) -> aws_config().
new(AccessKeyID, SecretAccessKey, Host) ->
#aws_config{
access_key_id=AccessKeyID,
secret_access_key=SecretAccessKey,
sns_host=Host
}.
-spec configure(string(), string()) -> ok.
configure(AccessKeyID, SecretAccessKey) ->
put(aws_config, new(AccessKeyID, SecretAccessKey)),
ok.
-spec configure(string(), string(), string()) -> ok.
configure(AccessKeyID, SecretAccessKey, Host) ->
put(aws_config, new(AccessKeyID, SecretAccessKey, Host)),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% PRIVATE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
encode_attributes(Attributes) ->
lists:foldl(
fun({Index, {Key, Value}}, Acc) ->
Prefix = "Attributes.entry." ++ integer_to_list(Index),
[{Prefix ++ ".key", encode_attribute_name(Key)},
{Prefix ++ ".value", Value} | Acc]
end, [], lists:zip(lists:seq(1, length(Attributes)), Attributes)).
encode_attribute_name(custom_user_data) -> "CustomUserData";
encode_attribute_name(enabled) -> "Enabled";
encode_attribute_name(token) -> "Token".
encode_permissions(Permissions) ->
[encode_permission(P) || P <- Permissions].
encode_permission({AccountId, Permission}) ->
{AccountId,
case Permission of
all -> "*";
add_permission -> "AddPermission";
confirm_subscription -> "ConfirmSubscription";
create_platform_application -> "CreatePlatformApplication";
create_platform_endpoint -> "CreatePlatformEndpoint";
create_topic -> "CreateTopic";
delete_endpoint -> "DeleteEndpoint";
delete_platform_application -> "DeletePlatformApplication";
delete_topic -> "DeleteTopic";
get_endpoint_attributes -> "GetEndpointAttributes";
get_platform_application_attributes -> "GetPlatformApplicationAttributes";
get_subscription_attributes -> "GetSubscriptionAttributes";
get_topic_attributes -> "GetTopicAttributes";
list_endpoints_by_platform_application -> "ListEndpointsByPlatformApplication";
list_platform_applications -> "ListPlatformApplications";
list_subscriptions -> "ListSubscriptions";
list_subscriptions_by_topic -> "ListSubscriptionsByTopic";
list_topics -> "ListTopics";
publish -> "Publish";
remove_permission -> "RemovePermission";
set_endpoint_attributes -> "SetEndpointAttributes";
set_platform_application_attributes -> "SetPlatformApplicationAttributes";
set_subscription_attributes -> "SetSubscriptionAttributes";
set_topic_attributes -> "SetTopicAttributes";
subscribe -> "Subscribe";
unsubscribe -> "Unsubscribe"
end}.
default_config() -> erlcloud_aws:default_config().
new_config(AccessKeyID, SecretAccessKey) ->
#aws_config{
access_key_id=AccessKeyID,
secret_access_key=SecretAccessKey
}.
set_sns_host(Host) ->
Config = erlcloud_aws:default_config(),
put(aws_config, Config#aws_config{sns_host = Host}).
sns_simple_request(Config, Action, Params) ->
sns_request(Config, Action, Params),
ok.
sns_xml_request(Config, Action, Params) ->
case erlcloud_aws:aws_request_xml4(get,
scheme_to_protocol(Config#aws_config.sns_scheme),
Config#aws_config.sns_host, Config#aws_config.sns_port, "/",
[{"Action", Action}, {"Version", ?API_VERSION} | Params],
"sns", Config) of
{ok, XML} -> XML;
{error, {http_error, _, _BadRequest, Body}} ->
XML = element(1, xmerl_scan:string(binary_to_list(Body))),
ErrCode = erlcloud_xml:get_text("Error/Code", XML),
ErrMsg = erlcloud_xml:get_text("Error/Message", XML),
erlang:error({sns_error, ErrCode, ErrMsg});
{error, Reason} ->
erlang:error({sns_error, Reason})
end.
sns_request(Config, Action, Params) ->
case erlcloud_aws:aws_request_xml4(post,
scheme_to_protocol(Config#aws_config.sns_scheme),
Config#aws_config.sns_host, Config#aws_config.sns_port, "/",
[{"Action", Action}, {"Version", ?API_VERSION} | Params],
"sns", Config) of
{ok, _Response} -> ok;
{error, {http_error, 400, _BadRequest, Body}} ->
XML = element(1, xmerl_scan:string(binary_to_list(Body))),
ErrCode = erlcloud_xml:get_text("Error/Code", XML),
ErrMsg = erlcloud_xml:get_text("Error/Message", XML),
erlang:error({sns_error, ErrCode, ErrMsg});
{error, Reason} ->
erlang:error({sns_error, Reason})
end.
list_all(Fun, Type, Config, Token, Acc) ->
Res = Fun(Token, Config),
List = proplists:get_value(Type, Res),
case proplists:get_value(next_token, Res) of
"" ->
lists:foldl(fun erlang:'++'/2, [], [List | Acc]);
NextToken ->
list_all(Fun, Type, Config, NextToken, [List | Acc])
end.
extract_endpoint(Nodes) ->
[erlcloud_xml:decode(
[{arn, "EndpointArn", text},
{attributes, "Attributes/entry", fun extract_attribute/1}
], Node) || Node <- Nodes].
extract_application(Nodes) ->
[erlcloud_xml:decode(
[{arn, "PlatformApplicationArn", text},
{attributes, "Attributes/entry", fun extract_attribute/1}
], Node) || Node <- Nodes].
extract_attribute(Nodes) ->
[{parse_key(erlcloud_xml:get_text("key", Node)),
erlcloud_xml:get_text("value", Node)}
|| Node <- Nodes].
extract_subscription(Nodes) ->
[erlcloud_xml:decode(
[{topic_arn, "TopicArn", text},
{protocol, "Protocol", text},
{arn, "SubscriptionArn", text},
{owner, "Owner", text},
{endpoint, "Endpoint", text}
], Node) || Node <- Nodes].
extract_topic_arn(Nodes) ->
[erlcloud_xml:decode([{arn, "TopicArn", text}], Node) || Node <- Nodes].
parse_key("Enabled") -> enabled;
parse_key("CustomUserData") -> custom_user_data;
parse_key("Token") -> token;
parse_key("EventEndpointCreated") -> event_endpoint_created;
parse_key("EventEndpointDeleted") -> event_endpoint_deleted;
parse_key("EventEndpointUpdated") -> event_endpoint_updated;
parse_key("EventDeliveryFailure") -> event_delivery_failure;
% Subscription attribute names.
parse_key("RawMessageDelivery") -> 'RawMessageDelivery';
parse_key("ConfirmationWasAuthenticated") -> 'ConfirmationWasAuthenticated';
parse_key("FilterPolicy") -> 'FilterPolicy';
parse_key("DeliveryPolicy") -> 'DeliveryPolicy';
parse_key(OtherKey) -> list_to_atom(string:to_lower(OtherKey)).
scheme_to_protocol(S) when is_list(S) -> s2p(string:to_lower(S));
scheme_to_protocol(_) -> erlang:error({sns_error, badarg}).
s2p("http://") -> "http";
s2p("https://") -> "https";
s2p(X) -> erlang:error({sns_error, {unsupported_scheme, X}}).
-spec message_attributes(sns_message_attributes()) -> [{string(), string()}].
message_attributes(Attributes) ->
EnumeratedAttrs = lists:zip(lists:seq(1, length(Attributes)), Attributes),
lists:flatmap(
fun({Num, {Name, Value}}) ->
[format_attribute_field(Num, Field) || Field <- fields_for_attribute(Name, Value)]
end,
EnumeratedAttrs).
-spec format_attribute_field(integer(), {string(), string()}) -> {string(), string()}.
format_attribute_field(Num, {Key, Value}) ->
StrNum = integer_to_list(Num),
{"MessageAttributes.entry." ++ StrNum ++ "." ++ Key, Value}.
-spec fields_for_attribute(string(), string() | binary() | number()) -> [{string(), string()}].
fields_for_attribute(Name, Value) ->
[{"Key", Name} | fields_for_attribute(Value)].
-spec fields_for_attribute(string() | binary() | number()) -> [{string(), string()}].
fields_for_attribute(Value) when is_list(Value) ->
[{"Value.DataType", "String"}, {"Value.StringValue", Value}];
fields_for_attribute(Value) when is_binary(Value) ->
[{"Value.DataType", "Binary"}, {"Value.BinaryValue", base64:encode_to_string(Value)}];
fields_for_attribute(Value) when is_float(Value) ->
[{"Value.DataType", "Number"}, {"Value.StringValue", float_to_list(Value)}];
fields_for_attribute(Value) when is_integer(Value) ->
[{"Value.DataType", "Number"}, {"Value.StringValue", integer_to_list(Value)}].