2019-04-22 02:59:20 +00:00

104 lines
2.4 KiB
Go

package fcm
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
const (
// PriorityHigh used for high notification priority
PriorityHigh = "high"
// PriorityNormal used for normal notification priority
PriorityNormal = "normal"
// HeaderRetryAfter HTTP header constant
HeaderRetryAfter = "Retry-After"
// ErrorKey readable error caching
ErrorKey = "error"
// MethodPOST indicates http post method
MethodPOST = "POST"
// ServerURL push server url
ServerURL = "https://fcm.googleapis.com/fcm/send"
)
// retryableErrors whether the error is a retryable
var retryableErrors = map[string]bool{
"Unavailable": true,
"InternalServerError": true,
}
// Client stores client with api key to firebase
type Client struct {
APIKey string
HTTPClient *http.Client
}
// NewClient creates a new client
func NewClient(apiKey string, timeout time.Duration) *Client {
return &Client{
APIKey: apiKey,
HTTPClient: &http.Client{Timeout: timeout},
}
}
func (f *Client) authorization() string {
return fmt.Sprintf("key=%v", f.APIKey)
}
// Send sends message to FCM
func (f *Client) Send(message *Message) (*Response, error) {
data, err := json.Marshal(message)
if err != nil {
return &Response{}, err
}
req, err := http.NewRequest(MethodPOST, ServerURL, bytes.NewBuffer(data))
if err != nil {
return &Response{}, err
}
req.Header.Set("Authorization", f.authorization())
req.Header.Set("Content-Type", "application/json")
resp, err := f.HTTPClient.Do(req)
if err != nil {
return &Response{}, err
}
defer resp.Body.Close()
response := &Response{StatusCode: resp.StatusCode}
if resp.StatusCode >= 500 {
response.RetryAfter = resp.Header.Get(HeaderRetryAfter)
}
if resp.StatusCode != 200 {
return response, fmt.Errorf("fcm status code(%d)", resp.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return response, err
}
if err := json.Unmarshal(body, &response); err != nil {
return response, err
}
if err := f.Failed(response); err != nil {
return response, err
}
response.Ok = true
return response, nil
}
// Failed method indicates if the server couldn't process
// the request in time.
func (f *Client) Failed(response *Response) error {
for _, response := range response.Results {
if retryableErrors[response.Error] {
return fmt.Errorf("fcm push error(%s)", response.Error)
}
}
return nil
}