1
0
mirror of https://github.com/nikoksr/notify.git synced 2025-01-22 03:09:35 +02:00

feat(service): Add AWS SNS (#110)

Co-authored-by: Niko Köser <koeserniko@gmail.com>
This commit is contained in:
Raphael Abrantes 2022-02-07 06:18:48 -03:00 committed by GitHub
parent 7d85160b7a
commit 80bc1fa47d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 202 additions and 1 deletions

3
go.mod
View File

@ -6,11 +6,13 @@ require (
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
github.com/Rhymen/go-whatsapp v0.1.1
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210506200512-3b3352a919f0
github.com/antihax/optional v1.0.0 // indirect
github.com/atc0005/go-teams-notify/v2 v2.6.0
github.com/aws/aws-sdk-go-v2 v1.13.0
github.com/aws/aws-sdk-go-v2/config v1.13.1
github.com/aws/aws-sdk-go-v2/credentials v1.8.0
github.com/aws/aws-sdk-go-v2/service/ses v1.12.0
github.com/aws/aws-sdk-go-v2/service/sns v1.4.1
github.com/blinkbean/dingtalk v0.0.0-20210905093040-7d935c0f7e19
github.com/bwmarrin/discordgo v0.23.2
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb
@ -32,7 +34,6 @@ require (
)
require (
github.com/antihax/optional v1.0.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 // indirect

4
go.sum
View File

@ -50,6 +50,7 @@ github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwc
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/atc0005/go-teams-notify/v2 v2.6.0 h1:YegKDWbjlatR0fP2yHsQYXzTcUGNJXhm1/OiCgbyysc=
github.com/atc0005/go-teams-notify/v2 v2.6.0/go.mod h1:xo6GejLDHn3tWBA181F8LrllIL0xC1uRsRxq7YNXaaY=
github.com/aws/aws-sdk-go-v2 v1.6.0/go.mod h1:tI4KhsR5VkzlUa2DZAdwx7wCAYGwkZZ1H31PYrBFx1w=
github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA=
github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w=
github.com/aws/aws-sdk-go-v2/config v1.13.1 h1:yLv8bfNoT4r+UvUKQKqRtdnvuWGMK5a82l4ru9Jvnuo=
@ -68,10 +69,13 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU=
github.com/aws/aws-sdk-go-v2/service/ses v1.12.0 h1:AsIuaTDMsg0bX5cfGNfU8uxUA1tAhBrojswetpD6PcY=
github.com/aws/aws-sdk-go-v2/service/ses v1.12.0/go.mod h1:061vZ/X66UM49xth/ZZGvtJdHGgLh8FwgRvt+1YyhJI=
github.com/aws/aws-sdk-go-v2/service/sns v1.4.1 h1:uc9t63SToTT6v/NG2UT3m+8DNpZF1noCSFbHk8dh9RE=
github.com/aws/aws-sdk-go-v2/service/sns v1.4.1/go.mod h1:SyRNX444n2Vk3NAEEM0ewyS8qsTeAjig3HPjvlBuhlM=
github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXWrscPqsrAaU1aTA=
github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU=
github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E=
github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk=
github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w=
github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/blinkbean/dingtalk v0.0.0-20210905093040-7d935c0f7e19 h1:pamuM2sgLJLoMWfchc6y071z8ifalajU7btZmZNhoH4=

View File

@ -0,0 +1,79 @@
package amazonsns
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/sns"
"github.com/pkg/errors"
)
// SNSSendMessageAPI Basic interface to send messages through SNS.
type SNSSendMessageAPI interface {
SendMessage(ctx context.Context,
params *sns.PublishInput,
optFns ...func(*sns.Options)) (*sns.PublishOutput, error)
}
// SNSSendMessageClient Client specific for SNS using aws sdk v2.
type SNSSendMessageClient struct {
client *sns.Client
}
// SendMessage Client specific for SNS using aws sdk v2.
func (s SNSSendMessageClient) SendMessage(ctx context.Context,
params *sns.PublishInput,
optFns ...func(*sns.Options)) (*sns.PublishOutput, error) {
return s.client.Publish(ctx, params, optFns...)
}
// AmazonSNS Basic structure with SNS information
type AmazonSNS struct {
sendMessageClient SNSSendMessageAPI
queueTopics []string
}
// New creates a new AmazonSNS
func New(accessKeyID, secretKey, region string) (*AmazonSNS, error) {
credProvider := credentials.NewStaticCredentialsProvider(accessKeyID, secretKey, "")
cfg, err := config.LoadDefaultConfig(
context.Background(),
config.WithCredentialsProvider(credProvider),
config.WithRegion(region),
)
if err != nil {
return nil, err
}
client := sns.NewFromConfig(cfg)
return &AmazonSNS{
sendMessageClient: SNSSendMessageClient{client: client},
}, nil
}
// AddReceivers takes queue urls and adds them to the internal topics
// list. The Send method will send a given message to all those
// Topics.
func (s *AmazonSNS) AddReceivers(queues ...string) {
s.queueTopics = append(s.queueTopics, queues...)
}
// Send message to everyone on all topics
func (s AmazonSNS) Send(ctx context.Context, subject, message string) error {
// For each topic
for _, topic := range s.queueTopics {
// Create new input with subject, message and the specific topic
input := &sns.PublishInput{
Subject: aws.String(subject),
Message: aws.String(message),
TopicArn: aws.String(topic),
}
// Send the message
_, err := s.sendMessageClient.SendMessage(ctx, input)
if err != nil {
return errors.Wrapf(err, "failed to send message using Amazon SNS to ARN TOPIC '%s'", topic)
}
}
return nil
}

View File

@ -0,0 +1,117 @@
package amazonsns
import (
"context"
"errors"
"testing"
"github.com/aws/aws-sdk-go-v2/service/sns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type SNSSendMessageMock struct {
mock.Mock
}
func (m *SNSSendMessageMock) SendMessage(ctx context.Context,
params *sns.PublishInput,
optFns ...func(*sns.Options)) (*sns.PublishOutput, error) {
args := m.Called(ctx, params, optFns)
return args.Get(0).(*sns.PublishOutput), args.Error(1)
}
func TestAddReceivers(t *testing.T) {
amazonSNS, err := New("", "", "")
if err != nil {
t.Error(err)
}
amazonSNS.AddReceivers("One topic")
}
func TestSendMessageWithNoTopicsConfigured(t *testing.T) {
mockSns := new(SNSSendMessageMock)
amazonSNS := AmazonSNS{
sendMessageClient: mockSns,
}
err := amazonSNS.Send(context.Background(), "Subject", "Message")
assert.Nil(t, err)
mockSns.AssertNotCalled(t, "SendMessage", mock.Anything, mock.Anything, mock.Anything)
}
func TestSendMessageWithSucessAndOneTopicCOnfigured(t *testing.T) {
mockSns := new(SNSSendMessageMock)
output := sns.PublishOutput{}
mockSns.On("SendMessage", mock.Anything, mock.Anything, mock.Anything).
Return(&output, nil)
amazonSNS := AmazonSNS{
sendMessageClient: mockSns,
}
amazonSNS.AddReceivers("arn:aws:sns:region:number:topicname")
err := amazonSNS.Send(context.Background(), "Subject", "Message")
assert.Nil(t, err)
mockSns.AssertExpectations(t)
assert.Equal(t, 1, len(mockSns.Calls))
}
func TestSendMessageWithSucessAndTwoTopicCOnfigured(t *testing.T) {
mockSns := new(SNSSendMessageMock)
output := sns.PublishOutput{}
mockSns.On("SendMessage", mock.Anything, mock.Anything, mock.Anything).
Return(&output, nil)
amazonSNS := AmazonSNS{
sendMessageClient: mockSns,
}
amazonSNS.AddReceivers("arn:aws:sns:region:number:topicname1",
"arn:aws:sns:region:number:topicname1")
err := amazonSNS.Send(context.Background(), "Subject", "Message")
assert.Nil(t, err)
mockSns.AssertExpectations(t)
assert.Equal(t, 2, len(mockSns.Calls))
}
func TestSendMessageWithErrorAndOneQueueConfiguredShouldReturnError(t *testing.T) {
mockSns := new(SNSSendMessageMock)
output := sns.PublishOutput{}
mockSns.On("SendMessage", mock.Anything, mock.Anything, mock.Anything).
Return(&output, errors.New("Error on SNS"))
amazonSNS := AmazonSNS{
sendMessageClient: mockSns,
}
amazonSNS.AddReceivers("arn:aws:sns:region:number:topicname")
err := amazonSNS.Send(context.Background(), "Subject", "Message")
assert.NotNil(t, err)
mockSns.AssertExpectations(t)
assert.Equal(t, 1, len(mockSns.Calls))
}
func TestSendMessageWithErrorAndTwoQueueConfiguredShouldReturnErrorOnFirst(t *testing.T) {
mockSns := new(SNSSendMessageMock)
output := sns.PublishOutput{}
mockSns.On("SendMessage", mock.Anything, mock.Anything, mock.Anything).
Return(&output, errors.New("Error on SNS"))
amazonSNS := AmazonSNS{
sendMessageClient: mockSns,
}
amazonSNS.AddReceivers(
"arn:aws:sns:region:number:topicname1",
"arn:aws:sns:region:number:topicname1")
err := amazonSNS.Send(context.Background(), "Subject", "Message")
assert.NotNil(t, err)
mockSns.AssertExpectations(t)
assert.Equal(t, 1, len(mockSns.Calls))
}