/
fcm.go
229 lines (188 loc) · 10.7 KB
/
fcm.go
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package fcm
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"golang.org/x/net/context"
"google.golang.org/appengine/urlfetch"
)
const (
// Firebase Cloud Messaging HTTP endpoint
httpEndpointURL = "https://fcm.googleapis.com/fcm/send"
)
// HTTPMessage -> Downstream HTTP messages
type HTTPMessage struct {
To string `json:"to,omitempty"` // This parameter specifies the recipient of a message.
RegistrationIds []string `json:"registration_ids,omitempty"` // This parameter specifies the recipient of a multicast message, a message sent to more than one registration token.
Condition string `json:"condition,omitempty"` // This parameter specifies a logical expression of conditions that determine the message target.
NotificationKey string `json:"notification_key,omitempty"` // This parameter is deprecated. Instead, use to to specify message recipients.
CollapseKey string `json:"collapse_key,omitempty"` // This parameter identifies a group of messages (e.g., with collapse_key: "Updates Available") that can be collapsed, so that only the last message gets sent when delivery can be resumed. This is intended to avoid sending too many of the same messages when the device comes back online or becomes active.
Priority string `json:"priority,omitempty"` // Sets the priority of the message. Valid values are "normal" and "high." On iOS, these correspond to APNs priorities 5 and 10.
ContentAvailable bool `json:"content_available,omitempty"` // On iOS, use this field to represent content-available in the APNs payload. When a notification or message is sent and this is set to true, an inactive client app is awoken, and the message is sent through APNs as a silent notification and not through the FCM connection server. Note that silent notifications in APNs are not guaranteed to be delivered, and can depend on factors such as the user turning on Low Power Mode, force quitting the app, etc. On Android, data messages wake the app by default. On Chrome, currently not supported.
MutableContent bool `json:"mutable_content,omitempty"` // Currently for iOS 10+ devices only. On iOS, use this field to represent mutable-content in the APNs payload. When a notification is sent and this is set to true, the content of the notification can be modified before it is displayed, using a Notification Service app extension.
DelayWhileIdle bool `json:"delay_while_idle,omitempty"` // This parameter is deprecated.
TimeToLive int `json:"time_to_live,omitempty"` // This parameter specifies how long (in seconds) the message should be kept in FCM storage if the device is offline. The maximum time to live supported is 4 weeks, and the default value is 4 weeks.
RestrictedPackageName string `json:"restricted_package_name,omitempty"` // This parameter specifies the package name of the application where the registration tokens must match in order to receive the message.
DryRun bool `json:"dry_run,omitempty"` // This parameter, when set to true, allows developers to test a request without actually sending a message.
Data interface{} `json:"data,omitempty"` // This parameter specifies the custom key-value pairs of the message's payload.
Notification NotificationPayload `json:"notification,omitempty"` // This parameter specifies the predefined, user-visible key-value pairs of the notification payload.
}
// NotificationPayload -> Notification payload support
type NotificationPayload struct {
Title string `json:"title,omitempty"` // The notification's title.(iOS,Android,Web)
Body string `json:"body,omitempty"` // The notification's body text.(iOS,Android,Web)
AndroidChannelID string `json:"android_channel_id,omitempty"` // The notification's channel id (new in Android O).(Android)
Icon string `json:"icon,omitempty"` // The notification's icon.(Android,Web)
Sound string `json:"sound,omitempty"` // The sound to play when the device receives the notification.(iOS,Android)
Badge string `json:"badge,omitempty"` // The value of the badge on the home screen app icon.(iOS)
Tag string `json:"tag,omitempty"` // Identifier used to replace existing notifications in the notification drawer.(Android)
Color string `json:"color,omitempty"` // The notification's icon color, expressed in #rrggbb format.(Android)
ClickAction string `json:"click_action,omitempty"` // The action associated with a user click on the notification.(iOS,Android,Web)
Subtitle string `json:"subtitle,omitempty"` // The notification's subtitle.(iOS)
BodyLocKey string `json:"body_loc_key,omitempty"` // The key to the body string in the app's string resources to use to localize the body text to the user's current localization.(iOS,Android)
BodyLocArgs string `json:"body_loc_args,omitempty"` // Variable string values to be used in place of the format specifiers in body_loc_key to use to localize the body text to the user's current localization.(iOS,Android)
TitleLocKey string `json:"title_loc_key,omitempty"` // The key to the title string in the app's string resources to use to localize the title text to the user's current localization.(iOS,Android)
TitleLocArgs string `json:"title_loc_args,omitempty"` // Variable string values to be used in place of the format specifiers in title_loc_key to use to localize the title text to the user's current localization.(iOS,Android)
}
// HTTPResponse -> Downstream HTTP message response
type HTTPResponse struct {
StatusCode int
MulticastID int64 `json:"multicast_id"`
Success int `json:"success"`
Failure int `json:"failure"`
CanonicalIds int `json:"canonical_ids"`
Results []HTTPResponseResult `json:"results,omitempty"`
MessageID int64 `json:"message_id,omitempty"`
Error string `json:"error,omitempty"`
}
// HTTPResponseResult -> Downstream HTTP message response result
type HTTPResponseResult struct {
MessageID string `json:"message_id"`
RegistrationID int `json:"registration_id"`
Error string `json:"error,omitempty"`
}
// Client stores the key and the Message
type Client struct {
ServerKey string
Message HTTPMessage
}
// SendMessage to firebase
func (c *Client) SendMessage() (rm *HTTPResponse, err error) {
rm = new(HTTPResponse)
var jsonByte []byte
if jsonByte, err = json.Marshal(c.Message); err != nil {
return rm, err
}
request, _ := http.NewRequest("POST", httpEndpointURL, bytes.NewBuffer(jsonByte))
request.Header.Set("Authorization", "key="+c.ServerKey)
request.Header.Set("Content-Type", "application/json")
client := &http.Client{}
var response *http.Response
response, err = client.Do(request)
rm.StatusCode = response.StatusCode
if err != nil {
return rm, err
}
defer response.Body.Close()
var responseBody []byte
if responseBody, err = ioutil.ReadAll(response.Body); err != nil {
return rm, err
}
if response.StatusCode != 200 {
return rm, nil
}
if err = json.Unmarshal([]byte(responseBody), &rm); err != nil {
return rm, err
}
return rm, nil
}
// SendMessageWithHTTPClient to firebase
func (c *Client) SendMessageWithHTTPClient(ctx context.Context) (rm *HTTPResponse, err error) {
rm = new(HTTPResponse)
var jsonByte []byte
if jsonByte, err = json.Marshal(c.Message); err != nil {
return rm, err
}
request, _ := http.NewRequest("POST", httpEndpointURL, bytes.NewBuffer(jsonByte))
request.Header.Set("Authorization", "key="+c.ServerKey)
request.Header.Set("Content-Type", "application/json")
client := urlfetch.Client(ctx)
var response *http.Response
response, err = client.Do(request)
rm.StatusCode = response.StatusCode
if err != nil {
return rm, err
}
defer response.Body.Close()
var responseBody []byte
if responseBody, err = ioutil.ReadAll(response.Body); err != nil {
return rm, err
}
if response.StatusCode != 200 {
return rm, nil
}
if err = json.Unmarshal(responseBody, &rm); err != nil {
return rm, err
}
return rm, nil
}
// SetCollapseKey identifies a group of messages
func (c *Client) SetCollapseKey(collapseKey string) {
c.Message.CollapseKey = collapseKey
}
// SetCondition sets a logical expression of conditions that determine the message target
func (c *Client) SetCondition(condition string) {
c.Message.Condition = condition
}
// SetContentAvailable use this field to represent content-available in the APNs payload
func (c *Client) SetContentAvailable(contentAvailable bool) {
c.Message.ContentAvailable = contentAvailable
}
// SetData sets data payload
func (c *Client) SetData(body interface{}) {
c.Message.Data = body
}
// SetDryRun allows developers to test a request without actually sending a message
func (c *Client) SetDryRun(dryRun bool) {
c.Message.DryRun = dryRun
}
// SetMutableContent use this field to represent mutable-content in the APNs payload
func (c *Client) SetMutableContent(mutableContent bool) {
c.Message.MutableContent = mutableContent
}
// SetNotification sets the notification payload
func (c *Client) SetNotification(np NotificationPayload) {
c.Message.Notification = np
}
// SetPriority sets the priority of the message
func (c *Client) SetPriority(priority string) {
if priority != "high" {
priority = "normal"
}
c.Message.Priority = priority
}
// SetRegistrationIds sets the recipient of a multicast message
func (c *Client) SetRegistrationIds(registrationIds []string) {
c.Message.RegistrationIds = append(c.Message.RegistrationIds, registrationIds...)
}
// SetRestrictedPackageName sets the package name of the application where the registration tokens must match in order to receive the message
func (c *Client) SetRestrictedPackageName(restrictedPackageName string) {
c.Message.RestrictedPackageName = restrictedPackageName
}
// SetServerKey sets the server key
func (c *Client) SetServerKey(serverKey string) {
c.ServerKey = serverKey
}
// SetTimeToLive sets how long (in seconds) the message should be kept in FCM storage if the device is offline.
func (c *Client) SetTimeToLive(timeToLive int) {
if timeToLive > 2419200 {
c.Message.TimeToLive = 2419200
} else {
c.Message.TimeToLive = timeToLive
}
}
// SetTo sets the recipient of a message
func (c *Client) SetTo(to string) {
c.Message.To = to
}