package unipushapi import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "net/http" "strings" "sync" "time" "git.rosy.net.cn/baseapi/platformapi" "git.rosy.net.cn/baseapi/utils" ) const ( prodURL = "https://restapi.getui.com/v2" authAction = "auth" SuccessOffLine = "successed_offline" SuccessONLine = "successed_online" ) type TokenInfo struct { ExpireTime string `json:"expire_time"` Token string `json:"token"` } type API struct { token string appID string appKey string appSecret string masterSecret string client *http.Client config *platformapi.APIConfig locker sync.RWMutex } func New(appID, appKey, appSecret, masterSecret string, config ...*platformapi.APIConfig) *API { curConfig := platformapi.DefAPIConfig if len(config) > 0 { curConfig = *config[0] } return &API{ appID: appID, appKey: appKey, appSecret: appSecret, masterSecret: masterSecret, client: &http.Client{Timeout: curConfig.ClientTimeout}, config: &curConfig, } } func (a *API) signParam(appKey string, time int64, masterSecret string) (sig string) { //方法一: //创建一个基于SHA256算法的hash.Hash接口的对象 hash := sha256.New() //输入数据 hash.Write([]byte(appKey + utils.Int64ToStr(time) + masterSecret)) //计算哈希值 bytes := hash.Sum(nil) //将字符串编码为16进制格式,返回字符串 hashCode := hex.EncodeToString(bytes) //返回哈希值 return hashCode } func (a *API) AccessAPI(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) { params := make(map[string]interface{}) time := time.Now().UnixNano() / 1e6 params["timestamp"] = utils.Int64ToStr(time) params["appkey"] = a.appKey params["sign"] = a.signParam(a.appKey, time, a.masterSecret) result, _ := json.MarshalIndent(params, "", " ") fullURL := utils.GenerateGetURL(prodURL+"/"+a.appID, action, nil) err = platformapi.AccessPlatformAPIWithRetry(a.client, func() *http.Request { request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(result))) if action != authAction { request.Header.Set("token", a.CBGetToken()) } request.Header.Set("Content-Type", "application/json;charset=utf-8") return request }, a.config, func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) { if jsonResult1 == nil { return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil") } if err == nil { if jsonResult1["msg"].(string) != "success" { errLevel = platformapi.ErrLevelGeneralFail err = utils.NewErrorCode(jsonResult1["msg"].(string), utils.Int64ToStr(utils.MustInterface2Int64(jsonResult1["code"]))) } retVal = jsonResult1["data"].(map[string]interface{}) } return errLevel, err }) return retVal, err } func (a *API) AccessAPI2(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) { result, _ := json.MarshalIndent(bizParams, "", " ") fullURL := utils.GenerateGetURL(prodURL+"/"+a.appID, action, nil) err = platformapi.AccessPlatformAPIWithRetry(a.client, func() *http.Request { request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(result))) request.Header.Set("token", a.CBGetToken()) request.Header.Set("Content-Type", "application/json;charset=utf-8") return request }, a.config, func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) { if jsonResult1 == nil { return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil") } if err == nil { if jsonResult1["msg"].(string) != "success" { errLevel = platformapi.ErrLevelGeneralFail err = utils.NewErrorCode(jsonResult1["msg"].(string), utils.Int64ToStr(utils.MustInterface2Int64(jsonResult1["code"]))) } retVal = jsonResult1 } return errLevel, err }) return retVal, err } func (a *API) CBSetToken(newToken string) bool { curToken := a.CBGetToken() if curToken != newToken { a.locker.Lock() defer a.locker.Unlock() a.token = newToken return true } return false } func (a *API) CBGetToken() string { a.locker.RLock() defer a.locker.RUnlock() return a.token } func (a *API) CBRetrieveToken() (tokenInfo *TokenInfo, err error) { result, err := a.AccessAPI("auth", nil) if err != nil { return nil, err } tokenInfo = &TokenInfo{ Token: utils.Interface2String(result["token"]), ExpireTime: utils.Interface2String(result["expire_time"]), } a.CBSetToken(tokenInfo.Token) return tokenInfo, nil } type PushMsg struct { Notificatio Notification `json:"notification"` } type Notification struct { Title string `json:"title"` Body string `json:"body"` ClickType string `json:"click_type"` URL string `json:"url"` } type Audience struct { CID []string `json:"cid"` } type Settings struct { TTL int `json:"ttl"` } type Transmission struct { Transmission string `json:"transmission"` } func (a *API) PushToSingle(cid string, transmission bool, notification *Notification) (status string, err error) { params := map[string]interface{}{ "request_id": utils.GetUUID(), "audience": &Audience{ []string{cid}, }, } if !transmission { params["push_message"] = &PushMsg{ Notificatio: Notification{ Title: notification.Title, Body: notification.Body, ClickType: "startapp", //打开应用首页 }, } } else { params["push_message"] = &Transmission{ Transmission: notification.Body, } } result2, err := a.AccessAPI2("push/single/cid", params) if err != nil { return "", err } else { for _, v := range result2["data"].(map[string]interface{}) { for _, vv := range v.(map[string]interface{}) { if vv.(string) != "" { status = vv.(string) } } } } return status, nil }