v3 - main to cut out
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
** description("").
|
||||
** copyright('open-im,www.open-im.io').
|
||||
** author("fg,Gordon@tuoyun.net").
|
||||
** time(2021/5/27 11:24).
|
||||
*/
|
||||
package content_struct
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Content struct {
|
||||
IsDisplay int32 `json:"isDisplay"`
|
||||
ID string `json:"id"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func NewContentStructString(isDisplay int32, ID string, text string) string {
|
||||
c := Content{IsDisplay: isDisplay, ID: ID, Text: text}
|
||||
return c.contentToString()
|
||||
}
|
||||
|
||||
func (c *Content) contentToString() string {
|
||||
data, _ := json.Marshal(c)
|
||||
dataString := string(data)
|
||||
return dataString
|
||||
}
|
||||
|
||||
type groupMemberFullInfo struct {
|
||||
GroupId string `json:"groupID"`
|
||||
UserId string `json:"userId"`
|
||||
Role int `json:"role"`
|
||||
JoinTime uint64 `json:"joinTime"`
|
||||
NickName string `json:"nickName"`
|
||||
FaceUrl string `json:"faceUrl"`
|
||||
}
|
||||
|
||||
type AgreeOrRejectGroupMember struct {
|
||||
GroupId string `json:"groupID"`
|
||||
UserId string `json:"userId"`
|
||||
Role int `json:"role"`
|
||||
JoinTime uint64 `json:"joinTime"`
|
||||
NickName string `json:"nickName"`
|
||||
FaceUrl string `json:"faceUrl"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
type AtTextContent struct {
|
||||
Text string `json:"text"`
|
||||
AtUserList []string `json:"atUserList"`
|
||||
IsAtSelf bool `json:"isAtSelf"`
|
||||
}
|
||||
|
||||
type CreateGroupSysMsg struct {
|
||||
uIdCreator string `creatorUid`
|
||||
initMemberList []groupMemberFullInfo `json: initMemberList`
|
||||
CreateTime uint64 `json:"CreateTime"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type NotificationContent struct {
|
||||
IsDisplay int32 `json:"isDisplay"`
|
||||
DefaultTips string `json:"defaultTips"`
|
||||
Detail string `json:"detail"`
|
||||
}
|
||||
|
||||
func (c *NotificationContent) ContentToString() string {
|
||||
data, _ := json.Marshal(c)
|
||||
dataString := string(data)
|
||||
return dataString
|
||||
}
|
||||
|
||||
type KickGroupMemberApiReq struct {
|
||||
GroupID string `json:"groupID"`
|
||||
UidList []string `json:"uidList"`
|
||||
Reason string `json:"reason"`
|
||||
OperationID string `json:"operationID"`
|
||||
}
|
||||
|
||||
func NewCreateGroupSysMsgString(create *CreateGroupSysMsg, text string) string {
|
||||
create.Text = text
|
||||
jstring, _ := json.Marshal(create)
|
||||
|
||||
return string(jstring)
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package getui
|
||||
|
||||
import (
|
||||
"Open_IM/pkg/common/config"
|
||||
"Open_IM/pkg/common/db"
|
||||
"Open_IM/pkg/common/log"
|
||||
"Open_IM/pkg/utils"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
|
||||
//"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
GetuiClient *Getui
|
||||
|
||||
TokenExpireError = errors.New("token expire")
|
||||
)
|
||||
|
||||
const (
|
||||
PushURL = "/push/single/alias"
|
||||
AuthURL = "/auth"
|
||||
)
|
||||
|
||||
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 PushReq struct {
|
||||
RequestID string `json:"request_id"`
|
||||
Audience struct {
|
||||
Alias []string `json:"alias"`
|
||||
} `json:"audience"`
|
||||
PushMessage struct {
|
||||
Notification Notification `json:"notification,omitempty"`
|
||||
Transmission string `json:"transmission,omitempty"`
|
||||
} `json:"push_message"`
|
||||
PushChannel struct {
|
||||
Ios Ios `json:"ios"`
|
||||
Android Android `json:"android"`
|
||||
} `json:"push_channel"`
|
||||
}
|
||||
|
||||
type Ios struct {
|
||||
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"`
|
||||
} `json:"ups"`
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
ClickType string `json:"click_type"`
|
||||
}
|
||||
|
||||
type PushResp struct {
|
||||
}
|
||||
|
||||
func newGetuiClient() *Getui {
|
||||
return &Getui{}
|
||||
}
|
||||
|
||||
func (g *Getui) Push(userIDList []string, alert, detailContent, operationID string) (resp string, err error) {
|
||||
token, err := db.DB.GetGetuiToken()
|
||||
log.NewDebug(operationID, utils.GetSelfFuncName(), "token:", token)
|
||||
if err != nil {
|
||||
log.NewError(operationID, utils.OperationIDGenerator(), "GetGetuiToken failed", err.Error())
|
||||
}
|
||||
if token == "" || err != nil {
|
||||
token, err = g.getTokenAndSave2Redis(operationID)
|
||||
if err != nil {
|
||||
log.NewError(operationID, utils.GetSelfFuncName(), "getTokenAndSave2Redis failed", err.Error())
|
||||
return "", utils.Wrap(err, "")
|
||||
}
|
||||
}
|
||||
pushReq := PushReq{
|
||||
RequestID: utils.OperationIDGenerator(),
|
||||
Audience: struct {
|
||||
Alias []string `json:"alias"`
|
||||
}{Alias: []string{userIDList[0]}},
|
||||
}
|
||||
pushReq.PushMessage.Notification = Notification{
|
||||
Title: alert,
|
||||
Body: alert,
|
||||
ClickType: "startapp",
|
||||
}
|
||||
pushReq.PushChannel.Ios.Aps.Sound = "default"
|
||||
pushReq.PushChannel.Ios.Aps.Alert = Alert{
|
||||
Title: alert,
|
||||
Body: alert,
|
||||
}
|
||||
pushReq.PushChannel.Android.Ups.Notification = Notification{
|
||||
Title: alert,
|
||||
Body: alert,
|
||||
ClickType: "startapp",
|
||||
}
|
||||
pushResp := PushResp{}
|
||||
err = g.request(PushURL, pushReq, token, &pushResp, operationID)
|
||||
switch err {
|
||||
case TokenExpireError:
|
||||
token, err = g.getTokenAndSave2Redis(operationID)
|
||||
if err != nil {
|
||||
log.NewError(operationID, utils.GetSelfFuncName(), "getTokenAndSave2Redis failed, ", err.Error())
|
||||
} else {
|
||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "getTokenAndSave2Redis: ", token)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return "", utils.Wrap(err, "push failed")
|
||||
}
|
||||
respBytes, err := json.Marshal(pushResp)
|
||||
return string(respBytes), utils.Wrap(err, "")
|
||||
}
|
||||
|
||||
func (g *Getui) Auth(operationID string, 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.Write([]byte(config.Config.Push.Getui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.Getui.MasterSecret))
|
||||
sum := h.Sum(nil)
|
||||
sign := hex.EncodeToString(sum)
|
||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "sha256 result", sign)
|
||||
reqAuth := AuthReq{
|
||||
Sign: sign,
|
||||
Timestamp: strconv.Itoa(int(timeStamp)),
|
||||
Appkey: config.Config.Push.Getui.AppKey,
|
||||
}
|
||||
respAuth := AuthResp{}
|
||||
err = g.request(AuthURL, reqAuth, "", &respAuth, operationID)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "result: ", respAuth)
|
||||
expire, err := strconv.Atoi(respAuth.ExpireTime)
|
||||
return respAuth.Token, int64(expire), err
|
||||
}
|
||||
|
||||
func (g *Getui) request(url string, content interface{}, token string, returnStruct interface{}, operationID string) error {
|
||||
con, err := json.Marshal(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &http.Client{}
|
||||
log.Debug(operationID, utils.GetSelfFuncName(), "json:", string(con))
|
||||
req, err := http.NewRequest("POST", config.Config.Push.Getui.PushUrl+url, bytes.NewBuffer(con))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if token != "" {
|
||||
req.Header.Set("token", token)
|
||||
}
|
||||
req.Header.Set("content-type", "application/json")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
result, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.NewInfo(operationID, "getui", utils.GetSelfFuncName(), "resp, ", string(result))
|
||||
commonResp := GetuiCommonResp{}
|
||||
commonResp.Data = returnStruct
|
||||
if err := json.Unmarshal(result, &commonResp); err != nil {
|
||||
return err
|
||||
}
|
||||
if commonResp.Code == 10001 {
|
||||
return TokenExpireError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Getui) getTokenAndSave2Redis(operationID string) (token string, err error) {
|
||||
token, expireTime, err := g.Auth(operationID, time.Now().UnixNano()/1e6)
|
||||
if err != nil {
|
||||
return "", utils.Wrap(err, "Auth failed")
|
||||
}
|
||||
log.NewDebug(operationID, "getui", utils.GetSelfFuncName(), token, expireTime, err)
|
||||
err = db.DB.SetGetuiToken(token, 60*60*23)
|
||||
if err != nil {
|
||||
return "", utils.Wrap(err, "Auth failed")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func GetAuthorization(Appkey string, MasterSecret string) string {
|
||||
str := fmt.Sprintf("%s:%s", Appkey, MasterSecret)
|
||||
buf := []byte(str)
|
||||
Authorization := fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString(buf))
|
||||
return Authorization
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package push
|
||||
|
||||
import (
|
||||
"Open_IM/internal/push/jpush/common"
|
||||
"Open_IM/internal/push/jpush/requestBody"
|
||||
"Open_IM/pkg/common/config"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
JPushClient *JPush
|
||||
)
|
||||
|
||||
func init() {
|
||||
JPushClient = newGetuiClient()
|
||||
}
|
||||
|
||||
type JPush struct{}
|
||||
|
||||
func newGetuiClient() *JPush {
|
||||
return &JPush{}
|
||||
}
|
||||
|
||||
func (j *JPush) Auth(apiKey, secretKey string, timeStamp int64) (token string, err error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (j *JPush) SetAlias(cid, alias string) (resp string, err error) {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (j *JPush) Push(accounts []string, alert, detailContent, operationID string) (string, error) {
|
||||
var pf requestBody.Platform
|
||||
pf.SetAll()
|
||||
var au requestBody.Audience
|
||||
au.SetAlias(accounts)
|
||||
var no requestBody.Notification
|
||||
no.SetAlert(alert)
|
||||
var me requestBody.Message
|
||||
me.SetMsgContent(detailContent)
|
||||
var o requestBody.Options
|
||||
o.SetApnsProduction(false)
|
||||
var po requestBody.PushObj
|
||||
po.SetPlatform(&pf)
|
||||
po.SetAudience(&au)
|
||||
po.SetNotification(&no)
|
||||
po.SetMessage(&me)
|
||||
po.SetOptions(&o)
|
||||
|
||||
con, err := json.Marshal(po)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("POST", config.Config.Push.Jpns.PushUrl, bytes.NewBuffer(con))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", common.GetAuthorization(config.Config.Push.Jpns.AppKey, config.Config.Push.Jpns.MasterSecret))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
result, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(result), nil
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package requestBody
|
||||
|
||||
const (
|
||||
TAG = "tag"
|
||||
TAG_AND = "tag_and"
|
||||
TAG_NOT = "tag_not"
|
||||
ALIAS = "alias"
|
||||
REGISTRATION_ID = "registration_id"
|
||||
SEGMENT = "segment"
|
||||
ABTEST = "abtest"
|
||||
)
|
||||
|
||||
type Audience struct {
|
||||
Object interface{}
|
||||
audience map[string][]string
|
||||
}
|
||||
|
||||
func (a *Audience) set(key string, v []string) {
|
||||
if a.audience == nil {
|
||||
a.audience = make(map[string][]string)
|
||||
a.Object = a.audience
|
||||
}
|
||||
|
||||
//v, ok = this.audience[key]
|
||||
//if ok {
|
||||
// return
|
||||
//}
|
||||
a.audience[key] = v
|
||||
}
|
||||
|
||||
func (a *Audience) SetTag(tags []string) {
|
||||
a.set(TAG, tags)
|
||||
}
|
||||
|
||||
func (a *Audience) SetTagAnd(tags []string) {
|
||||
a.set(TAG_AND, tags)
|
||||
}
|
||||
|
||||
func (a *Audience) SetTagNot(tags []string) {
|
||||
a.set(TAG_NOT, tags)
|
||||
}
|
||||
|
||||
func (a *Audience) SetAlias(alias []string) {
|
||||
a.set(ALIAS, alias)
|
||||
}
|
||||
|
||||
func (a *Audience) SetRegistrationId(ids []string) {
|
||||
a.set(REGISTRATION_ID, ids)
|
||||
}
|
||||
|
||||
func (a *Audience) SetAll() {
|
||||
a.Object = "all"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package requestBody
|
||||
|
||||
type Message struct {
|
||||
MsgContent string `json:"msg_content"`
|
||||
Title string `json:"title,omitempty"`
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
Extras map[string]interface{} `json:"extras,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Message) SetMsgContent(c string) {
|
||||
m.MsgContent = c
|
||||
}
|
||||
|
||||
func (m *Message) SetTitle(t string) {
|
||||
m.Title = t
|
||||
}
|
||||
|
||||
func (m *Message) SetContentType(c string) {
|
||||
m.ContentType = c
|
||||
}
|
||||
|
||||
func (m *Message) SetExtras(key string, value interface{}) {
|
||||
if m.Extras == nil {
|
||||
m.Extras = make(map[string]interface{})
|
||||
}
|
||||
m.Extras[key] = value
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package requestBody
|
||||
|
||||
import (
|
||||
"Open_IM/pkg/common/config"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
Alert string `json:"alert,omitempty"`
|
||||
Android Android `json:"android,omitempty"`
|
||||
IOS Ios `json:"ios,omitempty"`
|
||||
}
|
||||
|
||||
type Android struct {
|
||||
Alert string `json:"alert,omitempty"`
|
||||
Intent struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
} `json:"intent,omitempty"`
|
||||
}
|
||||
type Ios struct {
|
||||
Alert string `json:"alert,omitempty"`
|
||||
Sound string `json:"sound,omitempty"`
|
||||
Badge string `json:"badge,omitempty"`
|
||||
}
|
||||
|
||||
func (n *Notification) SetAlert(alert string) {
|
||||
n.Alert = alert
|
||||
n.Android.Alert = alert
|
||||
n.SetAndroidIntent()
|
||||
n.IOS.Alert = alert
|
||||
n.IOS.Sound = "default"
|
||||
n.IOS.Badge = "+1"
|
||||
|
||||
}
|
||||
func (n *Notification) SetAndroidIntent() {
|
||||
n.Android.Intent.URL = config.Config.Push.Jpns.PushIntent
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package requestBody
|
||||
|
||||
type Options struct {
|
||||
ApnsProduction bool `json:"apns_production"`
|
||||
}
|
||||
|
||||
func (o *Options) SetApnsProduction(c bool) {
|
||||
o.ApnsProduction = c
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package requestBody
|
||||
|
||||
import (
|
||||
"Open_IM/pkg/common/constant"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
ANDROID = "android"
|
||||
IOS = "ios"
|
||||
QUICKAPP = "quickapp"
|
||||
WINDOWSPHONE = "winphone"
|
||||
ALL = "all"
|
||||
)
|
||||
|
||||
type Platform struct {
|
||||
Os interface{}
|
||||
osArry []string
|
||||
}
|
||||
|
||||
func (p *Platform) Set(os string) error {
|
||||
if p.Os == nil {
|
||||
p.osArry = make([]string, 0, 4)
|
||||
} else {
|
||||
switch p.Os.(type) {
|
||||
case string:
|
||||
return errors.New("platform is all")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
for _, value := range p.osArry {
|
||||
if os == value {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
switch os {
|
||||
case IOS:
|
||||
fallthrough
|
||||
case ANDROID:
|
||||
fallthrough
|
||||
case QUICKAPP:
|
||||
fallthrough
|
||||
case WINDOWSPHONE:
|
||||
p.osArry = append(p.osArry, os)
|
||||
p.Os = p.osArry
|
||||
default:
|
||||
return errors.New("unknow platform")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (p *Platform) SetPlatform(platform string) error {
|
||||
switch platform {
|
||||
case constant.AndroidPlatformStr:
|
||||
return p.SetAndroid()
|
||||
case constant.IOSPlatformStr:
|
||||
return p.SetIOS()
|
||||
default:
|
||||
return errors.New("platform err")
|
||||
}
|
||||
|
||||
}
|
||||
func (p *Platform) SetIOS() error {
|
||||
return p.Set(IOS)
|
||||
}
|
||||
|
||||
func (p *Platform) SetAndroid() error {
|
||||
return p.Set(ANDROID)
|
||||
}
|
||||
|
||||
func (p *Platform) SetQuickApp() error {
|
||||
return p.Set(QUICKAPP)
|
||||
}
|
||||
|
||||
func (p *Platform) SetWindowsPhone() error {
|
||||
return p.Set(WINDOWSPHONE)
|
||||
}
|
||||
|
||||
func (p *Platform) SetAll() {
|
||||
p.Os = ALL
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package requestBody
|
||||
|
||||
type PushObj struct {
|
||||
Platform interface{} `json:"platform"`
|
||||
Audience interface{} `json:"audience"`
|
||||
Notification interface{} `json:"notification,omitempty"`
|
||||
Message interface{} `json:"message,omitempty"`
|
||||
Options interface{} `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PushObj) SetPlatform(pf *Platform) {
|
||||
p.Platform = pf.Os
|
||||
}
|
||||
|
||||
func (p *PushObj) SetAudience(ad *Audience) {
|
||||
p.Audience = ad.Object
|
||||
}
|
||||
|
||||
func (p *PushObj) SetNotification(no *Notification) {
|
||||
p.Notification = no
|
||||
}
|
||||
|
||||
func (p *PushObj) SetMessage(m *Message) {
|
||||
p.Message = m
|
||||
}
|
||||
func (p *PushObj) SetOptions(o *Options) {
|
||||
p.Options = o
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
** description("").
|
||||
** copyright('open-im,www.open-im.io').
|
||||
** author("fg,Gordon@open-im.io").
|
||||
** time(2021/3/22 15:33).
|
||||
*/
|
||||
package logic
|
||||
|
||||
import (
|
||||
"Open_IM/pkg/common/config"
|
||||
"Open_IM/pkg/common/constant"
|
||||
"Open_IM/pkg/common/kafka"
|
||||
"Open_IM/pkg/statistics"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
rpcServer RPCServer
|
||||
pushCh PushConsumerHandler
|
||||
pushTerminal []int32
|
||||
producer *kafka.Producer
|
||||
count uint64
|
||||
)
|
||||
|
||||
func Init(rpcPort int) {
|
||||
|
||||
rpcServer.Init(rpcPort)
|
||||
pushCh.Init()
|
||||
pushTerminal = []int32{constant.IOSPlatformID, constant.AndroidPlatformID}
|
||||
}
|
||||
func init() {
|
||||
producer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.Ws2mschat.Topic)
|
||||
statistics.NewStatistics(&count, config.Config.ModuleName.PushName, fmt.Sprintf("%d second push to msg_gateway count", 300), 300)
|
||||
}
|
||||
|
||||
func Run() {
|
||||
go rpcServer.run()
|
||||
go pushCh.pushConsumerGroup.RegisterHandleAndConsumer(&pushCh)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
** description("").
|
||||
** copyright('Open_IM,www.Open_IM.io').
|
||||
** author("fg,Gordon@tuoyun.net").
|
||||
** time(2021/5/13 10:33).
|
||||
*/
|
||||
package logic
|
||||
|
||||
import (
|
||||
"Open_IM/pkg/common/config"
|
||||
kfk "Open_IM/pkg/common/kafka"
|
||||
"Open_IM/pkg/common/log"
|
||||
pbChat "Open_IM/pkg/proto/chat"
|
||||
pbPush "Open_IM/pkg/proto/push"
|
||||
"github.com/Shopify/sarama"
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type fcb func(msg []byte)
|
||||
|
||||
type PushConsumerHandler struct {
|
||||
msgHandle map[string]fcb
|
||||
pushConsumerGroup *kfk.MConsumerGroup
|
||||
}
|
||||
|
||||
func (ms *PushConsumerHandler) Init() {
|
||||
ms.msgHandle = make(map[string]fcb)
|
||||
ms.msgHandle[config.Config.Kafka.Ms2pschat.Topic] = ms.handleMs2PsChat
|
||||
ms.pushConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0,
|
||||
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ms2pschat.Topic}, config.Config.Kafka.Ms2pschat.Addr,
|
||||
config.Config.Kafka.ConsumerGroupID.MsgToPush)
|
||||
}
|
||||
func (ms *PushConsumerHandler) handleMs2PsChat(msg []byte) {
|
||||
log.InfoByKv("msg come from kafka And push!!!", "", "msg", string(msg))
|
||||
msgFromMQ := pbChat.PushMsgDataToMQ{}
|
||||
if err := proto.Unmarshal(msg, &msgFromMQ); err != nil {
|
||||
log.ErrorByKv("push Unmarshal msg err", "", "msg", string(msg), "err", err.Error())
|
||||
return
|
||||
}
|
||||
//Call push module to send message to the user
|
||||
MsgToUser((*pbPush.PushMsgReq)(&msgFromMQ))
|
||||
}
|
||||
func (PushConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||
func (PushConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||
func (ms *PushConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
|
||||
claim sarama.ConsumerGroupClaim) error {
|
||||
for msg := range claim.Messages() {
|
||||
log.InfoByKv("kafka get info to mysql", "", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value))
|
||||
ms.msgHandle[msg.Topic](msg.Value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"Open_IM/pkg/common/config"
|
||||
"Open_IM/pkg/common/log"
|
||||
"Open_IM/pkg/grpc-etcdv3/getcdv3"
|
||||
"Open_IM/pkg/proto/push"
|
||||
"Open_IM/pkg/utils"
|
||||
"context"
|
||||
"google.golang.org/grpc"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RPCServer struct {
|
||||
rpcPort int
|
||||
rpcRegisterName string
|
||||
etcdSchema string
|
||||
etcdAddr []string
|
||||
}
|
||||
|
||||
func (r *RPCServer) Init(rpcPort int) {
|
||||
r.rpcPort = rpcPort
|
||||
r.rpcRegisterName = config.Config.RpcRegisterName.OpenImPushName
|
||||
r.etcdSchema = config.Config.Etcd.EtcdSchema
|
||||
r.etcdAddr = config.Config.Etcd.EtcdAddr
|
||||
}
|
||||
func (r *RPCServer) run() {
|
||||
ip := utils.ServerIP
|
||||
registerAddress := ip + ":" + utils.IntToString(r.rpcPort)
|
||||
listener, err := net.Listen("tcp", registerAddress)
|
||||
if err != nil {
|
||||
log.ErrorByKv("push module rpc listening port err", "", "err", err.Error())
|
||||
return
|
||||
}
|
||||
defer listener.Close()
|
||||
srv := grpc.NewServer()
|
||||
defer srv.GracefulStop()
|
||||
pbPush.RegisterPushMsgServiceServer(srv, r)
|
||||
err = getcdv3.RegisterEtcd(r.etcdSchema, strings.Join(r.etcdAddr, ","), ip, r.rpcPort, r.rpcRegisterName, 10)
|
||||
if err != nil {
|
||||
log.ErrorByKv("register push module rpc to etcd err", "", "err", err.Error())
|
||||
}
|
||||
err = srv.Serve(listener)
|
||||
if err != nil {
|
||||
log.ErrorByKv("push module rpc start err", "", "err", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
func (r *RPCServer) PushMsg(_ context.Context, pbData *pbPush.PushMsgReq) (*pbPush.PushMsgResp, error) {
|
||||
//Call push module to send message to the user
|
||||
MsgToUser(pbData)
|
||||
return &pbPush.PushMsgResp{
|
||||
ResultCode: 0,
|
||||
}, nil
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
** description("").
|
||||
** copyright('open-im,www.open-im.io').
|
||||
** author("fg,Gordon@open-im.io").
|
||||
** time(2021/3/5 14:31).
|
||||
*/
|
||||
package logic
|
||||
|
||||
import (
|
||||
pusher "Open_IM/internal/push"
|
||||
"Open_IM/internal/push/getui"
|
||||
jpush "Open_IM/internal/push/jpush"
|
||||
"Open_IM/pkg/common/config"
|
||||
"Open_IM/pkg/common/constant"
|
||||
"Open_IM/pkg/common/log"
|
||||
"Open_IM/pkg/grpc-etcdv3/getcdv3"
|
||||
pbPush "Open_IM/pkg/proto/push"
|
||||
pbRelay "Open_IM/pkg/proto/relay"
|
||||
"Open_IM/pkg/utils"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpenIMContent struct {
|
||||
SessionType int `json:"sessionType"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Seq uint32 `json:"seq"`
|
||||
}
|
||||
type AtContent struct {
|
||||
Text string `json:"text"`
|
||||
AtUserList []string `json:"atUserList"`
|
||||
IsAtSelf bool `json:"isAtSelf"`
|
||||
}
|
||||
|
||||
func MsgToUser(pushMsg *pbPush.PushMsgReq) {
|
||||
var wsResult []*pbRelay.SingleMsgToUser
|
||||
isOfflinePush := utils.GetSwitchFromOptions(pushMsg.MsgData.Options, constant.IsOfflinePush)
|
||||
log.Debug("Get msg from msg_transfer And push msg", pushMsg.OperationID, "PushData", pushMsg.String())
|
||||
grpcCons := getcdv3.GetConn4Unique(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOnlineMessageRelayName)
|
||||
//Online push message
|
||||
log.Debug("test", pushMsg.OperationID, "len grpc", len(grpcCons), "data", pushMsg.String())
|
||||
for _, v := range grpcCons {
|
||||
msgClient := pbRelay.NewOnlineMessageRelayServiceClient(v)
|
||||
reply, err := msgClient.OnlinePushMsg(context.Background(), &pbRelay.OnlinePushMsgReq{OperationID: pushMsg.OperationID, MsgData: pushMsg.MsgData, PushToUserID: pushMsg.PushToUserID})
|
||||
if err != nil {
|
||||
log.InfoByKv("push data to client rpc err", pushMsg.OperationID, "err", err)
|
||||
continue
|
||||
}
|
||||
if reply != nil && reply.Resp != nil {
|
||||
wsResult = append(wsResult, reply.Resp...)
|
||||
}
|
||||
}
|
||||
log.InfoByKv("push_result", pushMsg.OperationID, "result", wsResult, "sendData", pushMsg.MsgData)
|
||||
count++
|
||||
if isOfflinePush && pushMsg.PushToUserID != pushMsg.MsgData.SendID {
|
||||
for _, v := range wsResult {
|
||||
if v.ResultCode == 0 {
|
||||
continue
|
||||
}
|
||||
if utils.IsContainInt32(v.RecvPlatFormID, pushTerminal) {
|
||||
//Use offline push messaging
|
||||
var UIDList []string
|
||||
UIDList = append(UIDList, v.RecvID)
|
||||
customContent := OpenIMContent{
|
||||
SessionType: int(pushMsg.MsgData.SessionType),
|
||||
From: pushMsg.MsgData.SendID,
|
||||
To: pushMsg.MsgData.RecvID,
|
||||
Seq: pushMsg.MsgData.Seq,
|
||||
}
|
||||
bCustomContent, _ := json.Marshal(customContent)
|
||||
jsonCustomContent := string(bCustomContent)
|
||||
var content string
|
||||
if pushMsg.MsgData.OfflinePushInfo != nil {
|
||||
content = pushMsg.MsgData.OfflinePushInfo.Title
|
||||
|
||||
} else {
|
||||
switch pushMsg.MsgData.ContentType {
|
||||
case constant.Text:
|
||||
content = constant.ContentType2PushContent[constant.Text]
|
||||
case constant.Picture:
|
||||
content = constant.ContentType2PushContent[constant.Picture]
|
||||
case constant.Voice:
|
||||
content = constant.ContentType2PushContent[constant.Voice]
|
||||
case constant.Video:
|
||||
content = constant.ContentType2PushContent[constant.Video]
|
||||
case constant.File:
|
||||
content = constant.ContentType2PushContent[constant.File]
|
||||
case constant.AtText:
|
||||
a := AtContent{}
|
||||
_ = utils.JsonStringToStruct(string(pushMsg.MsgData.Content), &a)
|
||||
if utils.IsContain(v.RecvID, a.AtUserList) {
|
||||
content = constant.ContentType2PushContent[constant.AtText] + constant.ContentType2PushContent[constant.Common]
|
||||
} else {
|
||||
content = constant.ContentType2PushContent[constant.GroupMsg]
|
||||
}
|
||||
default:
|
||||
content = constant.ContentType2PushContent[constant.Common]
|
||||
}
|
||||
}
|
||||
var offlinePusher pusher.OfflinePusher
|
||||
if config.Config.Push.Getui.Enable {
|
||||
log.NewInfo(pushMsg.OperationID, utils.GetSelfFuncName(), config.Config.Push.Getui)
|
||||
offlinePusher = getui.GetuiClient
|
||||
}
|
||||
if config.Config.Push.Jpns.Enable {
|
||||
offlinePusher = jpush.JPushClient
|
||||
}
|
||||
if offlinePusher == nil {
|
||||
offlinePusher = jpush.JPushClient
|
||||
}
|
||||
pushResult, err := offlinePusher.Push(UIDList, content, jsonCustomContent, pushMsg.OperationID)
|
||||
if err != nil {
|
||||
log.NewError(pushMsg.OperationID, "offline push error", pushMsg.String(), err.Error())
|
||||
} else {
|
||||
log.NewDebug(pushMsg.OperationID, "offline push return result is ", pushResult, pushMsg.MsgData)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//func SendMsgByWS(m *pbChat.WSToMsgSvrChatMsg) {
|
||||
// m.MsgID = rpcChat.GetMsgID(m.SendID)
|
||||
// m.ClientMsgID = m.MsgID
|
||||
// switch m.SessionType {
|
||||
// case constant.SingleChatType:
|
||||
// sendMsgToKafka(m, m.SendID, "msgKey--sendID")
|
||||
// sendMsgToKafka(m, m.RecvID, "msgKey--recvID")
|
||||
// case constant.GroupChatType:
|
||||
// etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName)
|
||||
// client := pbGroup.NewGroupClient(etcdConn)
|
||||
// req := &pbGroup.Req{
|
||||
// GroupID: m.RecvID,
|
||||
// Token: config.Config.Secret,
|
||||
// OperationID: m.OperationID,
|
||||
// }
|
||||
// reply, err := client.(context.Background(), req)
|
||||
// if err != nil {
|
||||
// log.Error(m.Token, m.OperationID, "rpc getGroupInfo failed, err = %s", err.Error())
|
||||
// return
|
||||
// }
|
||||
// if reply.ErrorCode != 0 {
|
||||
// log.Error(m.Token, m.OperationID, "rpc getGroupInfo failed, err = %s", reply.ErrorMsg)
|
||||
// return
|
||||
// }
|
||||
// groupID := m.RecvID
|
||||
// for i, v := range reply.MemberList {
|
||||
// m.RecvID = v.UserId + " " + groupID
|
||||
// sendMsgToKafka(m, utils.IntToString(i), "msgKey--recvID+\" \"+groupID")
|
||||
// }
|
||||
// default:
|
||||
//
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func sendMsgToKafka(m *pbChat.WSToMsgSvrChatMsg, key string, flag string) {
|
||||
// pid, offset, err := producer.SendMessage(m, key)
|
||||
// if err != nil {
|
||||
// log.ErrorByKv("kafka send failed", m.OperationID, "send data", m.String(), "pid", pid, "offset", offset, "err", err.Error(), flag, key)
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,34 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
tpns "Open_IM/internal/push/sdk/tpns-server-sdk-go/go"
|
||||
"Open_IM/internal/push/sdk/tpns-server-sdk-go/go/auth"
|
||||
"Open_IM/internal/push/sdk/tpns-server-sdk-go/go/common"
|
||||
"Open_IM/internal/push/sdk/tpns-server-sdk-go/go/req"
|
||||
"Open_IM/pkg/common/config"
|
||||
)
|
||||
|
||||
var badgeType = -2
|
||||
var iosAcceptId = auth.Auther{AccessID: config.Config.Push.Tpns.Ios.AccessID, SecretKey: config.Config.Push.Tpns.Ios.SecretKey}
|
||||
|
||||
func IOSAccountListPush(accounts []string, title, content, jsonCustomContent string) {
|
||||
var iosMessage = tpns.Message{
|
||||
Title: title,
|
||||
Content: content,
|
||||
IOS: &tpns.IOSParams{
|
||||
Aps: &tpns.Aps{
|
||||
BadgeType: &badgeType,
|
||||
Sound: "default",
|
||||
Category: "INVITE_CATEGORY",
|
||||
},
|
||||
CustomContent: jsonCustomContent,
|
||||
//CustomContent: `"{"key\":\"value\"}"`,
|
||||
},
|
||||
}
|
||||
pushReq, reqBody, err := req.NewListAccountPush(accounts, iosMessage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
iosAcceptId.Auth(pushReq, auth.UseSignAuthored, iosAcceptId, reqBody)
|
||||
common.PushAndGetResult(pushReq)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package push
|
||||
|
||||
type OfflinePusher interface {
|
||||
Push(userIDList []string, alert, detailContent, operationID string) (resp string, err error)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
b64 "encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
AccessID string
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
var UseSignAuthored = true
|
||||
|
||||
func (a *Auther) Auth(req *http.Request, useSignAuthored bool, auth Auther, reqBody string) {
|
||||
|
||||
if useSignAuthored {
|
||||
now := time.Now()
|
||||
timeStamp := now.Unix()
|
||||
req.Header.Add("AccessId", auth.AccessID)
|
||||
req.Header.Add("TimeStamp", strconv.Itoa(int(timeStamp)))
|
||||
sign := GenSign(uint64(timeStamp), auth.AccessID, auth.SecretKey, reqBody)
|
||||
req.Header.Add("Sign", sign)
|
||||
} else {
|
||||
author := makeAuthHeader(a.AccessID, a.SecretKey)
|
||||
//log.Printf("author string:%v", author)
|
||||
req.Header.Add("Authorization", author)
|
||||
}
|
||||
//req.Header.Add("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
func makeAuthHeader(appID, secretKey string) string {
|
||||
base64Str := base64.StdEncoding.EncodeToString(
|
||||
[]byte(
|
||||
fmt.Sprintf("%s:%s", appID, secretKey),
|
||||
),
|
||||
)
|
||||
return fmt.Sprintf("Basic %s", base64Str)
|
||||
}
|
||||
|
||||
func GenSign(timeStamp uint64, accessId string, secretKey, requestBody string) string {
|
||||
signBody := strconv.Itoa(int(timeStamp)) + accessId + requestBody
|
||||
// Create a new HMAC by defining the hash type and the key (as byte array)
|
||||
h := hmac.New(sha256.New, []byte(secretKey))
|
||||
// Write Data to it
|
||||
h.Write([]byte(signBody))
|
||||
|
||||
// Get result and encode as hexadecimal string
|
||||
sha := hex.EncodeToString(h.Sum(nil))
|
||||
//fmt.Println()
|
||||
//fmt.Println("timeStamp: " + strconv.Itoa(int(timeStamp)) + " accessID:" + accessId + " body:" + requestBody)
|
||||
sEnc := b64.StdEncoding.EncodeToString([]byte(sha))
|
||||
//fmt.Println("final Result " + sEnc)
|
||||
return sEnc
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func New() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
DisableCompression: false,
|
||||
DisableKeepAlives: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
tpns "Open_IM/internal/push/sdk/tpns-server-sdk-go/go"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func PushAndGetResult(pushReq *http.Request) {
|
||||
c := &http.Client{}
|
||||
rsp, err := c.Do(pushReq)
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
//fmt.Printf("http err:%v", err)
|
||||
return
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
body, err := ioutil.ReadAll(rsp.Body)
|
||||
//fmt.Printf("http ReadAll err:%v, body:%v ", err, string(body))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r := &tpns.CommonRsp{}
|
||||
json.Unmarshal(body, r)
|
||||
//fmt.Printf("push result: %+v", r)
|
||||
}
|
||||
|
||||
func UploadFile(req *http.Request) (int, error) {
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return 0, fmt.Errorf("response error, status: %s, body: %s", resp.Status, string(body))
|
||||
}
|
||||
|
||||
type uploadResponse struct {
|
||||
RetCode int `json:"retCode"`
|
||||
ErrMsg string `json:"errMsg"`
|
||||
UploadId int `json:"uploadId"`
|
||||
}
|
||||
|
||||
var ur uploadResponse
|
||||
if err := json.Unmarshal(body, &ur); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if ur.RetCode != 0 {
|
||||
return 0, fmt.Errorf("response with %d:%s", ur.RetCode, ur.ErrMsg)
|
||||
}
|
||||
return ur.UploadId, nil
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package common
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func ToJson(v interface{}) string {
|
||||
bs, _ := json.Marshal(v)
|
||||
return string(bs)
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
package tpns
|
||||
|
||||
type CommonRspEnv string
|
||||
|
||||
const (
|
||||
// EnvProd
|
||||
EnvProd CommonRspEnv = "product"
|
||||
// EnvDev
|
||||
EnvDev CommonRspEnv = "dev"
|
||||
)
|
||||
|
||||
type CommonRsp struct {
|
||||
// TODO: doc this
|
||||
Seq int64 `json:"seq"`
|
||||
|
||||
PushID string `json:"push_id"`
|
||||
|
||||
RetCode int `json:"ret_code"`
|
||||
|
||||
Environment CommonRspEnv `json:"environment"`
|
||||
|
||||
ErrMsg string `json:"err_msg,omitempty"`
|
||||
|
||||
Result map[string]string `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
type AudienceType string
|
||||
|
||||
const (
|
||||
AdAll AudienceType = "all"
|
||||
|
||||
AdTag AudienceType = "tag"
|
||||
|
||||
AdToken AudienceType = "token"
|
||||
|
||||
AdTokenList AudienceType = "token_list"
|
||||
|
||||
AdAccount AudienceType = "account"
|
||||
|
||||
AdAccountList AudienceType = "account_list"
|
||||
|
||||
AdPackageAccount AudienceType = "package_account_push"
|
||||
|
||||
AdPackageToken AudienceType = "package_token_push"
|
||||
)
|
||||
|
||||
// MessageType push API message_type
|
||||
type MessageType string
|
||||
|
||||
const (
|
||||
MsgTypeNotify MessageType = "notify"
|
||||
|
||||
MsgTypeMessage MessageType = "message"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
AudienceType AudienceType `json:"audience_type"`
|
||||
|
||||
Message Message `json:"message"`
|
||||
|
||||
MessageType MessageType `json:"message_type"`
|
||||
|
||||
Tag []TagRule `json:"tag_rules,omitempty"`
|
||||
|
||||
TokenList []string `json:"token_list,omitempty"`
|
||||
|
||||
AccountList []string `json:"account_list,omitempty"`
|
||||
|
||||
Environment CommonRspEnv `json:"environment,omitempty"`
|
||||
|
||||
UploadId int `json:"upload_id,omitempty"`
|
||||
|
||||
ExpireTime int `json:"expire_time,omitempty"`
|
||||
|
||||
SendTime string `json:"send_time,omitempty"`
|
||||
|
||||
MultiPkg bool `json:"multi_pkg,omitempty"`
|
||||
|
||||
PlanId string `json:"plan_id,omitempty"`
|
||||
|
||||
AccountPushType int `json:"account_push_type,omitempty"`
|
||||
|
||||
PushSpeed int `json:"push_speed,omitempty"`
|
||||
|
||||
CollapseId int `json:"collapse_id"`
|
||||
|
||||
TPNSOnlinePushType int `json:"tpns_online_push_type"`
|
||||
|
||||
ChannelRules []*ChannelDistributeRule `json:"channel_rules,omitempty"`
|
||||
|
||||
LoopParam *PushLoopParam `json:"loop_param,omitempty"`
|
||||
ForceCollapse bool `json:"force_collapse"`
|
||||
}
|
||||
|
||||
type TagListOperation string
|
||||
|
||||
type ChannelDistributeRule struct {
|
||||
ChannelName string `json:"channel"`
|
||||
Disable bool `json:"disable"`
|
||||
}
|
||||
|
||||
type PushLoopParam struct {
|
||||
StartDate string `json:"startDate"`
|
||||
|
||||
EndDate string `json:"endDate"`
|
||||
|
||||
LoopType PushLoopType `json:"loopType"`
|
||||
|
||||
LoopDayIndexs []uint32 `json:"loopDayIndexs"`
|
||||
|
||||
DayTimes []string `json:"dayTimes"`
|
||||
}
|
||||
|
||||
type PushLoopType int32
|
||||
|
||||
const (
|
||||
TagListOpAnd TagListOperation = "AND"
|
||||
|
||||
TagListOpOr TagListOperation = "OR"
|
||||
)
|
||||
|
||||
type TagType string
|
||||
|
||||
const (
|
||||
XGAutoProvince TagType = "xg_auto_province"
|
||||
XGAutoActive TagType = "xg_auto_active"
|
||||
XGUserDefine TagType = "xg_user_define"
|
||||
XGAutoVersion TagType = "xg_auto_version"
|
||||
XGAutoSdkversion TagType = "xg_auto_sdkversion"
|
||||
XGAutoDevicebrand TagType = "xg_auto_devicebrand"
|
||||
XGAutoDeviceversion TagType = "xg_auto_deviceversion"
|
||||
XGAutoCountry TagType = "xg_auto_country"
|
||||
)
|
||||
|
||||
type TagRule struct {
|
||||
TagItems []TagItem `json:"tag_items"`
|
||||
|
||||
IsNot bool `json:"is_not"`
|
||||
|
||||
Operator TagListOperation `json:"operator"`
|
||||
}
|
||||
|
||||
type TagItem struct {
|
||||
// 标签
|
||||
Tags []string `json:"tags"`
|
||||
IsNot bool `json:"is_not"`
|
||||
TagsOperator TagListOperation `json:"tags_operator"`
|
||||
ItemsOperator TagListOperation `json:"items_operator"`
|
||||
TagType TagType `json:"tag_type"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
|
||||
AcceptTime []AcceptTimeItem `json:"accept_time,omitempty"`
|
||||
|
||||
Android *AndroidParams `json:"android,omitempty"`
|
||||
|
||||
IOS *IOSParams `json:"ios,omitempty"`
|
||||
|
||||
ThreadId string `json:"thread_id,omitempty"`
|
||||
|
||||
ThreadSumtext string `json:"thread_sumtext,omitempty"`
|
||||
|
||||
XGMediaResources string `json:"xg_media_resources,omitempty"`
|
||||
|
||||
XGMediaAudioResources string `json:"xg_media_audio_resources,omitempty"`
|
||||
}
|
||||
|
||||
type AcceptTimeItem struct {
|
||||
Start HourAndMin `json:"start,omitempty"`
|
||||
End HourAndMin `json:"end,omitempty"`
|
||||
}
|
||||
|
||||
type HourAndMin struct {
|
||||
Hour string `json:"hour,omitempty"`
|
||||
Min string `json:"min,omitempty"`
|
||||
}
|
||||
|
||||
type AndroidParams struct {
|
||||
BuilderId *int `json:"builder_id,omitempty"`
|
||||
|
||||
Ring *int `json:"ring,omitempty"`
|
||||
|
||||
RingRaw string `json:"ring_raw,omitempty"`
|
||||
|
||||
Vibrate *int `json:"vibrate,omitempty"`
|
||||
|
||||
Lights *int `json:"lights,omitempty"`
|
||||
|
||||
Clearable *int `json:"clearable,omitempty"`
|
||||
|
||||
IconType *int `json:"icon_type"`
|
||||
|
||||
IconRes string `json:"icon_res,omitempty"`
|
||||
|
||||
StyleId *int `json:"style_id,omitempty"`
|
||||
|
||||
SmallIcon string `json:"small_icon,omitempty"`
|
||||
|
||||
Action *Action `json:"action,omitempty"`
|
||||
|
||||
CustomContent string `json:"custom_content,omitempty"`
|
||||
|
||||
ShowType *int `json:"show_type,omitempty"`
|
||||
|
||||
NChId string `json:"n_ch_id,omitempty"`
|
||||
|
||||
NChName string `json:"n_ch_name,omitempty"`
|
||||
|
||||
HwChId string `json:"hw_ch_id,omitempty"`
|
||||
|
||||
XmChId string `json:"xm_ch_id,omitempty"`
|
||||
|
||||
OppoChId string `json:"oppo_ch_id,omitempty"`
|
||||
|
||||
VivoChId string `json:"vivo_ch_id,omitempty"`
|
||||
|
||||
BadgeType *int `json:"badge_type,omitempty"`
|
||||
|
||||
IconColor *int `json:"icon_color,omitempty"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
ActionType *int `json:"action_type,omitempty"`
|
||||
Activity string `json:"activity"`
|
||||
AtyAttr AtyAttr `json:"aty_attr,omitempty"`
|
||||
Intent string `json:"intent"`
|
||||
Browser Browser `json:"browser,omitempty"`
|
||||
}
|
||||
|
||||
type Browser struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Confirm *int `json:"confirm,omitempty"`
|
||||
}
|
||||
|
||||
type AtyAttr struct {
|
||||
AttrIf *int `json:"if,omitempty"`
|
||||
Pf *int `json:"pf,omitempty"`
|
||||
}
|
||||
|
||||
type IOSParams struct {
|
||||
Aps *Aps `json:"aps,omitempty"`
|
||||
|
||||
CustomContent string `json:"custom_content,omitempty"`
|
||||
}
|
||||
|
||||
type Aps struct {
|
||||
Alert map[string]string `json:"alert,omitempty"`
|
||||
BadgeType *int `json:"badge_type,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
ContentAvailableInt *int `json:"content-available,omitempty"`
|
||||
MutableContent *int `json:"mutable-content,omitempty"`
|
||||
Sound string `json:"sound,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
package req
|
||||
|
||||
import (
|
||||
tpns "Open_IM/internal/push/sdk/tpns-server-sdk-go/go"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var PushURL = "https://api.tpns.tencent.com/v3/push/app"
|
||||
|
||||
//var PushURL = "https://test.api.tpns.tencent.com/v3/push/app"
|
||||
|
||||
func URL(url string) {
|
||||
PushURL = url
|
||||
}
|
||||
|
||||
type ReqOpt func(*tpns.Request)
|
||||
|
||||
func NewPush(req *tpns.Request, opts ...ReqOpt) (*http.Request, string, error) {
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewUploadFileRequest(host string, file string) (*http.Request, error) {
|
||||
fp, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer fp.Close()
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
part, err := writer.CreateFormFile("file", filepath.Base(fp.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
io.Copy(part, fp)
|
||||
writer.Close()
|
||||
url := host + "/v3/push/package/upload"
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func NewSingleAccountPush(
|
||||
message tpns.Message,
|
||||
account string,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdAccountList,
|
||||
AccountList: []string{account},
|
||||
Message: message,
|
||||
}
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewListAccountPush(
|
||||
accounts []string, message tpns.Message,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdAccountList,
|
||||
AccountList: accounts,
|
||||
Message: message,
|
||||
Environment: tpns.EnvDev,
|
||||
}
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewTokenPush(
|
||||
tokens []string, message tpns.Message,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdTokenList,
|
||||
TokenList: tokens,
|
||||
Message: message,
|
||||
Environment: tpns.EnvProd,
|
||||
}
|
||||
//fmt.Printf("reqBody :%v", common.ToJson(req))
|
||||
//fmt.Println()
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewTagsPush(
|
||||
tagList []tpns.TagRule, message tpns.Message,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdTag,
|
||||
Tag: tagList,
|
||||
Message: message,
|
||||
}
|
||||
//fmt.Printf("reqBody :%v", common.ToJson(req))
|
||||
//fmt.Println()
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewAllPush(
|
||||
message tpns.Message,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdAll,
|
||||
Message: message,
|
||||
}
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewAccountPackagePush(
|
||||
message tpns.Message,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdPackageAccount,
|
||||
Message: message,
|
||||
}
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewTokenPackagePush(
|
||||
message tpns.Message,
|
||||
opts ...ReqOpt,
|
||||
) (*http.Request, string, error) {
|
||||
req := &tpns.Request{
|
||||
MessageType: tpns.MsgTypeNotify,
|
||||
AudienceType: tpns.AdPackageToken,
|
||||
Message: message,
|
||||
}
|
||||
return NewPushReq(req, opts...)
|
||||
}
|
||||
|
||||
func NewPushReq(req *tpns.Request, opts ...ReqOpt) (request *http.Request, reqBody string, err error) {
|
||||
for _, opt := range opts {
|
||||
opt(req)
|
||||
}
|
||||
bodyBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
reqBody = string(bodyBytes)
|
||||
//fmt.Printf("NewPushReq req:%v", reqBody)
|
||||
request, err = http.NewRequest("POST", PushURL, bytes.NewReader(bodyBytes))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
return
|
||||
}
|
||||
|
||||
func EnvProd() ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Environment = tpns.EnvProd
|
||||
}
|
||||
}
|
||||
|
||||
func EnvDev() ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Environment = tpns.EnvDev
|
||||
}
|
||||
}
|
||||
|
||||
func Title(t string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Title = t
|
||||
if r.Message.IOS != nil {
|
||||
if r.Message.IOS.Aps != nil {
|
||||
r.Message.IOS.Aps.Alert["title"] = t
|
||||
} else {
|
||||
r.Message.IOS.Aps = &tpns.Aps{
|
||||
Alert: map[string]string{"title": t},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.Message.IOS = &tpns.IOSParams{
|
||||
Aps: &tpns.Aps{
|
||||
Alert: map[string]string{"title": t},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Content(c string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Content = c
|
||||
if r.Message.IOS != nil {
|
||||
if r.Message.IOS.Aps != nil {
|
||||
r.Message.IOS.Aps.Alert["body"] = c
|
||||
} else {
|
||||
r.Message.IOS.Aps = &tpns.Aps{
|
||||
Alert: map[string]string{"body": c},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.Message.IOS = &tpns.IOSParams{
|
||||
Aps: &tpns.Aps{
|
||||
Alert: map[string]string{"body": c},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Ring(ring *int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.Ring = ring
|
||||
}
|
||||
}
|
||||
|
||||
func RingRaw(rr string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.RingRaw = rr
|
||||
}
|
||||
}
|
||||
|
||||
func Vibrate(v *int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.Vibrate = v
|
||||
}
|
||||
}
|
||||
|
||||
func Lights(l *int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.Lights = l
|
||||
}
|
||||
}
|
||||
|
||||
func Clearable(c *int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.Clearable = c
|
||||
}
|
||||
}
|
||||
|
||||
func IconType(it *int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.IconType = it
|
||||
}
|
||||
}
|
||||
|
||||
func IconRes(ir string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.IconRes = ir
|
||||
}
|
||||
}
|
||||
|
||||
func AndroidCustomContent(ct string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.Android.CustomContent = ct
|
||||
}
|
||||
}
|
||||
|
||||
func Aps(aps *tpns.Aps) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message.IOS.Aps = aps
|
||||
}
|
||||
}
|
||||
|
||||
func AudienceType(at tpns.AudienceType) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.AudienceType = at
|
||||
}
|
||||
}
|
||||
|
||||
func Message(m tpns.Message) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Message = m
|
||||
}
|
||||
}
|
||||
|
||||
func TokenList(tl []string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.TokenList = tl
|
||||
}
|
||||
}
|
||||
|
||||
func TokenListAdd(t string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
if r.TokenList != nil {
|
||||
r.TokenList = append(r.TokenList, t)
|
||||
} else {
|
||||
r.TokenList = []string{t}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AccountList(al []string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.AccountList = al
|
||||
}
|
||||
}
|
||||
|
||||
//ChannelDistributeRules
|
||||
func AddChannelRules(ChannelRules []*tpns.ChannelDistributeRule) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.ChannelRules = ChannelRules
|
||||
}
|
||||
}
|
||||
|
||||
//ChannelDistributeRules
|
||||
func AddLoopParam(loopParam *tpns.PushLoopParam) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.LoopParam = loopParam
|
||||
}
|
||||
}
|
||||
|
||||
func AccountListAdd(a string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
if r.AccountList != nil {
|
||||
r.AccountList = append(r.AccountList, a)
|
||||
} else {
|
||||
r.AccountList = []string{a}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MessageType(t tpns.MessageType) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.MessageType = t
|
||||
}
|
||||
}
|
||||
|
||||
func AddMultiPkg(multipPkg bool) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.MultiPkg = multipPkg
|
||||
}
|
||||
}
|
||||
|
||||
func AddForceCollapse(forceCollapse bool) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.ForceCollapse = forceCollapse
|
||||
}
|
||||
}
|
||||
|
||||
func AddTPNSOnlinePushType(onlinePushType int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.TPNSOnlinePushType = onlinePushType
|
||||
}
|
||||
}
|
||||
|
||||
func AddCollapseId(collapseId int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.CollapseId = collapseId
|
||||
}
|
||||
}
|
||||
|
||||
func AddPushSpeed(pushSpeed int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.PushSpeed = pushSpeed
|
||||
}
|
||||
}
|
||||
|
||||
func AddAccountPushType(accountPushType int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.AccountPushType = accountPushType
|
||||
}
|
||||
}
|
||||
|
||||
func AddPlanId(planId string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.PlanId = planId
|
||||
}
|
||||
}
|
||||
|
||||
func AddSendTime(sendTime string) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.SendTime = sendTime
|
||||
}
|
||||
}
|
||||
|
||||
func AddExpireTime(expireTime int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.ExpireTime = expireTime
|
||||
}
|
||||
}
|
||||
|
||||
func AddUploadId(UploadId int) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.UploadId = UploadId
|
||||
}
|
||||
}
|
||||
|
||||
func AddEnvironment(Environment tpns.CommonRspEnv) ReqOpt {
|
||||
return func(r *tpns.Request) {
|
||||
r.Environment = Environment
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user