135 lines
4.0 KiB
Go
135 lines
4.0 KiB
Go
|
package huawei
|
|||
|
|
|||
|
// http://developer.huawei.com/consumer/cn/service/hms/catalog/huaweipush.html?page=hmssdk_huaweipush_api_reference_s2
|
|||
|
|
|||
|
import (
|
|||
|
"encoding/json"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"io/ioutil"
|
|||
|
"net/http"
|
|||
|
"net/url"
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
"time"
|
|||
|
|
|||
|
"go-common/library/log"
|
|||
|
"go-common/library/stat"
|
|||
|
"go-common/library/stat/prom"
|
|||
|
)
|
|||
|
|
|||
|
const (
|
|||
|
_pushURL = "https://api.push.hicloud.com/pushsend.do"
|
|||
|
_nspSvc = "openpush.message.api.send"
|
|||
|
_ver = "1" // current SDK version
|
|||
|
// ResponseCodeSuccess success code
|
|||
|
ResponseCodeSuccess = "80000000"
|
|||
|
// ResponseCodeSomeTokenInvalid some tokens failed
|
|||
|
ResponseCodeSomeTokenInvalid = "80100000"
|
|||
|
// ResponseCodeAllTokenInvalid all tokens failed
|
|||
|
ResponseCodeAllTokenInvalid = "80100002"
|
|||
|
// ResponseCodeAllTokenInvalidNew .
|
|||
|
ResponseCodeAllTokenInvalidNew = "80300007"
|
|||
|
)
|
|||
|
|
|||
|
var (
|
|||
|
// ErrLimit .
|
|||
|
ErrLimit = errors.New("触发华为系统级流控")
|
|||
|
)
|
|||
|
|
|||
|
// Client huawei push http client.
|
|||
|
type Client struct {
|
|||
|
Access *Access
|
|||
|
HTTPClient *http.Client
|
|||
|
Stats stat.Stat
|
|||
|
SDKCtx string
|
|||
|
Package string
|
|||
|
}
|
|||
|
|
|||
|
// ver huawei push service version.
|
|||
|
type ver struct {
|
|||
|
Ver string `json:"ver"`
|
|||
|
AppID string `json:"appId"`
|
|||
|
}
|
|||
|
|
|||
|
// NewClient new huawei push HTTP client.
|
|||
|
func NewClient(pkg string, a *Access, timeout time.Duration) *Client {
|
|||
|
ctx, _ := json.Marshal(ver{Ver: _ver, AppID: a.AppID})
|
|||
|
return &Client{
|
|||
|
Access: a,
|
|||
|
HTTPClient: &http.Client{Timeout: timeout},
|
|||
|
Stats: prom.HTTPClient,
|
|||
|
SDKCtx: string(ctx),
|
|||
|
Package: pkg,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Push push notifications.
|
|||
|
access_token: 必选,使用OAuth2进行鉴权时的ACCESSTOKEN
|
|||
|
nsp_ts: 必选,服务请求时间戳,自GMT 时间 1970-1-1 0:0:0至今的秒数。如果传入的时间与服务器时间相 差5分钟以上,服务器可能会拒绝请求。
|
|||
|
nsp_svc: 必选, 本接口固定为openpush.message.api.send
|
|||
|
device_token_list: 以半角逗号分隔的华为PUSHTOKEN列表,单次最多只是1000个
|
|||
|
expire_time: 格式ISO 8601[6]:2013-06-03T17:30,采用本地时间精确到分钟
|
|||
|
payload: 描述投递消息的JSON结构体,描述PUSH消息的:类型、内容、显示、点击动作、报表统计和扩展信 息。具体参考下面的详细说明。
|
|||
|
*/
|
|||
|
func (c *Client) Push(payload *Message, tokens []string, expire time.Time) (response *Response, err error) {
|
|||
|
now := time.Now()
|
|||
|
if c.Stats != nil {
|
|||
|
defer func() {
|
|||
|
c.Stats.Timing(_pushURL, int64(time.Since(now)/time.Millisecond))
|
|||
|
log.Info("huawei stats timing: %v", int64(time.Since(now)/time.Millisecond))
|
|||
|
if err != nil {
|
|||
|
c.Stats.Incr(_pushURL, "failed")
|
|||
|
}
|
|||
|
}()
|
|||
|
}
|
|||
|
pl, _ := payload.SetPkg(c.Package).JSON()
|
|||
|
reqURL := _pushURL + "?nsp_ctx=" + url.QueryEscape(c.SDKCtx)
|
|||
|
tokenStr, _ := json.Marshal(tokens)
|
|||
|
params := url.Values{}
|
|||
|
params.Add("access_token", c.Access.Token)
|
|||
|
params.Add("nsp_ts", strconv.FormatInt(now.Unix(), 10))
|
|||
|
params.Add("nsp_svc", _nspSvc)
|
|||
|
params.Add("device_token_list", string(tokenStr))
|
|||
|
params.Add("expire_time", expire.Format("2006-01-02T15:04"))
|
|||
|
params.Add("payload", pl)
|
|||
|
req, err := http.NewRequest(http.MethodPost, reqURL, strings.NewReader(params.Encode()))
|
|||
|
if err != nil {
|
|||
|
log.Error("http.NewRequest() error(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|||
|
req.Header.Set("Connection", "Keep-Alive")
|
|||
|
res, err := c.HTTPClient.Do(req)
|
|||
|
if err != nil {
|
|||
|
log.Error("HTTPClient.Do() error(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
defer res.Body.Close()
|
|||
|
if res.StatusCode == http.StatusServiceUnavailable {
|
|||
|
return nil, ErrLimit
|
|||
|
}
|
|||
|
if res.StatusCode != http.StatusOK {
|
|||
|
err = fmt.Errorf("huawei Push http code(%d)", res.StatusCode)
|
|||
|
return
|
|||
|
}
|
|||
|
response = &Response{}
|
|||
|
nspStatus := res.Header.Get("NSP_STATUS")
|
|||
|
if nspStatus != "" {
|
|||
|
log.Error("push huawei system error, NSP_STATUS(%s)", nspStatus)
|
|||
|
response.Code = nspStatus
|
|||
|
response.Msg = "NSP_STATUS error"
|
|||
|
return
|
|||
|
}
|
|||
|
bs, err := ioutil.ReadAll(res.Body)
|
|||
|
if err != nil {
|
|||
|
log.Error("ioutil.ReadAll() error(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
if err = json.Unmarshal(bs, &response); err != nil {
|
|||
|
log.Error("json decode body(%s) error(%v)", string(bs), err)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|