@ -3,16 +3,16 @@ package getui
import (
import (
"Open_IM/internal/push"
"Open_IM/internal/push"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/db"
"Open_IM/pkg/common/db/cache"
//http2 "Open_IM/pkg/common/http"
"Open_IM/pkg/common/log"
"Open_IM/pkg/common/log"
"Open_IM/pkg/utils"
"Open_IM/pkg/utils"
"bytes"
"bytes"
"context"
"crypto/sha256"
"crypto/sha256"
"errors"
//"crypto/sha512"
"encoding/hex"
"encoding/hex"
"encoding/json"
"encoding/json"
"errors"
"io/ioutil"
"io/ioutil"
"net/http"
"net/http"
"strconv"
"strconv"
@ -20,166 +20,61 @@ import (
)
)
var (
var (
GetuiClient * Getui
TokenExpireError = errors . New ( "token expire" )
TokenExpireError = errors . New ( "token expire" )
)
)
const (
const (
PushURL = "/push/single/alias"
pushURL = "/push/single/alias"
AuthURL = "/auth"
authURL = "/auth"
TaskURL = "/push/list/message"
taskURL = "/push/list/message"
BatchPushURL = "/push/list/alias"
batchPushURL = "/push/list/alias"
)
func init ( ) {
GetuiClient = newGetuiClient ( )
}
type Getui struct { }
type GetuiCommonResp struct {
Code int ` json:"code" `
Msg string ` json:"msg" `
Data interface { } ` json:"data" `
}
type AuthReq struct {
Sign string ` json:"sign" `
Timestamp string ` json:"timestamp" `
Appkey string ` json:"appkey" `
}
type AuthResp struct {
ExpireTime string ` json:"expire_time" `
Token string ` json:"token" `
}
type TaskResp struct {
TaskID string ` json:"taskID" `
}
type Settings struct {
TTL * int64 ` json:"ttl" `
}
type Audience struct {
Alias [ ] string ` json:"alias" `
}
type PushMessage struct {
Notification * Notification ` json:"notification,omitempty" `
Transmission * string ` json:"transmission,omitempty" `
}
type PushChannel struct {
tokenExpire = 10001
Ios * Ios ` json:"ios" `
ttl = 0
Android * Android ` json:"android" `
)
}
type PushReq struct {
RequestID * string ` json:"request_id" `
Settings * Settings ` json:"settings" `
Audience * Audience ` json:"audience" `
PushMessage * PushMessage ` json:"push_message" `
PushChannel * PushChannel ` json:"push_channel" `
IsAsync * bool ` json:"is_async" `
Taskid * string ` json:"taskid" `
}
type Ios struct {
NotiType * string ` json:"type" `
AutoBadge * string ` json:"auto_badge" `
Aps struct {
Sound string ` json:"sound" `
Alert Alert ` json:"alert" `
} ` json:"aps" `
}
type Alert struct {
Title string ` json:"title" `
Body string ` json:"body" `
}
type Android struct {
Ups struct {
Notification Notification ` json:"notification" `
Options Options ` json:"options" `
} ` json:"ups" `
}
type Notification struct {
Title string ` json:"title" `
Body string ` json:"body" `
ChannelID string ` json:"channelID" `
ChannelName string ` json:"ChannelName" `
ClickType string ` json:"click_type" `
}
type Options struct {
HW struct {
DefaultSound bool ` json:"/message/android/notification/default_sound" `
ChannelID string ` json:"/message/android/notification/channel_id" `
Sound string ` json:"/message/android/notification/sound" `
Importance string ` json:"/message/android/notification/importance" `
} ` json:"HW" `
XM struct {
ChannelID string ` json:"/extra.channel_id" `
} ` json:"XM" `
VV struct {
Classification int ` json:"/classification" `
} ` json:"VV" `
}
type PushResp struct {
type Client struct {
cache cache . Cache
}
}
func new GetuiClient( ) * Getui {
func newClient ( cache cache . Cache ) * Client {
return & Getui{ }
return & Client { cache : cache }
}
}
func ( g * Getui ) Push ( userIDList [ ] string , title , detailContent , operationID string , opts push . PushOpts ) ( resp string , err error ) {
func ( g * Client ) Push ( ctx context . Context , userIDs [ ] string , title , content , operationID string , opts * push . Opts ) error {
token , err := db . DB . GetGetuiToken ( )
token , err := g . cache . GetGetuiToken ( ctx )
log . NewDebug ( operationID , utils . GetSelfFuncName ( ) , "token: " , token , userIDList )
if err != nil {
if err != nil {
log . NewError ( operationID , utils . GetSelfFuncName ( ) , "GetGetuiToken failed" , err . Error ( ) )
log . NewError ( operationID , utils . GetSelfFuncName ( ) , "GetGetuiToken failed" , err . Error ( ) )
}
}
if token == "" || err != nil {
if token == "" || err != nil {
token , err = g . getTokenAndSave2Redis ( operationID )
token , err = g . getTokenAndSave2Redis ( ctx )
if err != nil {
if err != nil {
log . NewError ( operationID , utils . GetSelfFuncName ( ) , "getTokenAndSave2Redis failed" , err . Error ( ) )
log . NewError ( operationID , utils . GetSelfFuncName ( ) , "getTokenAndSave2Redis failed" , err . Error ( ) )
return "" , utils . Wrap ( err , "" )
return utils . Wrap ( err , "" )
}
}
}
}
pushReq := newPushReq ( title , content )
pushReq := PushReq { PushMessage : & PushMessage { Notification : & Notification {
pushReq . setPushChannel ( title , content )
Title : title ,
pushResp := struct { } { }
Body : detailContent ,
if len ( userIDs ) > 1 {
ClickType : "startapp" ,
taskID , err := g . GetTaskID ( ctx , token , pushReq )
ChannelID : config . Config . Push . Getui . ChannelID ,
ChannelName : config . Config . Push . Getui . ChannelName ,
} } }
pushReq . setPushChannel ( title , detailContent )
pushResp := PushResp { }
if len ( userIDList ) > 1 {
taskID , err := g . GetTaskID ( operationID , token , pushReq )
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "GetTaskIDAndSave2Redis failed" )
return utils . Wrap ( err , "GetTaskIDAndSave2Redis failed" )
}
}
pushReq = PushReq { Audience : & Audience { Alias : userID Li st } }
pushReq = PushReq { Audience : & Audience { Alias : userIDs } }
var IsAsync = true
var IsAsync = true
pushReq . IsAsync = & IsAsync
pushReq . IsAsync = & IsAsync
pushReq . Task id = & taskID
pushReq . TaskID = & taskID
err = g . request ( B atchPushURL, pushReq , token , & pushResp , operationID )
err = g . request ( ctx , batchPushURL , pushReq , token , & pushResp )
} else {
} else {
reqID := utils . OperationIDGenerator ( )
reqID := utils . OperationIDGenerator ( )
pushReq . RequestID = & reqID
pushReq . RequestID = & reqID
pushReq . Audience = & Audience { Alias : [ ] string { userID Li st [ 0 ] } }
pushReq . Audience = & Audience { Alias : [ ] string { userIDs [ 0 ] } }
err = g . request ( P ushURL, pushReq , token , & pushResp , operationID )
err = g . request ( ctx , pushURL , pushReq , token , & pushResp )
}
}
switch err {
switch err {
case TokenExpireError :
case TokenExpireError :
token , err = g . getTokenAndSave2Redis ( operationID )
token , err = g . getTokenAndSave2Redis ( ctx )
if err != nil {
if err != nil {
log . NewError ( operationID , utils . GetSelfFuncName ( ) , "getTokenAndSave2Redis failed, " , err . Error ( ) )
log . NewError ( operationID , utils . GetSelfFuncName ( ) , "getTokenAndSave2Redis failed, " , err . Error ( ) )
} else {
} else {
@ -187,52 +82,47 @@ func (g *Getui) Push(userIDList []string, title, detailContent, operationID stri
}
}
}
}
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "push failed" )
return utils . Wrap ( err , "push failed" )
}
}
respBytes , err := json . Marshal ( pushResp )
return utils . Wrap ( err , "" )
return string ( respBytes ) , utils . Wrap ( err , "" )
}
}
func ( g * Getui ) Auth ( operationID string , timeStamp int64 ) ( token string , expireTime int64 , err error ) {
func ( g * Client ) Auth ( ctx context . Context , timeStamp int64 ) ( token string , expireTime int64 , err error ) {
log . NewInfo ( operationID , utils . GetSelfFuncName ( ) , config . Config . Push . Getui . AppKey , timeStamp , config . Config . Push . Getui . MasterSecret )
h := sha256 . New ( )
h := sha256 . New ( )
h . Write ( [ ] byte ( config . Config . Push . Getui . AppKey + strconv . Itoa ( int ( timeStamp ) ) + config . Config . Push . Getui . MasterSecret ) )
h . Write ( [ ] byte ( config . Config . Push . Getui . AppKey + strconv . Itoa ( int ( timeStamp ) ) + config . Config . Push . Getui . MasterSecret ) )
sum := h . Sum ( nil )
sign := hex . EncodeToString ( h . Sum ( nil ) )
sign := hex . EncodeToString ( sum )
log . NewInfo ( operationID , utils . GetSelfFuncName ( ) , "sha256 result" , sign )
reqAuth := AuthReq {
reqAuth := AuthReq {
Sign : sign ,
Sign : sign ,
Timestamp : strconv . Itoa ( int ( timeStamp ) ) ,
Timestamp : strconv . Itoa ( int ( timeStamp ) ) ,
App k ey: config . Config . Push . Getui . AppKey ,
App K ey: config . Config . Push . Getui . AppKey ,
}
}
respAuth := AuthResp { }
respAuth := AuthResp { }
err = g . request ( A uthURL, reqAuth , "" , & respAuth , operationID )
err = g . request ( ctx, a uthURL, reqAuth , "" , & respAuth )
if err != nil {
if err != nil {
return "" , 0 , err
return "" , 0 , err
}
}
log . NewInfo ( operationID , utils . GetSelfFuncName ( ) , "result: " , respAuth )
//log.NewInfo(operationID, utils.GetSelfFuncName(), "result: ", respAuth)
expire , err := strconv . Atoi ( respAuth . ExpireTime )
expire , err := strconv . Atoi ( respAuth . ExpireTime )
return respAuth . Token , int64 ( expire ) , err
return respAuth . Token , int64 ( expire ) , err
}
}
func ( g * Getui) GetTaskID ( operationID , token string , pushReq PushReq ) ( string , error ) {
func ( g * Client) GetTaskID ( ctx context . Context , token string , pushReq PushReq ) ( string , error ) {
respTask := TaskResp { }
respTask := TaskResp { }
ttl := int64 ( 1000 * 60 * 5 )
ttl := int64 ( 1000 * 60 * 5 )
pushReq . Settings = & Settings { TTL : & ttl }
pushReq . Settings = & Settings { TTL : & ttl }
err := g . request ( T askURL, pushReq , token , & respTask , operationID )
err := g . request ( ctx, t askURL, pushReq , token , & respTask )
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "" )
return "" , utils . Wrap ( err , "" )
}
}
return respTask . TaskID , nil
return respTask . TaskID , nil
}
}
func ( g * Getui) request ( url string , content interface { } , token string , returnStruct interface { } , operationID string ) error {
func ( g * Client) request ( ctx context . Context , url string , content interface { } , token string , output interface { } ) error {
con , err := json . Marshal ( content )
con , err := json . Marshal ( content )
if err != nil {
if err != nil {
return err
return err
}
}
client := & http . Client { }
client := & http . Client { }
log . Debug ( operationID , utils . GetSelfFuncName ( ) , "json:" , string ( con ) , "token:" , token )
req , err := http . NewRequest ( "POST" , config . Config . Push . Getui . PushUrl + url , bytes . NewBuffer ( con ) )
req , err := http . NewRequest ( "POST" , config . Config . Push . Getui . PushUrl + url , bytes . NewBuffer ( con ) )
if err != nil {
if err != nil {
return err
return err
@ -250,74 +140,38 @@ func (g *Getui) request(url string, content interface{}, token string, returnStr
if err != nil {
if err != nil {
return err
return err
}
}
log . NewDebug ( operationID , "getui" , utils . GetSelfFuncName ( ) , "resp, " , string ( result ) )
//log.NewDebug(operationID, "getui", utils.GetSelfFuncName(), "resp, ", string(result))
commonResp := Getui CommonResp{ }
commonResp := CommonResp{ }
commonResp . Data = returnStruc t
commonResp . Data = outpu t
if err := json . Unmarshal ( result , & commonResp ) ; err != nil {
if err := json . Unmarshal ( result , & commonResp ) ; err != nil {
return err
return err
}
}
if commonResp . Code == 10001 {
if commonResp . Code == tokenExpire {
return TokenExpireError
return TokenExpireError
}
}
return nil
return nil
}
}
func ( pushReq * PushReq ) setPushChannel ( title string , body string ) {
func ( g * Client ) getTokenAndSave2Redis ( ctx context . Context ) ( token string , err error ) {
pushReq . PushChannel = & PushChannel { }
token , _ , err = g . Auth ( ctx , time . Now ( ) . UnixNano ( ) / 1e6 )
// autoBadge := "+1"
pushReq . PushChannel . Ios = & Ios { }
notify := "notify"
pushReq . PushChannel . Ios . NotiType = & notify
pushReq . PushChannel . Ios . Aps . Sound = "default"
pushReq . PushChannel . Ios . Aps . Alert = Alert {
Title : title ,
Body : body ,
}
pushReq . PushChannel . Android = & Android { }
pushReq . PushChannel . Android . Ups . Notification = Notification {
Title : title ,
Body : body ,
ClickType : "startapp" ,
}
pushReq . PushChannel . Android . Ups . Options = Options {
HW : struct {
DefaultSound bool ` json:"/message/android/notification/default_sound" `
ChannelID string ` json:"/message/android/notification/channel_id" `
Sound string ` json:"/message/android/notification/sound" `
Importance string ` json:"/message/android/notification/importance" `
} { ChannelID : "RingRing4" , Sound : "/raw/ring001" , Importance : "NORMAL" } ,
XM : struct {
ChannelID string ` json:"/extra.channel_id" `
} { ChannelID : "high_system" } ,
VV : struct {
Classification int "json:\"/classification\""
} {
Classification : 1 ,
} ,
}
}
func ( g * Getui ) getTokenAndSave2Redis ( operationID string ) ( token string , err error ) {
token , expireTime , err := g . Auth ( operationID , time . Now ( ) . UnixNano ( ) / 1e6 )
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "Auth failed" )
return "" , utils . Wrap ( err , "Auth failed" )
}
}
log . NewDebug ( operationID , "getui" , utils . GetSelfFuncName ( ) , token , expireTime , err )
err = g . cache . SetGetuiTaskID ( ctx , token , 60 * 60 * 23 )
err = db . DB . SetGetuiToken ( token , 60 * 60 * 23 )
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "Auth failed" )
return "" , utils . Wrap ( err , "Auth failed" )
}
}
return token , nil
return token , nil
}
}
func ( g * Getui) GetTaskIDAndSave2Redis ( operationID , token string , pushReq PushReq ) ( taskID string , err error ) {
func ( g * Client ) GetTaskIDAndSave2Redis ( ctx context . Context , token string , pushReq PushReq ) ( taskID string , err error ) {
ttl := int64 ( 1000 * 60 * 60 * 24 )
ttl := int64 ( 1000 * 60 * 60 * 24 )
pushReq . Settings = & Settings { TTL : & ttl }
pushReq . Settings = & Settings { TTL : & ttl }
taskID , err = g . GetTaskID ( operationID , token , pushReq )
taskID , err = g . GetTaskID ( ctx , token , pushReq )
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "GetTaskIDAndSave2Redis failed" )
return "" , utils . Wrap ( err , "GetTaskIDAndSave2Redis failed" )
}
}
err = db. DB . SetGetuiTaskID ( taskID , 60 * 60 * 23 )
err = g . cache . SetGetuiTaskID ( ctx , taskID , 60 * 60 * 23 )
if err != nil {
if err != nil {
return "" , utils . Wrap ( err , "Auth failed" )
return "" , utils . Wrap ( err , "Auth failed" )
}
}