From 23935fcb8b9a8c73574218b54b84a2ff3771bd17 Mon Sep 17 00:00:00 2001 From: jiangyong27 Date: Mon, 29 Jan 2024 22:13:11 +0800 Subject: [PATCH] push --- go.mod | 7 +- push/getui.go | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/util.go | 11 +++ 3 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 push/getui.go diff --git a/go.mod b/go.mod index 175d4d5..57a5b69 100644 --- a/go.mod +++ b/go.mod @@ -6,15 +6,16 @@ require ( github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 github.com/gin-gonic/gin v1.9.1 github.com/gomodule/redigo v1.8.9 + github.com/google/uuid v1.6.0 github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/minio/minio-go v6.0.14+incompatible github.com/qiniu/go-sdk/v7 v7.19.0 github.com/sirupsen/logrus v1.9.3 github.com/smbrave/goutil v0.0.0-20240105134047-64fe0dfafba2 - github.com/spf13/cast v1.5.0 + github.com/spf13/cast v1.6.0 github.com/wechatpay-apiv3/wechatpay-go v0.2.18 golang.org/x/crypto v0.9.0 - gorm.io/gorm v1.25.5 + gorm.io/gorm v1.25.6 ) require ( @@ -42,7 +43,7 @@ require ( golang.org/x/arch v0.3.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/push/getui.go b/push/getui.go new file mode 100644 index 0000000..b84cce1 --- /dev/null +++ b/push/getui.go @@ -0,0 +1,193 @@ +package push + +import ( + "encoding/json" + "errors" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/smbrave/goutil" + "github.com/spf13/cast" + "gitlab.batiao8.com/open/gosdk/util" + "time" +) + +type GetuiConfig struct { + AppId string + AppKey string + MasterSecret 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 + Message string +} + +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"]) + if code != 0 { + log.Errorf("json[%s] rsp error", string(rspBody)) + return nil, errors.New(string(rspBody)) + } + data := cast.ToStringMap(result["data"]) + 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 := util.HttpPostJson(reqUrl, nil, reqBody) + if err != nil { + log.Errorf("goutil http post error :%s", 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 + return g.token +} + +func (g *Getui) Push(req *GetuiMessage) error { + 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": "startapp", + }, + } + reqBody, _ := json.Marshal(params) + _, err := util.HttpPostJson(reqUrl, map[string]string{"token": g.Token()}, reqBody) + if err != nil { + log.Errorf("goutil http post error :%s", err.Error()) + return err + } + + return 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 := util.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 + } + if _, ok := result[cid]; !ok { + return nil, errors.New("not cid exist") + } + + 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 := util.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, errors.New("not cid exist") + } + 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 +} diff --git a/util/util.go b/util/util.go index 700d0c3..af35bf9 100644 --- a/util/util.go +++ b/util/util.go @@ -1,6 +1,8 @@ package util import ( + "crypto/sha256" + "encoding/hex" "fmt" "github.com/spf13/cast" ) @@ -16,3 +18,12 @@ func CutTail(str string, length int) string { func FloatCut(f float64) float64 { return cast.ToFloat64(fmt.Sprintf("%.2f", f)) } + +func Sha256(s string) string { + + hash := sha256.New() + + hash.Write([]byte(s)) + hashValue := hash.Sum(nil) + return hex.EncodeToString(hashValue) +}