This commit is contained in:
richboo111
2023-03-21 15:26:28 +08:00
7 changed files with 326 additions and 327 deletions

View File

@@ -6,7 +6,7 @@ import (
) )
func TestAscriptionPlace(t *testing.T) { func TestAscriptionPlace(t *testing.T) {
p, err := Find("13146872779") p, err := Find("17146563473")
fmt.Println(p) fmt.Println(p)
fmt.Println(err) fmt.Println(err)
} }

View File

@@ -1,10 +1,9 @@
package uinapp package uinapp
import ( import (
"git.rosy.net.cn/baseapi/utils" "fmt"
"git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals"
"testing" "testing"
"time"
) )
var ( var (
@@ -18,55 +17,45 @@ func TestGetToken(t *testing.T) {
globals.SugarLogger.Debug("result := %v", err) globals.SugarLogger.Debug("result := %v", err)
} }
func TestSendMsgAndroid(t *testing.T) { func TestCidSend(t *testing.T) {
api.SendMsgByUinApp(SendMsgReq{ err := api.SendMsgByUinApp(map[string]interface{}{
RequestId: utils.Int64ToStr(time.Now().UnixNano()), "request_id": "12345237568ydfd2",
GroupName: "", "settings": map[string]interface{}{
Audience: AudienceCid{CId: []string{android}}, "ttl": 7200000,
Settings: SendMsgSetting{}, },
PushMessage: PushMessageDetail{ "audience": map[string]interface{}{
Notification: PushMessageDetailNotification{ "cid": []string{"808ba3cebba05782f82063d590b738a3"},
Title: "测试消息推送[个推推送消息参数]", },
Body: "吃早饭了没得[个推推送消息参数]", "push_message": map[string]interface{}{
BigText: "这是个什么东西[个推推送消息参数]", "transmission": "{'type':'new','title':'火车南站店','content':'老板,您来新订单了,请尽快接单!'}",
BigImage: "", },
Logo: "", "push_channel": map[string]interface{}{
LogoUrl: "", "android": map[string]interface{}{
ChannelId: "", "ups": map[string]interface{}{
ChannelName: "", "transmission": "厂商透传消息",
ChannelLevel: 0, },
ClickType: "startapp", },
Intent: "", "ios": map[string]interface{}{
Url: "", "type": "notify",
Payload: "", "payload": "{'type':'new','title':'火车南站店','content':'老板,您来新订单了,请尽快接单!'}",
NotifyId: 0, "aps": map[string]interface{}{
RingName: "", "alert": map[string]interface{}{
BadgeAddNum: 0, "title": "火车南站店",
ThreadId: "", "body": "新订单",
},
"content-available": 0,
"sound": "自定义铃声设置为包含后缀名的完整文件名示例值ring.mp3",
"category": "在客户端通知栏触发特定的action和button显示",
},
"auto_badge": "+1",
"multimedia": []map[string]interface{}{
{
"url": "https://xxx",
"type": 1,
"only_wifi": false},
},
}, },
}, },
PushChannel: PushChannelDetail{
//Ios: IosApsDetail{},
Android: AndroidPushChannelDetail{Ups: AndroidPushChannelUps{
Notification: AndroidPushChannelNotification{
Title: "测试消息推送[厂商推送消息参数]",
Body: "吃早饭了没得[厂商推送消息参数]",
ClickType: "startapp",
Intent: "",
Url: "",
NotifyId: 0,
},
Transmission: "",
Revoke: struct {
OldTaskId string `json:"old_task_id"`
}{},
Options: struct {
Constraint string `json:"constraint"`
Key string `json:"key"`
Value interface{} `json:"value"`
}{},
}},
Mp: MpPushChannelDetail{},
},
}) })
fmt.Println(err)
} }

View File

@@ -109,17 +109,19 @@ type IosPushChannelAps struct {
ContentState struct{} `json:"content-state"` // type为liveactivity时必填 ContentState struct{} `json:"content-state"` // type为liveactivity时必填
} }
type MultimediaIos struct {
Url string `json:"url"` // 多媒体资源地址
TypeMultimedia int64 `json:"type"` // 资源类型1.图片2.音频3.视频)
OnlyWifi bool `json:"only_wifi"` // 是否只在wifi环境下加载如果设置成true,但未使用wifi时会展示成普通通知
}
type IosApsDetail struct { type IosApsDetail struct {
NotifyType string `json:"type"` // notify默认通知消息 voipvoip语音推送notifyapns通知消息liveactivity灵动岛推送(不支持p12证书) NotifyType string `json:"type"` // notify默认通知消息 voipvoip语音推送notifyapns通知消息liveactivity灵动岛推送(不支持p12证书)
Aps IosPushChannelAps `json:"aps"` // 推送通知消息内容 Aps IosPushChannelAps `json:"aps"` // 推送通知消息内容
AutoBadge string `json:""` // 用于计算icon上显示的数字还可以实现显示数字的自动增减如“+1”、 “-1”、 “1” 等计算结果将覆盖badge AutoBadge string `json:""` // 用于计算icon上显示的数字还可以实现显示数字的自动增减如“+1”、 “-1”、 “1” 等计算结果将覆盖badge
Payload string `json:"payload"` // 增加自定义的数据 Payload string `json:"payload"` // 增加自定义的数据
Multimedia []struct { // 多媒体设置 Multimedia []MultimediaIos `json:"multimedia"` // 多媒体设置
Url string `json:"url"` // 多媒体资源地址 ApnsCollapseId string `json:"apns-collapse-id"` // 使用相同的apns-collapse-id可以覆盖之前的消息
TypeMultimedia int64 `json:"type"` // 资源类型1.图片2.音频3.视频)
OnlyWifi bool `json:"only_wifi"` // 是否只在wifi环境下加载如果设置成true,但未使用wifi时会展示成普通通知
} `json:"multimedia"` // 多媒体设置
ApnsCollapseId string `json:"apns-collapse-id"` // 使用相同的apns-collapse-id可以覆盖之前的消息
} }
type AndroidPushChannelUps struct { type AndroidPushChannelUps struct {

View File

@@ -1,9 +1,12 @@
package uinapp package uinapp
import ( import (
"encoding/json"
"errors" "errors"
"fmt"
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"net/http" "net/http"
"strings"
) )
type SendMsgRes struct { type SendMsgRes struct {
@@ -16,13 +19,15 @@ type SendMsgRes struct {
} `json:"data"` } `json:"data"`
} }
func (a *API) SendMsgByUinApp(parma SendMsgReq) error { func (a *API) SendMsgByUinApp(parma map[string]interface{}) error {
if err := a.CheckTokenIsExpire(); err != nil { if _, err := a.CheckTokenIsExpire(); err != nil {
return err return err
} }
result, err := a.AccessAPI(BaseUrl+a.appId, PushMsgByCid, http.MethodPost, utils.Struct2MapByJson(parma)) data, _ := json.Marshal(parma)
if err != nil { fmt.Println(string(data))
result, err := a.AccessAPI(BaseUrl+a.appId, PushMsgByCid, http.MethodPost, parma)
if err != nil && !strings.Contains(err.Error(), "success") {
return err return err
} }
@@ -30,7 +35,7 @@ func (a *API) SendMsgByUinApp(parma SendMsgReq) error {
if err := utils.Map2StructByJson(result, &sendMsgRes, false); err != nil { if err := utils.Map2StructByJson(result, &sendMsgRes, false); err != nil {
return err return err
} }
if sendMsgRes.Code != 200 { if sendMsgRes.Code != 0 {
return errors.New(sendMsgRes.Msg) return errors.New(sendMsgRes.Msg)
} }
return nil return nil

View File

@@ -122,10 +122,11 @@ func (a *API) GetUinAppToken() error {
// CheckTokenIsExpire 校验头肯是否过期 // CheckTokenIsExpire 校验头肯是否过期
// 注鉴权接口每分钟最大调用量为100次每天最大调用量为10万次建议开发者妥善管理token以免达到限制影响推送.感觉不做缓存也够用了! // 注鉴权接口每分钟最大调用量为100次每天最大调用量为10万次建议开发者妥善管理token以免达到限制影响推送.感觉不做缓存也够用了!
func (a *API) CheckTokenIsExpire() error { func (a *API) CheckTokenIsExpire() (string, error) {
// 没有token或者token过期了 // 没有token或者token过期了
if a.token == "" || a.expireTime == "" || utils.Str2Int64(a.expireTime) < (time.Now().UnixNano()/1e6) { if a.token == "" || a.expireTime == "" || utils.Str2Int64(a.expireTime) < (time.Now().UnixNano()/1e6) {
return a.GetUinAppToken() a.GetUinAppToken()
return a.token, nil
} }
return nil return a.token, nil
} }

View File

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

View File

@@ -1,43 +1,44 @@
package unipushapi package unipushapi
import ( //
"testing" //import (
// "testing"
"git.rosy.net.cn/baseapi" //
"git.rosy.net.cn/baseapi/utils" // "git.rosy.net.cn/baseapi"
"go.uber.org/zap" // "git.rosy.net.cn/baseapi/utils"
) // "go.uber.org/zap"
//)
var ( //
api *API //var (
sugarLogger *zap.SugaredLogger // api *API
) // sugarLogger *zap.SugaredLogger
//)
func init() { //
logger, _ := zap.NewDevelopment() //func init() {
sugarLogger = logger.Sugar() // logger, _ := zap.NewDevelopment()
baseapi.Init(sugarLogger) // sugarLogger = logger.Sugar()
api = New("5lyyrvHODG6wC8Sdr3a9h", "iFrkUDmR2g5eqQpfh2kQ57", "WTn53qd6WAAdLMXfmXvzb7", "dGZcR0XGGg7H5Pd7FR3n47") // baseapi.Init(sugarLogger)
api.CBSetToken("cf74937695849a89bcb414e49f03702416b49024a49e7f62570280f99eb63b58") // api = New("5lyyrvHODG6wC8Sdr3a9h", "iFrkUDmR2g5eqQpfh2kQ57", "WTn53qd6WAAdLMXfmXvzb7", "dGZcR0XGGg7H5Pd7FR3n47")
// ef364b677911fa64d41a25d22d5e155065c4898046be65ddd627fa6c8cd87c2e // api.CBSetToken("cf74937695849a89bcb414e49f03702416b49024a49e7f62570280f99eb63b58")
} // // ef364b677911fa64d41a25d22d5e155065c4898046be65ddd627fa6c8cd87c2e
//}
func TestCBRetrieveToken(t *testing.T) { //
result, err := api.CBRetrieveToken() //func TestCBRetrieveToken(t *testing.T) {
if err != nil { // result, err := api.CBRetrieveToken()
t.Fatal(err.Error()) // if err != nil {
} // t.Fatal(err.Error())
t.Log(utils.Format4Output(result, false)) // }
} // t.Log(utils.Format4Output(result, false))
//}
func TestPushToSingle(t *testing.T) { //
result, err := api.PushToSingle("8aa96ba065a29a0135c5151819fb1666", false, &Notification{ //func TestPushToSingle(t *testing.T) {
Title: "测试", // result, err := api.PushToSingle("8aa96ba065a29a0135c5151819fb1666", false, &Notification{
Body: "测测测", // Title: "测试",
}) // Body: "测测测",
if err != nil { // })
t.Fatal(err.Error()) // if err != nil {
} // t.Fatal(err.Error())
t.Log(utils.Format4Output(result, false)) // }
// RASS_0911_1517001ff419d4699a0be17ac3f04a54 // t.Log(utils.Format4Output(result, false))
} // // RASS_0911_1517001ff419d4699a0be17ac3f04a54
//}