forked from Iwark/pushnotification
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpushnotification.go
More file actions
180 lines (159 loc) · 4.76 KB
/
pushnotification.go
File metadata and controls
180 lines (159 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package pushnotification
import (
"errors"
"log"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"
)
// Service is the main entry point into using this package.
type Service struct {
Key string
Secret string
Region string
GCM string
APNS string
APNSSandbox string
Windows string
Platforms map[string]string
}
type Device struct {
Token string
Type string
EndpointArn string
created bool
}
func (device *Device) IsCreated() bool {
return device.created
}
// Data is the data of the sending pushnotification.
type Data struct {
Alert *string `json:"alert,omitempty"`
Subject *string `json:"subject,omitempty"`
Sound *string `json:"sound,omitempty"`
Badge *int `json:"badge,omitempty"`
Data map[string]interface{} `json:"custom_data"`
}
// Send sends a push notification
func (service *Service) Send(device *Device, data *Data) (err error) {
svc := sns.New(session.New(&aws.Config{
Credentials: credentials.NewStaticCredentials(service.Key, service.Secret, ""),
Region: aws.String(service.Region),
}))
message, err := newMessageJSON(data)
if err != nil {
log.Println("Message could not be created", err)
return
}
err = service.pushToDevice(svc, device, *data.Subject, message)
// or get this extra info from an app
if device.Type == "ios" && len(service.APNSSandbox) > 0 {
sandBox := &Device{
Token: device.Token,
Type: "_ios_sandbox_",
}
err = service.pushToDevice(svc, sandBox, *data.Subject, message)
}
return
}
func (service *Service) pushToDevice(svc *sns.SNS, device *Device, subject string, message string) (err error) {
err = service.getEndpointArn(svc, device)
if err != nil {
log.Println("Endpoint could not be retrieved", err)
return
}
input := &sns.PublishInput{
Message: aws.String(message),
MessageStructure: aws.String("json"),
TargetArn: aws.String(device.EndpointArn),
}
if subject != "" {
input.Subject = aws.String(subject)
}
_, err = svc.Publish(input)
return
}
// get platform ARN for device, create or update when needed
func (service *Service) getEndpointArn(svc *sns.SNS, device *Device) (err error) {
// recommended approach with endpointArn
// https://mobile.awsblog.com/post/Tx223MJB0XKV9RU/Mobile-token-management-with-Amazon-SNS
if len(device.EndpointArn) == 0 {
device.EndpointArn, err = service.createEndpointArn(svc, device)
if err != nil {
return
}
device.created = true
}
// get endpoint and check status etc
resp, err := svc.GetEndpointAttributes(&sns.GetEndpointAttributesInput{
EndpointArn: aws.String(device.EndpointArn),
})
if err != nil {
// endpoint is not there
device.EndpointArn, err = service.createEndpointArn(svc, device)
if err != nil {
return
}
device.created = true
} else if *resp.Attributes["Token"] == device.Token || *resp.Attributes["Enabled"] != "true" {
// update endpoint
params := &sns.SetEndpointAttributesInput{
Attributes: map[string]*string{
"Token": aws.String(device.Token),
"Enabled": aws.String("true"),
},
EndpointArn: aws.String(device.EndpointArn),
}
_, err := svc.SetEndpointAttributes(params)
if err != nil {
log.Println("Endpoint could not be updated", err)
}
}
return
}
// create platform ARN for device
func (service *Service) createEndpointArn(svc *sns.SNS, device *Device) (string, error) {
platform, err := service.getPlatform(device)
if err != nil {
log.Println(err)
return "", err
}
resp, err := svc.CreatePlatformEndpoint(&sns.CreatePlatformEndpointInput{
PlatformApplicationArn: aws.String(platform),
Token: aws.String(device.Token),
})
if err != nil {
log.Println(err)
return "", err
}
return *resp.EndpointArn, err
}
// get application ARN for device type
func (service *Service) getPlatform(device *Device) (platform string, err error) {
deviceType := strings.ToLower(device.Type)
if deviceType == "gcm" && len(service.GCM) > 0 {
platform = service.GCM
} else if deviceType == "android" && len(service.GCM) > 0 {
platform = service.GCM
} else if deviceType == "ios" && len(service.APNS) > 0 {
platform = service.APNS
} else if deviceType == "_ios_sandbox_" && len(service.APNSSandbox) > 0 {
platform = service.APNSSandbox
} else if deviceType == "windows" && len(service.Windows) > 0 {
platform = service.Windows
} else {
notfound := true
if service.Platforms != nil {
if value, ok := service.Platforms[deviceType]; ok {
platform = value
notfound = false
}
}
if notfound {
err = errors.New("Device.Type " + device.Type + " not supported")
}
}
return
}