123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- 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
- }
|