1082 lines
30 KiB
Go
1082 lines
30 KiB
Go
package im
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"encoding/base64"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"math/big"
|
||
"strings"
|
||
"time"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
|
||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
|
||
)
|
||
|
||
func SendVendorV2(data SendData, vendorOrgCode string) (err error) {
|
||
if data.VendorID == model.VendorIDMTWM {
|
||
dataStr, _ := json.Marshal(data.Data)
|
||
temp := string(dataStr)
|
||
globals.SugarLogger.Debugf("SendVendorV2 mtwmtemp=%s", temp)
|
||
if _, err = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, vendorOrgCode).(*mtwmapi.API).MsgSend(string(dataStr)); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
if data.VendorID == model.VendorIDEBAI {
|
||
str, _ := json.Marshal(data.Data)
|
||
param := &ebaiapi.BusinessSendMsgReq{}
|
||
err = json.Unmarshal(str, ¶m)
|
||
globals.SugarLogger.Debugf("SendVendorV2 ebaiparam=%s", utils.Format4Output(param, false))
|
||
err = partner.CurAPIManager.GetAPI(model.VendorIDEBAI, vendorOrgCode).(*ebaiapi.API).BusinessSendMsg(param)
|
||
}
|
||
err = ReadMsgFromClient(data.VendorID, vendorOrgCode, data.Data)
|
||
if err != nil {
|
||
globals.SugarLogger.Debugf("SendVendorV2:%v", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
type GetPoiIMStatusReq struct {
|
||
VendorID int `json:"vendorID"`
|
||
VendorStoreID string `json:"vendorStoreID"`
|
||
VendorOrgCode string `json:"vendorOrgCode"`
|
||
}
|
||
|
||
type GetPoiIMStatusResp struct {
|
||
VendorID int `json:"vendorID"`
|
||
ImStatus int `json:"imStatus"`
|
||
ErrMsg string `json:"errMsg"`
|
||
}
|
||
|
||
// GetPoiIMStatus 查询门店IM单聊开关状态
|
||
func GetPoiIMStatus(param []GetPoiIMStatusReq) (retVal []*GetPoiIMStatusResp) {
|
||
var (
|
||
ans1 = &GetPoiIMStatusResp{}
|
||
ans2 = &GetPoiIMStatusResp{}
|
||
)
|
||
if len(param) == 0 {
|
||
return nil
|
||
}
|
||
for _, v := range param {
|
||
switch v.VendorID {
|
||
case model.VendorIDMTWM:
|
||
api := partner.CurAPIManager.GetAPI(model.VendorIDMTWM, v.VendorOrgCode).(*mtwmapi.API)
|
||
switch v.VendorOrgCode {
|
||
case "5873":
|
||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(dao.GetDB(), v.VendorStoreID, model.VendorIDMTWM, v.VendorOrgCode)
|
||
if err != nil || storeDetail == nil {
|
||
return nil
|
||
}
|
||
api.SetToken(storeDetail.MtwmToken)
|
||
default:
|
||
|
||
}
|
||
temp, err := api.GetPoiIMStatus(v.VendorStoreID)
|
||
if err != nil {
|
||
ans1.ErrMsg = fmt.Sprintf("1:%v", err)
|
||
continue
|
||
}
|
||
ans1.VendorID = model.VendorIDMTWM
|
||
ans1.ImStatus = temp.ImStatus
|
||
case model.VendorIDEBAI:
|
||
status, err := partner.CurAPIManager.GetAPI(model.VendorIDEBAI, v.VendorOrgCode).(*ebaiapi.API).GetStoreIMStatus(v.VendorStoreID)
|
||
if err != nil {
|
||
ans1.ErrMsg = fmt.Sprintf("3:%v", err)
|
||
continue
|
||
}
|
||
ans2.VendorID = model.VendorIDEBAI
|
||
ans2.ImStatus = utils.Str2Int(status)
|
||
}
|
||
}
|
||
retVal = append(retVal, ans1, ans2)
|
||
return retVal
|
||
}
|
||
|
||
type SetPoiIMStatusReq struct {
|
||
VendorID int `json:"vendorID"`
|
||
VendorStoreID string `json:"vendorStoreID"`
|
||
VendorOrgCode string `json:"vendorOrgCode"`
|
||
ImStatus int `json:"imStatus"`
|
||
}
|
||
|
||
// SetPoiIMStatus 设置平台门店im状态
|
||
func SetPoiIMStatus(param []SetPoiIMStatusReq) error {
|
||
var errList errlist.ErrList
|
||
if len(param) == 0 {
|
||
return nil
|
||
}
|
||
for _, v := range param {
|
||
switch v.VendorID {
|
||
case model.VendorIDMTWM:
|
||
if err := partner.CurAPIManager.GetAPI(model.VendorIDMTWM, v.VendorOrgCode).(*mtwmapi.API).SetPoiIMStatus(v.VendorStoreID, v.ImStatus); err != nil {
|
||
errList.AddErr(fmt.Errorf("mtwm:%v", err))
|
||
}
|
||
case model.VendorIDEBAI:
|
||
if err := partner.CurAPIManager.GetAPI(model.VendorIDEBAI, v.VendorOrgCode).(*ebaiapi.API).UpdateIMStatus(v.VendorStoreID, v.ImStatus); err != nil {
|
||
errList.AddErr(fmt.Errorf("ebai:%v", err))
|
||
}
|
||
}
|
||
}
|
||
return errList.GetErrListAsOne()
|
||
}
|
||
|
||
// ReadMsgFromClient 存储客户端发送的消息
|
||
func ReadMsgFromClient(vendorID int, elmAppID string, msg interface{}) error {
|
||
var (
|
||
err error
|
||
elmTime int
|
||
jxMsg = &JXMsg{}
|
||
errList errlist.ErrList
|
||
userList = &UserMessageList{}
|
||
)
|
||
|
||
data, err := json.Marshal(msg)
|
||
if err != nil {
|
||
errList.AddErr(fmt.Errorf("json处理数据错误:%v", err))
|
||
}
|
||
|
||
if vendorID == VendorIDMT {
|
||
var pushContent = mtwmapi.PushContentReq{}
|
||
err = json.Unmarshal(data, &pushContent)
|
||
jxMsg = &JXMsg{
|
||
SendType: SendTypeJx,
|
||
MsgContent: pushContent,
|
||
}
|
||
userList = &UserMessageList{
|
||
VendorID: VendorIDMT,
|
||
UserID: utils.Int2Str(pushContent.OpenUserID),
|
||
LatestMsg: pushContent.MsgContent,
|
||
LatestTime: pushContent.Cts,
|
||
OrderID: "",
|
||
}
|
||
if pushContent.OrderID != 0 {
|
||
userList.OrderID = utils.Int2Str(pushContent.OrderID)
|
||
}
|
||
}
|
||
if vendorID == VendorIDELM {
|
||
var ElmData = ebaiapi.ImMessageSend{}
|
||
err = json.Unmarshal(data, &ElmData)
|
||
jxMsg = &JXMsg{
|
||
SendType: SendTypeJx,
|
||
MsgContent: ElmData,
|
||
}
|
||
if ElmData.PayLoad.CreateTime == 0 {
|
||
elmTime = int(time.Now().Unix())
|
||
}
|
||
userList = &UserMessageList{
|
||
VendorID: VendorIDELM,
|
||
UserID: ElmData.PayLoad.GroupID,
|
||
LatestMsg: ElmData.PayLoad.Content,
|
||
LatestTime: elmTime,
|
||
}
|
||
}
|
||
|
||
//1 存储展示列表时单条数据
|
||
if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("存储详细聊天记录错误:%v", err))
|
||
}
|
||
//2 存储详细聊天记录list
|
||
if err = SetUserList(jxMsg, userList, vendorID, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("存储STU聊天记录错误:%v", err))
|
||
}
|
||
if errList.GetErrListAsOne() != nil {
|
||
return fmt.Errorf("ReadMsgFromClient:%v", errList.GetErrListAsOne())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// ReadMsgFromVendor 读取数据并存储到redis
|
||
func ReadMsgFromVendor(vendorID int, elmAppID string, msg []byte) error {
|
||
var (
|
||
err error
|
||
jxMsg = &JXMsg{}
|
||
vendorStoreID string
|
||
errList errlist.ErrList
|
||
userList = &UserMessageList{}
|
||
)
|
||
if len(string(msg)) == 0 {
|
||
errList.AddErr(fmt.Errorf("读取平台数据为空,请检查"))
|
||
}
|
||
|
||
switch vendorID {
|
||
case VendorIDMT:
|
||
var PushContentReq = mtwmapi.PushContentReq{}
|
||
err = json.Unmarshal(msg, &PushContentReq)
|
||
if len(PushContentReq.MsgContent) != 0 || PushContentReq.MsgContent != "" {
|
||
if FilterIm(PushContentReq.AppID, PushContentReq.MsgContent) { //自动回复消息过滤
|
||
return nil
|
||
}
|
||
}
|
||
|
||
jxMsg = &JXMsg{
|
||
SendType: SendTypeMt,
|
||
MsgContent: PushContentReq,
|
||
}
|
||
userList = &UserMessageList{
|
||
VendorID: VendorIDMT,
|
||
UserID: utils.Int2Str(PushContentReq.OpenUserID),
|
||
LatestMsg: PushContentReq.MsgContent,
|
||
LatestTime: PushContentReq.Cts,
|
||
OrderID: "",
|
||
}
|
||
vendorStoreID = PushContentReq.AppPoiCode
|
||
if PushContentReq.OrderID != 0 {
|
||
userList.OrderID = utils.Int2Str(PushContentReq.OrderID)
|
||
}
|
||
case VendorIDELM:
|
||
var ElmData = ebaiapi.ImMessageSend{}
|
||
err = json.Unmarshal(msg, &ElmData)
|
||
jxMsg = &JXMsg{
|
||
SendType: SendTypeElm,
|
||
MsgContent: ElmData,
|
||
}
|
||
userList = &UserMessageList{
|
||
VendorID: VendorIDELM,
|
||
UserID: ElmData.PayLoad.GroupID,
|
||
LatestMsg: ElmData.PayLoad.Content,
|
||
LatestTime: int(ElmData.PayLoad.CreateTime / 1000),
|
||
}
|
||
|
||
}
|
||
|
||
//1 存储详细聊天记录list
|
||
if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("存储详细聊天记录错误:%v", err))
|
||
}
|
||
//2 存储展示列表时单条数据
|
||
if err = SetUserList(jxMsg, userList, vendorID, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("存储STU聊天记录错误:%v", err))
|
||
}
|
||
//3 cid推送新消息
|
||
if err = PushMsgByCid(vendorStoreID, vendorID, string(msg)); err != nil {
|
||
errList.AddErr(fmt.Errorf("向商家cid推送新消息错误:%v", err))
|
||
}
|
||
//4 客服自动回复
|
||
if err = CheckAndReply(jxMsg, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("客服自动回复出错:%v", err))
|
||
}
|
||
|
||
//5延迟40s 自动回复
|
||
//timer := time.NewTimer(30 * time.Second)
|
||
|
||
if errList.GetErrListAsOne() != nil {
|
||
return fmt.Errorf("ReadMsgFromVendor:%v", errList.GetErrListAsOne())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// PushMsgByCid 通过cid push用户
|
||
func PushMsgByCid(vendorStoreID string, vendorID int, msg string) error {
|
||
if err := push.NotifyImNewMessage(vendorStoreID, vendorID, msg); err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// SetMessageDetail 赋值
|
||
//格式 AppID:AppPoiCode:1:OpenUserID
|
||
func SetMessageDetail(req *JXMsg, vendorID int, elmAppID string) error {
|
||
if req == nil {
|
||
return nil
|
||
}
|
||
//生成京西消息ID detail
|
||
msgID := GenMsgDetailID(req, vendorID, elmAppID)
|
||
if len(msgID) == 0 {
|
||
return nil
|
||
}
|
||
|
||
data, _ := json.Marshal(req)
|
||
err := rdb.RPush(msgID, string(data))
|
||
ok, err := rdb.ExpireResult(msgID, ExpireTimeDay)
|
||
if err != nil || !ok {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// SetUserList 赋值
|
||
//AppPoiCode:10 [userid1:{SingleChat},userid2:{}]
|
||
func SetUserList(jxMsg *JXMsg, userList *UserMessageList, vendorID int, elmAppID string) error {
|
||
//生成msgID
|
||
msgID := GenMsgListID(jxMsg, vendorID, elmAppID)
|
||
if len(msgID) == 0 {
|
||
return nil
|
||
}
|
||
|
||
//获取未读消息条数并删除旧数据
|
||
cnt, err := GetNewAndTrim(msgID, userList.UserID)
|
||
if cnt > 0 {
|
||
userList.NewMessageNum = cnt
|
||
} else {
|
||
userList.NewMessageNum = 1
|
||
}
|
||
//存储当前数据
|
||
data, _ := json.Marshal(userList)
|
||
err = rdb.RPush(msgID, string(data))
|
||
ok, err := rdb.ExpireResult(msgID, ExpireTimeDay)
|
||
if err != nil || !ok {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// GetNewAndTrim 获取未读条数并清除旧数据
|
||
func GetNewAndTrim(key string, flag string) (cnt int, err error) {
|
||
cnt = 0
|
||
if n, err := rdb.Exists(key); n > 0 && err == nil {
|
||
s2 := rdb.LRange(key)
|
||
for i := 0; i < len(s2); i++ {
|
||
v := UserMessageList{}
|
||
_ = json.Unmarshal([]byte(s2[i]), &v)
|
||
if v.UserID == flag {
|
||
err = rdb.LSet(key, i, "del")
|
||
err = rdb.LRem(key, 0, "del")
|
||
s2 = append(s2[:i], s2[i+1:]...)
|
||
i--
|
||
if v.NewMessageNum == 0 { //目前为首条
|
||
cnt++ //赋值1
|
||
} else {
|
||
cnt = v.NewMessageNum
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
return 0, nil
|
||
}
|
||
return cnt, err
|
||
}
|
||
|
||
// GenMsgDetailID 生成查询详细聊天记录ID
|
||
func GenMsgDetailID(jxMsg *JXMsg, vendorID int, elmAppID string) (msgID string) {
|
||
//globals.SugarLogger.Debugf("GenMsgDetailID test0124 jxMsg=%s", utils.Format4Output(jxMsg, false))
|
||
if jxMsg == nil {
|
||
return ""
|
||
}
|
||
if vendorID == VendorIDMT {
|
||
var d1 = jxMsg.MsgContent.(mtwmapi.PushContentReq)
|
||
msgID = utils.Int2Str(d1.AppID) + ":" + d1.AppPoiCode + ":1:" + utils.Int2Str(d1.OpenUserID)
|
||
}
|
||
if vendorID == VendorIDELM {
|
||
var ElmData = ebaiapi.ImMessageSend{}
|
||
tempMsgContent, _ := json.Marshal(jxMsg.MsgContent)
|
||
if err := json.Unmarshal(tempMsgContent, &ElmData); err != nil {
|
||
return ""
|
||
}
|
||
//var d2 = jxMsg.MsgContent.(ebaiapi.ImMessageSend)
|
||
//msgID = elmAppID + ":" + d2.PlatformShopID + ":3:" + d2.PayLoad.GroupID
|
||
msgID = elmAppID + ":" + ElmData.PlatformShopID + ":3:" + ElmData.PayLoad.GroupID
|
||
}
|
||
return msgID
|
||
}
|
||
|
||
// GenMsgListID 生成展示列表时单条数据ID(部分)
|
||
func GenMsgListID(jxMsg *JXMsg, vendorID int, elmAppID string) (msgID string) {
|
||
|
||
//globals.SugarLogger.Debugf("GenMsgListID test0124 jxMsg=%s,vendorID=%d", utils.Format4Output(jxMsg, false), vendorID)
|
||
if jxMsg == nil {
|
||
return ""
|
||
}
|
||
if vendorID == VendorIDMT {
|
||
var d1 = jxMsg.MsgContent.(mtwmapi.PushContentReq)
|
||
msgID = utils.Int2Str(d1.AppID) + ":" + d1.AppPoiCode + ":1"
|
||
}
|
||
if vendorID == VendorIDELM {
|
||
var ElmData = ebaiapi.ImMessageSend{}
|
||
tempMsgContent, _ := json.Marshal(jxMsg.MsgContent)
|
||
err := json.Unmarshal(tempMsgContent, &ElmData)
|
||
fmt.Println(err)
|
||
//var d2 = jxMsg.MsgContent.(ebaiapi.ImMessageSend)
|
||
//msgID = elmAppID + ":" + d2.PlatformShopID + ":3"
|
||
msgID = elmAppID + ":" + ElmData.PlatformShopID + ":3"
|
||
|
||
}
|
||
return msgID
|
||
}
|
||
|
||
// GetImUserList 获取门店用户聊天列表
|
||
func GetImUserList(req []RelInfo) (map[string][]interface{}, error) {
|
||
retVal := make(map[string][]interface{}, 0)
|
||
if len(req) == 0 {
|
||
return nil, errors.New("msgID不允许为空")
|
||
}
|
||
var keys []string
|
||
for _, i := range req {
|
||
key := i.AppID + ":" + i.VendorStoreID + ":" + i.VendorID
|
||
keys = append(keys, key)
|
||
}
|
||
for _, j := range keys {
|
||
temp := rdb.LRange(j)
|
||
for _, v := range temp {
|
||
//过滤过期信息
|
||
if FilterUserList(v) {
|
||
retVal[j] = append(retVal[j], v)
|
||
}
|
||
}
|
||
}
|
||
return retVal, nil
|
||
}
|
||
|
||
func FilterUserList(val string) bool {
|
||
retVal := UserMessageList{}
|
||
err := json.Unmarshal([]byte(val), &retVal)
|
||
if err != nil || time.Now().Unix()-int64(retVal.LatestTime) >= 3600*6 {
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
// FilterChatDetail 去重
|
||
func FilterChatDetail(req *JXMsg, vendorID int) {
|
||
//if vendorID == VendorIDMT {
|
||
// mt := req.MsgContent.(mtwmapi.PushContentReq)
|
||
// temp, _ := GetImChatDetail([]UserRelInfo{{
|
||
// VendorStoreID: mt.AppPoiCode,
|
||
// VendorID: "1",
|
||
// AppID: utils.Int2Str(mt.AppID),
|
||
// UserID: utils.Int2Str(mt.OpenUserID),
|
||
// }})
|
||
//
|
||
//}
|
||
//
|
||
//if vendorID == VendorIDELM {
|
||
// elm := req.MsgContent.(ebaiapi.ImMessageSend)
|
||
// temp, _ := GetImChatDetail([]UserRelInfo{{
|
||
// VendorStoreID: elm.PlatformShopID,
|
||
// VendorID: "3",
|
||
// AppID: "34665",
|
||
// UserID: elm.PayLoad.SenderID,
|
||
// }})
|
||
//}
|
||
}
|
||
|
||
// GetImChatDetail 获取门店用户聊天详情
|
||
func GetImChatDetail(req []UserRelInfo) (map[string][]interface{}, error) {
|
||
retVal := make(map[string][]interface{}, 0)
|
||
if len(req) == 0 {
|
||
return nil, errors.New("msgID不允许为空")
|
||
}
|
||
var keys []string
|
||
for _, i := range req {
|
||
key := i.AppID + ":" + i.VendorStoreID + ":" + i.VendorID + ":" + i.UserID
|
||
keys = append(keys, key)
|
||
}
|
||
for _, j := range keys {
|
||
temp := rdb.LRange(j)
|
||
for _, v := range temp {
|
||
retVal[j] = append(retVal[j], v)
|
||
//retVal["chatDetail"] = append(retVal["chatDetail"], v)
|
||
}
|
||
}
|
||
return retVal, nil
|
||
}
|
||
|
||
// SetJxMsgRead 设置jx消息已读 userID(美团:openUserID;饿了么:groupID)
|
||
func SetJxMsgRead(appID, vendorStoreID, vendorID, userID string) error {
|
||
var (
|
||
temp = UserMessageList{}
|
||
key = appID + ":" + vendorStoreID + ":" + vendorID
|
||
)
|
||
if n, err := rdb.Exists(key); n > 0 && err == nil {
|
||
s2 := rdb.LRange(key)
|
||
for i := 0; i < len(s2); i++ {
|
||
v := UserMessageList{}
|
||
_ = json.Unmarshal([]byte(s2[i]), &v)
|
||
if v.UserID == userID {
|
||
//删除此条数据
|
||
err = rdb.LSet(key, i, "del")
|
||
err = rdb.LRem(key, 0, "del")
|
||
s2 = append(s2[:i], s2[i+1:]...)
|
||
i--
|
||
//cnt=0 重新赋值
|
||
temp = UserMessageList{
|
||
VendorID: v.VendorID,
|
||
UserID: v.UserID,
|
||
OrderID: v.OrderID,
|
||
NewMessageNum: 0,
|
||
LatestMsg: v.LatestMsg,
|
||
LatestTime: v.LatestTime,
|
||
}
|
||
}
|
||
}
|
||
str, _ := json.Marshal(temp)
|
||
err = rdb.RPush(key, str)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// AutoReply 是否已回复
|
||
//key=AppID+:+UserID+:+msgID(mt)
|
||
//key=AppID+:+UserID+:+msgID(elm)
|
||
type AutoReply struct {
|
||
UserID int `json:"userID"`
|
||
MsgID int `json:"msgID"` //消息ID
|
||
IsApply bool `json:"IsApply"` //是否已回复
|
||
Timestamp int `json:"timestamp"` //消息接收时间
|
||
}
|
||
|
||
// CheckAndReply 判断并回复V1
|
||
func CheckAndReply(req *JXMsg, elmAppID string) (err error) {
|
||
var (
|
||
key string
|
||
//keyDetail UserRelInfo
|
||
flag = false
|
||
vendorID int
|
||
errList errlist.ErrList
|
||
apply *AutoReply
|
||
jxMsg = &JXMsg{}
|
||
//userList = &UserMessageList{}
|
||
)
|
||
|
||
if req.SendType == SendTypeMt {
|
||
vendorID = VendorIDMT
|
||
mt := req.MsgContent.(mtwmapi.PushContentReq)
|
||
//跳过12小时内商家消息自动回复
|
||
if mt.MsgSource != mtwmapi.MsgSourceUser {
|
||
return nil
|
||
}
|
||
|
||
key = utils.Int2Str(mt.AppID) + ":" + utils.Int2Str(mt.OpenUserID) + ":autoReply"
|
||
keyDetailMt := UserRelInfo{
|
||
AppID: utils.Int2Str(mt.AppID),
|
||
VendorStoreID: mt.AppPoiCode,
|
||
VendorID: VendorIDMTStr,
|
||
UserID: utils.Int2Str(mt.OpenUserID),
|
||
}
|
||
//1 检测是否已自动回复
|
||
flag = GetIfReply(key, keyDetailMt)
|
||
//判断flag状态
|
||
if !flag {
|
||
apply = &AutoReply{
|
||
UserID: mt.AppID,
|
||
MsgID: mt.MsgID,
|
||
IsApply: true,
|
||
Timestamp: mt.Cts,
|
||
}
|
||
|
||
temp := mt
|
||
//获取自定义回复模板
|
||
if template := GetCustomTemplate(utils.Int2Str(mt.AppID), mt.AppPoiCode); len(template.Template) > 0 {
|
||
// 关闭自动回复
|
||
if template.Template == "3ASOkN9WiU3AUae2tYGChA==" {
|
||
return nil
|
||
}
|
||
temp.MsgContent = template.Template
|
||
} else {
|
||
temp.MsgContent, err = GetDefaultTemplate(utils.Int2Str(mt.AppID), mt.AppPoiCode, VendorIDMT)
|
||
if err != nil {
|
||
temp.MsgContent = AutoReplyByAppID[mt.AppID]
|
||
}
|
||
}
|
||
temp.MsgType = mtwmapi.MsgTypeText
|
||
temp.MsgSource = mtwmapi.MsgSourceStore
|
||
temp.Cts = int(time.Now().Unix())
|
||
temp.MsgID = RandTimeNumber()
|
||
|
||
dataStr, _ := json.Marshal(temp)
|
||
if _, err = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, utils.Int2Str(mt.AppID)).(*mtwmapi.API).MsgSend(string(dataStr)); err != nil {
|
||
apply.IsApply = false
|
||
globals.SugarLogger.Debugf("CheckAndReply mtSend err:%v", err)
|
||
} else {
|
||
jxMsg = &JXMsg{
|
||
SendType: SendTypeJx,
|
||
MsgContent: temp,
|
||
}
|
||
|
||
// 存储详细聊天记录
|
||
if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("自动回复:存储详细聊天记录错误:%v", err))
|
||
}
|
||
}
|
||
//3 记录自动回复状态
|
||
if err = RecordAutoStatus(key, apply); err != nil {
|
||
errList.AddErr(fmt.Errorf("自动回复:记录自动回复状态错误:%v", err))
|
||
}
|
||
}
|
||
}
|
||
|
||
if req.SendType == SendTypeElm {
|
||
vendorID = VendorIDELM
|
||
elm := req.MsgContent.(ebaiapi.ImMessageSend)
|
||
key = elmAppID + ":" + elm.PayLoad.SenderID + ":autoReply"
|
||
|
||
if elm.PayLoad.SenderID == "" || elm.PayLoad.SenderID[:2] != ebaiapi.SenderTypeUser {
|
||
return nil
|
||
}
|
||
|
||
keyDetailElm := UserRelInfo{
|
||
AppID: elmAppID,
|
||
VendorStoreID: elm.PlatformShopID,
|
||
VendorID: VendorIDELMStr,
|
||
UserID: elm.PayLoad.GroupID,
|
||
}
|
||
//1 检测是否已自动回复
|
||
flag = GetIfReply(key, keyDetailElm)
|
||
if !flag {
|
||
apply = &AutoReply{
|
||
UserID: utils.Str2Int(elm.PayLoad.SenderID),
|
||
MsgID: utils.Str2Int(elm.PayLoad.MsgID),
|
||
IsApply: true,
|
||
Timestamp: elm.PayLoad.CreateTime,
|
||
}
|
||
|
||
param := &ebaiapi.BusinessSendMsgReq{
|
||
PlatformShopId: elm.PlatformShopID,
|
||
BizType: ebaiapi.IMType,
|
||
SubBizType: ebaiapi.IMTypeSendMsg,
|
||
PayLoad: ebaiapi.BusinessMsgPayload{
|
||
GroupId: elm.PayLoad.GroupID,
|
||
MsgId: utils.Int2Str(RandTimeNumber()),
|
||
ReceiverIds: elm.PayLoad.ReceiverIDs,
|
||
ContentType: utils.Int2Str(ebaiapi.ContentTypeNormal),
|
||
},
|
||
}
|
||
|
||
temp := ""
|
||
if template := GetCustomTemplate(elmAppID, elm.PlatformShopID); len(template.Template) > 0 {
|
||
temp = template.Template
|
||
} else {
|
||
temp, err = GetDefaultTemplate(elmAppID, elm.PlatformShopID, VendorIDELM)
|
||
if err != nil {
|
||
temp = LastTemplate
|
||
}
|
||
}
|
||
tempStr, _ := json.Marshal(temp)
|
||
tempContent := ebaiapi.Content{
|
||
Text: string(tempStr),
|
||
//Text: temp,
|
||
}
|
||
tempContentStr, _ := json.Marshal(tempContent)
|
||
|
||
param.PayLoad.Content = string(tempContentStr)
|
||
|
||
if err = partner.CurAPIManager.GetAPI(model.VendorIDEBAI, elmAppID).(*ebaiapi.API).BusinessSendMsg(param); err != nil {
|
||
apply.IsApply = false
|
||
globals.SugarLogger.Debugf("CheckAndReply mtSend err:%v", err)
|
||
} else {
|
||
|
||
jxMsg = &JXMsg{
|
||
SendType: SendTypeJx,
|
||
MsgContent: param,
|
||
}
|
||
|
||
//存储详细聊天记录list
|
||
if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
|
||
errList.AddErr(fmt.Errorf("自动回复:存储详细聊天记录错误:%v", err))
|
||
}
|
||
}
|
||
//3 记录自动回复状态
|
||
if err = RecordAutoStatus(key, apply); err != nil {
|
||
errList.AddErr(fmt.Errorf("自动回复:记录自动回复状态错误:%v", err))
|
||
}
|
||
}
|
||
}
|
||
|
||
if errList.GetErrListAsOne() != nil {
|
||
return fmt.Errorf("CheckAndReply err=%v", errList.GetErrListAsOne())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// CheckAndReplyV2 判断并回复V2 延迟35s
|
||
//func CheckAndReplyV2(req *JXMsg, elmAppID string) (err error) {
|
||
// var (
|
||
// key string
|
||
// vendorID int
|
||
// errList errlist.ErrList
|
||
// jxMsg = &JXMsg{}
|
||
// )
|
||
//
|
||
// if req.SendType == SendTypeMt {
|
||
// vendorID = VendorIDMT
|
||
// mt := req.MsgContent.(mtwmapi.PushContentReq)
|
||
// //获取聊天详情
|
||
// imDetail, err := GetImChatDetail([]UserRelInfo{{
|
||
// VendorStoreID: mt.AppPoiCode,
|
||
// VendorID: VendorIDMTStr,
|
||
// AppID: utils.Int2Str(mt.AppID),
|
||
// UserID: utils.Int2Str(mt.OpenUserID),
|
||
// }})
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
// if len(imDetail) > 0 {
|
||
// //获取此消息列表最后一条数据
|
||
// key = GenMsgDetailID(req, VendorIDMT, elmAppID)
|
||
// temp := imDetail[key][len(imDetail)-1]
|
||
// tStr, _ := json.Marshal(temp)
|
||
//
|
||
// lastMsg := &JXMsg{}
|
||
// err = json.Unmarshal(tStr, lastMsg)
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
// //京西发送或美团商家发送 跳过
|
||
// if lastMsg.SendType == SendTypeJx {
|
||
// return nil
|
||
// }
|
||
//
|
||
// lastMt := lastMsg.MsgContent.(mtwmapi.PushContentReq)
|
||
// if lastMt.MsgSource == mtwmapi.MsgSourceStore {
|
||
// return nil
|
||
// }
|
||
//
|
||
// //生成回复消息体
|
||
// sendMt := mt
|
||
// //获取自定义回复模板
|
||
// if template := GetCustomTemplate(utils.Int2Str(mt.AppID), mt.AppPoiCode); len(template) > 0 {
|
||
// sendMt.MsgContent = template
|
||
// } else {
|
||
// sendMt.MsgContent, err = GetDefaultTemplate(utils.Int2Str(mt.AppID), mt.AppPoiCode, VendorIDMT)
|
||
// if err != nil {
|
||
// sendMt.MsgContent = AutoReplyByAppID[mt.AppID]
|
||
// }
|
||
// }
|
||
// sendMt.MsgType = mtwmapi.MsgTypeText
|
||
// sendMt.MsgSource = mtwmapi.MsgSourceStore
|
||
// sendMt.Cts = int(time.Now().Unix())
|
||
// sendMt.MsgID = RandTimeNumber()
|
||
//
|
||
// //向美团发送消息
|
||
// dataStr, _ := json.Marshal(sendMt)
|
||
// if _, err = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, utils.Int2Str(mt.AppID)).(*mtwmapi.API).MsgSend(string(dataStr)); err != nil {
|
||
// globals.SugarLogger.Debugf("CheckAndReply mtSend err:%v", err)
|
||
// return err
|
||
// } else {
|
||
// jxMsg = &JXMsg{
|
||
// SendType: SendTypeJx,
|
||
// MsgContent: temp,
|
||
// }
|
||
// if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
|
||
// errList.AddErr(fmt.Errorf("自动回复V2:存储详细聊天记录错误:%v", err))
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// if req.SendType == SendTypeElm {
|
||
// vendorID = VendorIDELM
|
||
// elm := req.MsgContent.(ebaiapi.ImMessageSend)
|
||
// imDetail, err := GetImChatDetail([]UserRelInfo{{
|
||
// VendorStoreID: elm.PlatformShopID,
|
||
// VendorID: VendorIDELMStr,
|
||
// AppID: elmAppID,
|
||
// UserID: elm.PayLoad.SenderID,
|
||
// }})
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
// if len(imDetail) > 0 {
|
||
// //获取此消息列表最后一条数据
|
||
// key = GenMsgDetailID(req, VendorIDELM, elmAppID)
|
||
// temp := imDetail[key][len(imDetail)-1]
|
||
// tStr, _ := json.Marshal(temp)
|
||
//
|
||
// lastMsg := &JXMsg{}
|
||
// err = json.Unmarshal(tStr, lastMsg)
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
// //京西发送或美团商家发送 跳过
|
||
// if lastMsg.SendType == SendTypeJx {
|
||
// return nil
|
||
// }
|
||
//
|
||
// //结构不一样后解
|
||
// lastElm := lastMsg.MsgContent.(ebaiapi.ImMessageSend)
|
||
// if lastElm.PayLoad.SenderID == "" || elm.PayLoad.SenderID[:2] != ebaiapi.SenderTypeUser {
|
||
// return nil
|
||
// }
|
||
//
|
||
// param := &ebaiapi.BusinessSendMsgReq{
|
||
// PlatformShopId: elm.PlatformShopID,
|
||
// BizType: ebaiapi.IMType,
|
||
// SubBizType: ebaiapi.IMTypeSendMsg,
|
||
// PayLoad: ebaiapi.BusinessMsgPayload{
|
||
// GroupId: elm.PayLoad.GroupID,
|
||
// MsgId: utils.Int2Str(RandTimeNumber()),
|
||
// ReceiverIds: elm.PayLoad.ReceiverIDs,
|
||
// ContentType: utils.Int2Str(ebaiapi.ContentTypeNormal),
|
||
// },
|
||
// }
|
||
//
|
||
// data := ""
|
||
// if template := GetCustomTemplate(elmAppID, elm.PlatformShopID); len(template) > 0 {
|
||
// data = template
|
||
// } else {
|
||
// data, err = GetDefaultTemplate(elmAppID, elm.PlatformShopID, VendorIDELM)
|
||
// if err != nil {
|
||
// data = LastTemplate
|
||
// }
|
||
// }
|
||
// dataStr, _ := json.Marshal(data)
|
||
// tempContent := ebaiapi.Content{
|
||
// Text: string(dataStr),
|
||
// }
|
||
// tempContentStr, _ := json.Marshal(tempContent)
|
||
// param.PayLoad.Content = string(tempContentStr)
|
||
//
|
||
// if err = partner.CurAPIManager.GetAPI(model.VendorIDEBAI, elmAppID).(*ebaiapi.API).BusinessSendMsg(param); err != nil {
|
||
// globals.SugarLogger.Debugf("CheckAndReply mtSend err:%v", err)
|
||
// return err
|
||
// } else {
|
||
// jxMsg = &JXMsg{
|
||
// SendType: SendTypeJx,
|
||
// MsgContent: param,
|
||
// }
|
||
// if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
|
||
// errList.AddErr(fmt.Errorf("自动回复V2:存储详细聊天记录错误:%v", err))
|
||
// }
|
||
// }
|
||
//
|
||
// }
|
||
//
|
||
// }
|
||
//
|
||
// if errList.GetErrListAsOne() != nil {
|
||
// return fmt.Errorf("CheckAndReplyV2 err=%v", errList.GetErrListAsOne())
|
||
// }
|
||
//
|
||
// return nil
|
||
//}
|
||
|
||
// GetIfReply 检查是否已回复
|
||
// 美团只需要第一条消息在一分钟之内回复就达标了,后面不需要自动回复了
|
||
func GetIfReply(key string, keyDetail UserRelInfo) (flag bool) {
|
||
flag = false
|
||
if n, err := rdb.Exists(key); n > 0 && err == nil {
|
||
str := rdb.LRange(key)
|
||
for i := 0; i < len(str); i++ {
|
||
v := AutoReply{}
|
||
if err = json.Unmarshal([]byte(str[i]), &v); err == nil {
|
||
flag = v.IsApply
|
||
}
|
||
}
|
||
}
|
||
|
||
//检测是否商家回复
|
||
var param []UserRelInfo
|
||
temp := append(param, keyDetail)
|
||
detail, err := GetImChatDetail(temp)
|
||
if err == nil && detail != nil {
|
||
tKey := keyDetail.AppID + ":" + keyDetail.VendorStoreID + ":" + keyDetail.VendorID + ":" + keyDetail.UserID
|
||
if detail[tKey] != nil {
|
||
for _, v := range detail[tKey] {
|
||
b := v.(string)
|
||
lastMsg := &JXMsg{}
|
||
err = json.Unmarshal([]byte(b), lastMsg)
|
||
if err != nil {
|
||
return false
|
||
}
|
||
switch keyDetail.VendorID {
|
||
case VendorIDMTStr:
|
||
mt := lastMsg.MsgContent.(map[string]interface{})
|
||
if mt["msg_source"].(float64) == mtwmapi.MsgSourceStore {
|
||
return true
|
||
}
|
||
case VendorIDELMStr:
|
||
elm := lastMsg.MsgContent.(map[string]interface{})
|
||
s := ""
|
||
if elm["payLoad"].(map[string]interface{})["senderId"] != nil {
|
||
s = elm["payLoad"].(map[string]interface{})["senderId"].(string)
|
||
}
|
||
if s == "" || s[:2] == ebaiapi.SenderTypeBusiness || s[:2] == ebaiapi.SenderTypeChainedAccountLogin || s[:2] == ebaiapi.SenderTypeSystem {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
//tDetail := detail[tKey][len(detail[tKey])-1]
|
||
//b := tDetail.(string)
|
||
//lastMsg := &JXMsg{}
|
||
//err = json.Unmarshal([]byte(b), lastMsg)
|
||
//if err != nil || lastMsg.SendType == SendTypeJx {
|
||
// return false
|
||
//}
|
||
//switch keyDetail.VendorID {
|
||
//case VendorIDMTStr:
|
||
// mt := lastMsg.MsgContent.(map[string]interface{})
|
||
// if mt["msg_source"].(float64) != mtwmapi.MsgSourceUser {
|
||
// return false
|
||
// }
|
||
//case VendorIDELMStr:
|
||
// elm := lastMsg.MsgContent.(map[string]interface{})
|
||
// s := elm["payLoad"].(map[string]interface{})["senderId"].(string)
|
||
// if s == "" || s[:2] != ebaiapi.SenderTypeUser {
|
||
// return false
|
||
// }
|
||
//}
|
||
}
|
||
}
|
||
return flag
|
||
}
|
||
|
||
// RecordAutoStatus 记录是否已自动回复状态
|
||
func RecordAutoStatus(key string, apply *AutoReply) error {
|
||
data, _ := json.Marshal(apply)
|
||
err := rdb.RPush(key, string(data))
|
||
ok, err := rdb.ExpireResult(key, ExpireTimeAutoReply)
|
||
if err != nil || !ok {
|
||
globals.SugarLogger.Debugf("CheckAndReply apply err:%v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// GenCustomReplyID 生成门店自动回复模板ID
|
||
func GenCustomReplyID(appID, vendorStoreID string) string {
|
||
return BaseCusKey + ":" + appID + ":" + vendorStoreID
|
||
}
|
||
|
||
// GetCustomTemplate 获取自动回复模板
|
||
func GetCustomTemplate(appID, vendorStoreID string) (storeTemplate StoreTemplate) {
|
||
var retVal string
|
||
key := GenCustomReplyID(appID, vendorStoreID)
|
||
|
||
data := rdb.LRange(key)
|
||
if data != nil {
|
||
retVal = data[0]
|
||
}
|
||
|
||
//temp := rdb.Get(key)
|
||
//temp := regexp.MustCompile(`^"(.*)"$`).ReplaceAllString(retVal, `$1`)
|
||
//storeTemplate = strings.Trim(retVal, "/")
|
||
//fmt.Println(temp)
|
||
temp := StoreTemplate{}
|
||
_ = json.Unmarshal([]byte(retVal), &temp)
|
||
|
||
storeTemplate = temp
|
||
|
||
return storeTemplate
|
||
}
|
||
|
||
// AddCustomReply 增加门店自定义回复模板
|
||
func AddCustomReply(appID, vendorStoreID, replyTemplate string) (storeTemplate string, err error) {
|
||
if len(appID) == 0 || len(vendorStoreID) == 0 {
|
||
return "", errors.New("参数错误请检查!")
|
||
}
|
||
|
||
key := GenCustomReplyID(appID, vendorStoreID)
|
||
|
||
template := StoreTemplate{
|
||
Template: replyTemplate,
|
||
}
|
||
data, _ := json.Marshal(template)
|
||
|
||
err = rdb.Del(key)
|
||
if err == nil && replyTemplate != "" {
|
||
err = rdb.RPush(key, data)
|
||
//err = rdb.Set(key, replyTemplate, 0)
|
||
}
|
||
return "", err
|
||
}
|
||
|
||
// GetDefaultTemplate 获取门店默认回复模板
|
||
func GetDefaultTemplate(appID, vendorStoreID string, vendorID int) (string, error) {
|
||
var (
|
||
phoneNum = " "
|
||
t string
|
||
)
|
||
store, err := dao.GetStoreDetailByVendorStoreID(dao.GetDB(), vendorStoreID, vendorID, "")
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
//if err != nil && err == orm.ErrNoRows {
|
||
// t = BasePhoneNum
|
||
//}
|
||
|
||
if len(store.Tel1) > 0 {
|
||
t = store.Tel1
|
||
}
|
||
|
||
phoneNum = t[:3] + "-" + t[3:7] + "-" + t[7:]
|
||
temp := BaseTemplate + phoneNum
|
||
|
||
if vendorID == VendorIDMT {
|
||
data, err := EncryptIm(utils.Str2Int(appID), temp)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return data, nil
|
||
}
|
||
if vendorID == VendorIDELM {
|
||
return temp, nil
|
||
}
|
||
|
||
return "", nil
|
||
}
|
||
|
||
/************************工具函数*/
|
||
|
||
// DelRedisByKey 清除redis数据
|
||
func DelRedisByKey(keys []string) {
|
||
var errList errlist.ErrList
|
||
for _, key := range keys {
|
||
err := rdb.Del(key)
|
||
if err != nil {
|
||
errList.AddErr(err)
|
||
}
|
||
}
|
||
if errList.GetErrListAsOne() != nil {
|
||
globals.SugarLogger.Debugf("DelRedisByKey err=%v", errList.GetErrListAsOne())
|
||
}
|
||
return
|
||
}
|
||
|
||
var rel = map[int]string{
|
||
589: "a81eb3df418d83d6a1a4b7c572156d2f",
|
||
5873: "41c479790a76f86326f89e8048964739",
|
||
4123: "df2c88338b85f830cebce2a9eab56628",
|
||
}
|
||
|
||
// DecryptIm 解密操作
|
||
func DecryptIm(appID int, msg string) (string, error) {
|
||
data, _ := base64.StdEncoding.DecodeString(msg)
|
||
key := utils.LimitUTF8StringLen2(rel[appID], 16)
|
||
res, err := utils.AESCBCDecpryt(data, []byte(key), []byte(key))
|
||
if len(string(res)) > 0 && err == nil {
|
||
return string(res), nil
|
||
}
|
||
return "", err
|
||
}
|
||
|
||
// EncryptIm 加密操作
|
||
func EncryptIm(appID int, msg string) (retVal string, err error) {
|
||
key := utils.LimitUTF8StringLen2(rel[appID], 16)
|
||
if data, err := utils.AESCBCEncpryt([]byte(msg), []byte(key), []byte(key)); err == nil {
|
||
retVal = base64.StdEncoding.EncodeToString(data)
|
||
}
|
||
return retVal, err
|
||
}
|
||
|
||
// FilterIm 过滤操作
|
||
func FilterIm(appID int, msg string) bool {
|
||
var check = "[自动回复]"
|
||
data, _ := DecryptIm(appID, msg)
|
||
if len(data) > 0 && strings.Contains(data, check) {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
// RandTimeNumber 生成int类型 随机数+时间戳
|
||
func RandTimeNumber() int {
|
||
num, _ := rand.Int(rand.Reader, big.NewInt(100000))
|
||
str := utils.Int64ToStr(num.Int64()) + utils.Int2Str(int(time.Now().Unix()))
|
||
return utils.Str2Int(str)
|
||
}
|