360 lines
10 KiB
Go
360 lines
10 KiB
Go
// See documentation here:
|
|
//
|
|
// Sending notifications
|
|
//
|
|
// https://developer.huawei.com/consumer/en/doc/development/HMSCore-References/https-send-api-0000001050986197
|
|
//
|
|
// OAuth2.0
|
|
//
|
|
// https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/oauth2-0000001212610981
|
|
package huawei_push
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.bit5.ru/backend/errors"
|
|
|
|
"golang.org/x/oauth2"
|
|
"github.com/go-logr/logr"
|
|
)
|
|
|
|
func MakeSendEndpointV1(appId string) string {
|
|
return fmt.Sprintf("https://push-api.cloud.huawei.com/v1/%s/messages:send", appId)
|
|
}
|
|
|
|
func MakeSendEndpointV2(projectId string) string {
|
|
return fmt.Sprintf("https://push-api.cloud.huawei.com/v2/%s/messages:send", projectId)
|
|
}
|
|
|
|
type ClientConfig struct {
|
|
SendEndpoint string
|
|
}
|
|
|
|
type Client struct {
|
|
cfg ClientConfig
|
|
ts oauth2.TokenSource
|
|
httpClient *http.Client
|
|
logger logr.Logger
|
|
}
|
|
|
|
func NewClient(cfg ClientConfig, ts oauth2.TokenSource, httpClient *http.Client, logger logr.Logger) *Client {
|
|
return &Client{
|
|
cfg: cfg,
|
|
ts: ts,
|
|
httpClient: httpClient,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (c *Client) SendMessage(msg Message) (SendResponse, error) {
|
|
sendRequest := SendRequest{
|
|
ValidateOnly: false,
|
|
Message: msg,
|
|
}
|
|
|
|
return c.doSend(sendRequest)
|
|
}
|
|
|
|
func (c *Client) ValidateMessage(msg Message) (SendResponse, error) {
|
|
sendRequest := SendRequest{
|
|
ValidateOnly: true,
|
|
Message: msg,
|
|
}
|
|
|
|
return c.doSend(sendRequest)
|
|
}
|
|
|
|
func (c *Client) doSend(req SendRequest) (SendResponse, error) {
|
|
accessToken, err := c.ts.Token()
|
|
if err != nil {
|
|
return SendResponse{}, err
|
|
}
|
|
|
|
data, err := json.Marshal(req)
|
|
if err != nil {
|
|
return SendResponse{}, errors.WithStack(err)
|
|
}
|
|
|
|
request, err := http.NewRequest(http.MethodPost, c.cfg.SendEndpoint, bytes.NewReader(data))
|
|
if err != nil {
|
|
return SendResponse{}, errors.WithStack(err)
|
|
}
|
|
|
|
accessToken.SetAuthHeader(request)
|
|
request.Header.Set("Content-Type", "application/json; charset=UTF-8")
|
|
|
|
response, err := c.httpClient.Do(request)
|
|
if err != nil {
|
|
return SendResponse{}, errors.WithStack(err)
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(response.Body)
|
|
if err != nil {
|
|
return SendResponse{}, errors.WithStack(err)
|
|
}
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
return SendResponse{}, errors.New(string(body))
|
|
}
|
|
|
|
var resp SendResponse
|
|
if err := json.Unmarshal(body, &resp); err != nil {
|
|
return SendResponse{}, errors.WithStack(err)
|
|
}
|
|
|
|
if resp.IsPartialSuccess() {
|
|
if err := json.Unmarshal([]byte(resp.Message), &resp.PartialResponse); err != nil {
|
|
return SendResponse{}, errors.WithStack(err)
|
|
}
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
type SendRequest struct {
|
|
ValidateOnly bool `json:"validate_only"`
|
|
Message Message `json:"message"`
|
|
}
|
|
|
|
type ResultCode string
|
|
|
|
const (
|
|
ResultCode_Success ResultCode = "80000000"
|
|
ResultCode_PartialSuccess ResultCode = "80100000"
|
|
)
|
|
|
|
type SendResponse struct {
|
|
Code ResultCode `json:"code"`
|
|
Message string `json:"msg"`
|
|
RequestId string `json:"requestId"`
|
|
|
|
PartialResponse PartialSuccessResponse `json:"-"`
|
|
}
|
|
|
|
type PartialSuccessResponse struct {
|
|
Success int `json:"success"`
|
|
Failure int `json:"failure"`
|
|
IllegalTokens []string `json:"illegal_tokens"`
|
|
}
|
|
|
|
func (r SendResponse) IsSuccess() bool {
|
|
return r.Code == ResultCode_Success
|
|
}
|
|
|
|
func (r SendResponse) IsPartialSuccess() bool {
|
|
return r.Code == ResultCode_PartialSuccess
|
|
}
|
|
|
|
func (r SendResponse) IsError() bool {
|
|
return !r.IsSuccess() && !r.IsPartialSuccess()
|
|
}
|
|
|
|
type Message struct {
|
|
Data json.RawMessage `json:"data,omitempty"`
|
|
Notification *Notification `json:"notification,omitempty"`
|
|
Android *AndroidConfig `json:"android,omitempty"`
|
|
Apns *ApnsConfig `json:"apns,omitempty"`
|
|
Webpush *WebPushConfig `json:"webpush,omitempty"`
|
|
|
|
Token []string `json:"token,omitempty"`
|
|
Topic string `json:"topic,omitempty"`
|
|
Condition string `json:"condition,omitempty"`
|
|
}
|
|
|
|
type Notification struct {
|
|
Title string `json:"title"`
|
|
Body string `json:"body"`
|
|
Image string `json:"image,omitempty"`
|
|
}
|
|
|
|
type AndroidConfig struct {
|
|
CollapseKey int `json:"collapse_key,omitempty"`
|
|
Ttl string `json:"ttl,omitempty"`
|
|
BiTag string `json:"bi_tag,omitempty"`
|
|
ReceiptId string `json:"receipt_id,omitempty"`
|
|
FastAppTarget FastAppState `json:"fast_app_target,omitempty"`
|
|
Data json.RawMessage `json:"data,omitempty"`
|
|
Notification *AndroidNotification `json:"notification,omitempty"`
|
|
}
|
|
|
|
type FastAppState uint8
|
|
|
|
const (
|
|
FastAppState_Dev FastAppState = 1
|
|
FastAppState_Prod FastAppState = 2
|
|
)
|
|
|
|
type AndroidNotification struct {
|
|
Title string `json:"title,omitempty"`
|
|
Body string `json:"body,omitempty"`
|
|
Icon string `json:"icon,omitempty"`
|
|
Color string `json:"color,omitempty"`
|
|
Sound string `json:"sound,omitempty"`
|
|
UseDefaultSound bool `json:"default_sound,omitempty"`
|
|
Tag string `json:"tag,omitempty"`
|
|
ClickAction ClickAction `json:"click_action"`
|
|
BodyLocalizationKey string `json:"body_loc_key,omitempty"`
|
|
BodyLocalizationArgs []string `json:"body_loc_args,omitempty"`
|
|
TitleLocalizationKey string `json:"title_loc_key,omitempty"`
|
|
TitleLocalizationArgs []string `json:"title_loc_args,omitempty"`
|
|
MultiLanguageKey *MessageLocalization `json:"multi_lang_key,omitempty"`
|
|
ChannelID string `json:"channel_id,omitempty"`
|
|
NotifySummary string `json:"notify_summary,omitempty"`
|
|
Image string `json:"image,omitempty"`
|
|
Style NotificationStyle `json:"style,omitempty"`
|
|
BigTitle string `json:"big_title,omitempty"`
|
|
BigBody string `json:"big_body,omitempty"`
|
|
ClearAfter time.Duration `json:"auto_clear,omitempty"`
|
|
NotifyId int `json:"notify_id,omitempty"`
|
|
Group string `json:"group,omitempty"`
|
|
Badge *NotificationBadge `json:"badge,omitempty"`
|
|
Ticker string `json:"ticker,omitempty"`
|
|
When string `json:"when,omitempty"`
|
|
Importance NotificationImportance `json:"importance,omitempty"`
|
|
UseDefaultVibrate bool `json:"use_default_vibrate,omitempty"`
|
|
UseDefaultLight bool `json:"use_default_light,omitempty"`
|
|
VibrateTimings []string `json:"vibrate_config,omitempty"`
|
|
Visibility NotificationVisibility `json:"visibility,omitempty"`
|
|
LightSettings *LightSettings `json:"light_settings,omitempty"`
|
|
ShowInForeground bool `json:"foreground_show,omitempty"`
|
|
ProfileId string `json:"profile_id,omitempty"`
|
|
InboxContent []string `json:"inbox_content,omitempty"`
|
|
Buttons []ActionButton `json:"buttons,omitempty"`
|
|
}
|
|
|
|
type MessageLocalization struct {
|
|
TitleKey map[string]string `json:"title_key"`
|
|
BodyKey map[string]string `json:"body_key"`
|
|
}
|
|
|
|
type NotificationStyle uint8
|
|
|
|
const (
|
|
NotificationStyle_Default NotificationStyle = 0
|
|
NotificationStyle_Large NotificationStyle = 1
|
|
NotificationStyle_Inbox NotificationStyle = 3
|
|
)
|
|
|
|
type NotificationImportance string
|
|
|
|
const (
|
|
NotificationImportance_Low NotificationImportance = "LOW"
|
|
NotificationImportance_Normal NotificationImportance = "NORMAL"
|
|
)
|
|
|
|
type NotificationVisibility string
|
|
|
|
const (
|
|
NotificationVisibility_Unspecified NotificationVisibility = "VISIBILITY_UNSPECIFIED"
|
|
NotificationVisibility_Public NotificationVisibility = "PUBLIC"
|
|
NotificationVisibility_Secret NotificationVisibility = "SECRET"
|
|
NotificationVisibility_Private NotificationVisibility = "PRIVATE"
|
|
)
|
|
|
|
type ActionButton struct {
|
|
Name string `json:"name"`
|
|
Type ButtonActionType `json:"action_type"`
|
|
IntentType IntentType `json:"intent_type,omitempty"`
|
|
Intent string `json:"intent,omitempty"`
|
|
Data json.RawMessage `json:"data,omitempty"`
|
|
}
|
|
|
|
type ButtonActionType uint8
|
|
|
|
const (
|
|
ButtonActionType_AppHome ButtonActionType = 0
|
|
ButtonActionType_AppPage ButtonActionType = 1
|
|
ButtonActionType_Url ButtonActionType = 2
|
|
ButtonActionType_Delete ButtonActionType = 3
|
|
ButtonActionType_Share ButtonActionType = 4
|
|
)
|
|
|
|
type IntentType uint8
|
|
|
|
const (
|
|
IntentType_Intent IntentType = 0
|
|
IntentType_Action IntentType = 1
|
|
)
|
|
|
|
type ClickAction struct {
|
|
Type ClickActionType `json:"type"`
|
|
Intent string `json:"intent,omitempty"`
|
|
Url string `json:"url,omitempty"`
|
|
Action string `json:"action,omitempty"`
|
|
}
|
|
|
|
type ClickActionType uint8
|
|
|
|
const (
|
|
ClickActionType_AppPage ClickActionType = 1
|
|
ClickActionType_Url ClickActionType = 2
|
|
ClickActionType_StartApp ClickActionType = 3
|
|
)
|
|
|
|
type NotificationBadge struct {
|
|
ActivityClass string `json:"class"`
|
|
AddNum uint8 `json:"add_num,omitempty"`
|
|
SetNum uint8 `json:"set_num,omitempty"`
|
|
}
|
|
|
|
type LightSettings struct {
|
|
Color Color `json:"color"`
|
|
OnDuration string `json:"light_on_duration"`
|
|
OffDuration string `json:"light_off_duration"`
|
|
}
|
|
|
|
type Color struct {
|
|
Red float32 `json:"red"`
|
|
Green float32 `json:"green"`
|
|
Blue float32 `json:"blue"`
|
|
Alpha float32 `json:"alpha"`
|
|
}
|
|
|
|
type ApnsConfig struct {
|
|
Headers *ApnsHeaders `json:"headers,omitempty"`
|
|
Notification ApnsNotification `json:"payload"`
|
|
HmsOptions ApnsHmsOptions `json:"hms_options"`
|
|
}
|
|
|
|
// TODO
|
|
type ApnsHeaders struct{}
|
|
|
|
// TODO
|
|
type ApnsNotification struct{}
|
|
|
|
type ApnsHmsOptions struct {
|
|
UserType ApnsUserType `json:"target_user_type"`
|
|
}
|
|
|
|
type ApnsUserType uint8
|
|
|
|
const (
|
|
ApnsUserType_Test ApnsUserType = 1
|
|
ApnsUserType_Formal ApnsUserType = 2
|
|
ApnsUserType_VoIP ApnsUserType = 3
|
|
)
|
|
|
|
type WebPushConfig struct {
|
|
Headers *WebPushHeaders `json:"headers,omitempty"`
|
|
Notification WebPushNotification `json:"notification"`
|
|
HmsOptions *WebPushHmsOptions `json:"hms_options,omitempty"`
|
|
}
|
|
|
|
type WebPushHeaders struct {
|
|
Ttl string `json:"ttl"`
|
|
Topic string `json:"topic"`
|
|
}
|
|
|
|
// TODO
|
|
type WebPushNotification struct{}
|
|
|
|
type WebPushHmsOptions struct {
|
|
Link string `json:"link"`
|
|
}
|