You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.4 KiB
103 lines
2.4 KiB
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 |
|
}
|
|
|