package push import ( "encoding/json" "errors" "fmt" "git.u8t.cn/open/gosdk/util" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" "github.com/spf13/cast" "time" ) var ( ErrCidNotExist = errors.New("cid not exist") ) type GetuiConfig struct { AppId string AppKey string MasterSecret string XMChannelId string } type GetuiStatus struct { Status string LastLoginTime int64 } type GetuiDetail struct { ClientAppId string PackageName string DeviceToken string PhoneType int PhoneModel string NotificationSwitch bool CreateTime int64 LoginFreq int Brand string } type GetuiMessage struct { Cid string Title string //通知消息标题,长度 ≤ 50字 Message string //通知消息内容,长度 ≤ 256字 NotifyId string Intent string } type GetuiPushRsp struct { TaskId string `json:"task_id"` Status string `json:"status"` } type Getui struct { config *GetuiConfig token string tokenExpire int64 } func NewGetui(c *GetuiConfig) *Getui { return &Getui{ config: c, tokenExpire: 0, } } func (g *Getui) getResult(rspBody []byte) (map[string]interface{}, error) { result := make(map[string]interface{}) if err := json.Unmarshal(rspBody, &result); err != nil { log.Errorf("json[%s] error :%s", string(rspBody), err.Error()) return nil, err } code := cast.ToInt(result["code"]) msg := cast.ToString(result["msg"]) data := cast.ToStringMap(result["data"]) if code == 20001 && msg == "successed_ignore" { return data, nil } if code != 0 { log.Errorf("json[%s] rsp error", string(rspBody)) return nil, errors.New(string(rspBody)) } return data, nil } func (g *Getui) Token() string { nowTime := time.Now().Unix() if nowTime < g.tokenExpire { return g.token } timestamp := cast.ToString(time.Now().UnixMilli()) signStr := fmt.Sprintf("%s%s%s", g.config.AppKey, timestamp, g.config.MasterSecret) reqUrl := fmt.Sprintf("https://restapi.getui.com/v2/%s/auth", g.config.AppId) params := make(map[string]string) params["timestamp"] = timestamp params["appkey"] = g.config.AppKey params["sign"] = util.Sha256(signStr) reqBody, _ := json.Marshal(params) rspBody, err := HttpPostJson(reqUrl, nil, reqBody) if err != nil { log.Errorf("http post [%s] error :%s", string(reqBody), err.Error()) return "" } result, err := g.getResult(rspBody) if err != nil { log.Errorf("get Result error :%s", err.Error()) return "" } token := cast.ToString(result["token"]) tokenExpire := cast.ToInt64(result["expire_time"]) g.token = token g.tokenExpire = tokenExpire / 1000 return g.token } func (g *Getui) Push(req *GetuiMessage) (*GetuiPushRsp, error) { if len(req.Title) > 50 { req.Title = string([]rune(req.Title)[:16]) } if len(req.Message) > 256 { req.Message = string([]rune(req.Message)[:80]) } reqUrl := fmt.Sprintf("https://restapi.getui.com/v2/%s/push/single/cid", g.config.AppId) params := make(map[string]interface{}) params["request_id"] = time.Now().Format("20060102150405") + "_" + goutil.RandomStr(6) params["settings"] = map[string]interface{}{ "ttl": 2 * 3600 * 24 * 1000, } params["audience"] = map[string]interface{}{ "cid": []string{req.Cid}, } params["push_message"] = map[string]interface{}{ "notification": map[string]interface{}{ "title": req.Title, "body": req.Message, "channel_level": 4, "click_type": "intent", "notify_id": cast.ToInt64(req.NotifyId), "intent": req.Intent, }, } params["push_channel"] = map[string]interface{}{ "android": map[string]interface{}{ "ups": map[string]interface{}{ "notification": map[string]interface{}{ "title": req.Title, "body": req.Message, "click_type": "intent", "notify_id": cast.ToInt64(req.NotifyId), "intent": req.Intent, }, "options": map[string]interface{}{ "ALL": map[string]interface{}{ "channel": "default", }, "XM": map[string]interface{}{ "/extra.channel_id": g.config.XMChannelId, }, "VV": map[string]interface{}{ "/category": "ACCOUNT", }, }, }, }, } reqBody, err := json.Marshal(params) if err != nil { log.Errorf("json.Marshal error :%s", err.Error()) return nil, err } rspBody, err := HttpPostJson(reqUrl, map[string]string{"token": g.Token()}, reqBody) if err != nil { log.Errorf("goutil http post error :%s", err.Error()) return nil, err } data, err := g.getResult(rspBody) if err != nil { log.Errorf("get result[%s] error :%s", rspBody, err.Error()) return nil, err } rsp := new(GetuiPushRsp) for taskId, task := range data { rsp.TaskId = taskId cidStatus := cast.ToStringMap(task) for _, v := range cidStatus { rsp.Status = cast.ToString(v) } } return rsp, nil } func (g *Getui) GetUserStatus(cid string) (*GetuiStatus, error) { reqUrl := fmt.Sprintf("https://restapi.getui.com/v2/%s/user/status/%s", g.config.AppId, cid) rspBody, err := HttpGet(reqUrl, map[string]string{ "token": g.Token(), }) if err != nil { log.Warningf("goutil http get error :%s", err.Error()) return nil, err } result, err := g.getResult(rspBody) if err != nil { log.Errorf("get result[%s] error :%s", string(rspBody), err.Error()) return nil, err } if _, ok := result[cid]; !ok { return nil, ErrCidNotExist } status := new(GetuiStatus) cidResult := cast.ToStringMap(result[cid]) status.Status = cast.ToString(cidResult["status"]) status.Status = cast.ToString(cidResult["status"]) status.LastLoginTime = cast.ToInt64(cidResult["last_login_time"]) / 1000 return status, nil } func (g *Getui) GetUserDetail(cid string) (*GetuiDetail, error) { reqUrl := fmt.Sprintf("https://restapi.getui.com/v2/%s/user/detail/%s", g.config.AppId, cid) rspBody, err := HttpGet(reqUrl, map[string]string{ "token": g.Token(), }) if err != nil { log.Errorf("goutil http get error :%s", err.Error()) return nil, err } result, err := g.getResult(rspBody) if err != nil { log.Errorf("get result[%s] error :%s", string(rspBody), err.Error()) return nil, err } validCids := cast.ToStringMap(result["validCids"]) if _, ok := validCids[cid]; !ok { return nil, ErrCidNotExist } cidDetail := cast.ToStringMap(validCids[cid]) detail := new(GetuiDetail) detail.ClientAppId = cast.ToString(cidDetail["client_app_id"]) detail.PackageName = cast.ToString(cidDetail["package_name"]) detail.DeviceToken = cast.ToString(cidDetail["device_token"]) detail.PhoneModel = cast.ToString(cidDetail["phone_model"]) detail.Brand = cast.ToString(cidDetail["brand"]) detail.PhoneType = cast.ToInt(cidDetail["phone_type"]) detail.LoginFreq = cast.ToInt(cidDetail["login_freq"]) detail.NotificationSwitch = cast.ToBool(cidDetail["notification_switch"]) return detail, nil }