This commit is contained in:
richboo111
2023-04-25 16:52:01 +08:00
parent 2e8b699b4f
commit a3a663c729
9 changed files with 1032 additions and 1128 deletions

View File

@@ -1,95 +0,0 @@
package cms
import (
"encoding/json"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api"
)
// JXMsg 京西消息结构体
type JXMsg struct {
SendType string `json:"sendType"` //消息发送方 jx-商家mt-美团elm-饿了么
Data interface{} `json:"data"` //美团/饿了么 单聊消息
}
var (
rdb = api.Cacher
)
const (
SendTypeJx = "jx" //消息发送方jx标识符
ExpireTimeDay = 24 * time.Hour //redis一天过期时间
)
// GetUserList 查询门店-用户消息列表(与当前商铺聊天的所有用户) appid:vendorStoreID:10/11(mt/elm)
func GetUserList(keys []string) (retVal []interface{}) {
if len(keys) == 0 {
return nil
}
for _, v := range keys {
if value := rdb.Get(v); value != nil {
retVal = append(retVal, value)
}
}
if len(retVal) > 0 {
return retVal
}
return nil
}
// GetOneUserDetail 获取当前用户(单个)所有聊天记录 appID:vendorStoreID:10:userID
func GetOneUserDetail(msgID string) (retVal interface{}) {
if retVal = rdb.Get(msgID); retVal != nil {
return retVal
}
return nil
}
// SetMessageDetail 存储门店用户聊天detail 门店发送
func SetMessageDetail(data interface{}, vendorID string) error {
if vendorID == model.IMVendorIDMT {
param := JXMsg{
SendType: SendTypeJx,
Data: data,
}
//生成与美团消息id
req := data.(mtwmapi.SingleChat)
key := GenMtMsgDetailID(req.AppPoiCode, req.AppID, req.OpenUserID)
//存储
paramM, _ := json.Marshal(param)
err := rdb.RPush(key, string(paramM))
ok, err := rdb.ExpireResult(key, ExpireTimeDay)
if err != nil || !ok {
return err
}
}
if vendorID == model.IMVendorIDELM {
}
return nil
}
//1 美团
// GenMtMsgDetailID 生成查询详细聊天记录ID
func GenMtMsgDetailID(vendorStoreID string, appID, userID int) string {
temp := utils.Int2Str(appID) + ":" + vendorStoreID + ":10:" + utils.Int2Str(userID)
return temp
}
// SetMessageRead 平台方设置消息已读(不使用)
//func SetMessageRead(msgID, vendorStoreID, vendorID string) (err error) {
// if vendorID == model.IMVendorIDMT {
// err = api.MtwmAPI.MsgRead(vendorStoreID, msgID, vendorID)
//
// }
// if vendorID == model.IMVendorIDELM {
//
// }
// return nil
//}

View File

@@ -12,13 +12,13 @@ type ICacher interface {
GetAs(key string, ptr interface{}) error GetAs(key string, ptr interface{}) error
Keys(prefix string) ([]string, error) Keys(prefix string) ([]string, error)
FlushDB() error //FlushDB() error
Incr(key string) error //Incr(key string) error
LRange(key string) (retVal []string) //LRange(key string) (retVal []string)
Exists(keys ...string) (int64, error) //Exists(keys ...string) (int64, error)
RPush(key string, value interface{}) error //RPush(key string, value interface{}) error
Expire(key string, expiration time.Duration) error //Expire(key string, expiration time.Duration) error
LRem(key string, count int, value interface{}) error //LRem(key string, count int, value interface{}) error
LSet(key string, index int, value interface{}) error //LSet(key string, index int, value interface{}) error
ExpireResult(key string, expiration time.Duration) (bool, error) //ExpireResult(key string, expiration time.Duration) (bool, error)
} }

View File

@@ -1,12 +1,7 @@
package ebai package ebai
import ( import (
"encoding/json"
"git.rosy.net.cn/jx-callback/business/partner/purchase/im"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi" "git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/jx-callback/globals/api"
) )
const ( const (
@@ -15,9 +10,9 @@ const (
// OnImMessage 用户/骑手 发送/已读消息 回调 // OnImMessage 用户/骑手 发送/已读消息 回调
func (p *PurchaseHandler) OnImMessage(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) { func (p *PurchaseHandler) OnImMessage(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
str, err := json.Marshal(msg.Data) //str, err := json.Marshal(msg.Data)
im.ReadMsgFromVendor(IMVendorIDELM, msg.Source, str) //im.ReadMsgFromVendor(IMVendorIDELM, msg.Source, str)
return nil
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil) //return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
} }

View File

@@ -1,355 +1,356 @@
package im package im
import ( //
"encoding/json" //import (
"errors" // "encoding/json"
"fmt" // "errors"
"net/http" // "fmt"
// "net/http"
"git.rosy.net.cn/jx-callback/globals" //
// "git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi" //
// "git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi" //
"git.rosy.net.cn/baseapi/utils" // "git.rosy.net.cn/baseapi/platformapi/mtwmapi"
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush" // "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals/api" // push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
"github.com/gorilla/websocket" // "git.rosy.net.cn/jx-callback/globals/api"
) // "github.com/gorilla/websocket"
//)
// SendToVendor 向平台发消息 //
func SendToVendor(msg []byte) { //// SendToVendor 向平台发消息
var ( //func SendToVendor(msg []byte) {
w http.ResponseWriter // var (
sendData SendData // w http.ResponseWriter
err error // sendData SendData
elmAppID = api.EbaiAPI.GetSource() // err error
) // elmAppID = api.EbaiAPI.GetSource()
// )
//解析数据 //
if err = json.Unmarshal(msg, &sendData); err != nil { // //解析数据
return // if err = json.Unmarshal(msg, &sendData); err != nil {
} // return
// }
//存储数据 //
ReadMsgFromClient(sendData.VendorID, elmAppID, sendData.Data) // //存储数据
// ReadMsgFromClient(sendData.VendorID, elmAppID, sendData.Data)
//发送信息 //
if sendData.VendorID == VendorIDMT { // //发送信息
temp, _ := json.Marshal(sendData.Data) // if sendData.VendorID == VendorIDMT {
Send(temp) // temp, _ := json.Marshal(sendData.Data)
} // Send(temp)
if sendData.VendorID == VendorIDELM { // }
param := sendData.Data.(ebaiapi.BusinessSendMsgReq) // if sendData.VendorID == VendorIDELM {
if err := api.EbaiAPI.BusinessSendMsg(&param); err != nil { // param := sendData.Data.(ebaiapi.BusinessSendMsgReq)
globals.SugarLogger.Debugf("elm发送信息错误%v", err) // if err := api.EbaiAPI.BusinessSendMsg(&param); err != nil {
return // globals.SugarLogger.Debugf("elm发送信息错误%v", err)
} // return
} // }
// }
if err != nil { //
ClientRender(w, Fail, FailMsg, map[string]string{ // if err != nil {
"errMsg": fmt.Sprintf("%v", err), // ClientRender(w, Fail, FailMsg, map[string]string{
}) // "errMsg": fmt.Sprintf("%v", err),
} else { // })
ClientRender(w, SuccessCode, SuccessMsg, map[string]interface{}{ // } else {
"vendorID": sendData.VendorID, // ClientRender(w, SuccessCode, SuccessMsg, map[string]interface{}{
"msg": "ok", // "vendorID": sendData.VendorID,
}) // "msg": "ok",
} // })
return // }
} // return
//}
func Send(data []byte) { //
//生成完整url //func Send(data []byte) {
fullUrl := GenFullUrl() //clientID暂时不用 // //生成完整url
// fullUrl := GenFullUrl() //clientID暂时不用
conn, resp, err := websocket.DefaultDialer.Dial(fullUrl, nil) //
if err != nil || resp.StatusCode != 101 { // conn, resp, err := websocket.DefaultDialer.Dial(fullUrl, nil)
fmt.Printf("连接失败:%v http响应不成功", err) // if err != nil || resp.StatusCode != 101 {
} // fmt.Printf("连接失败:%v http响应不成功", err)
//关闭 // }
defer func(conn *websocket.Conn) { // //关闭
err := conn.Close() // defer func(conn *websocket.Conn) {
if err != nil { // err := conn.Close()
return // if err != nil {
} // return
}(conn) // }
// }(conn)
err = conn.WriteMessage(websocket.TextMessage, data) //
if err != nil { // err = conn.WriteMessage(websocket.TextMessage, data)
fmt.Println(err) // if err != nil {
} // fmt.Println(err)
// }
for { //
_, msg, err := conn.ReadMessage() // for {
if err != nil { // _, msg, err := conn.ReadMessage()
break // if err != nil {
} else { // break
temp := string(msg) // } else {
if temp != HeartCheckSuccess { // temp := string(msg)
ReadMsgFromVendor(VendorIDMT, "", msg) // if temp != HeartCheckSuccess {
} // ReadMsgFromVendor(VendorIDMT, "", msg)
} // }
fmt.Printf("%s receive: %s\n", conn.RemoteAddr(), string(msg)) // }
} // fmt.Printf("%s receive: %s\n", conn.RemoteAddr(), string(msg))
} // }
//}
// ReadMsgFromClient 存储客户端发送的消息 //
func ReadMsgFromClient(vendorID int, elmAppID string, msg interface{}) { //// ReadMsgFromClient 存储客户端发送的消息
var ( //func ReadMsgFromClient(vendorID int, elmAppID string, msg interface{}) {
err error // var (
jxMsg = &JXMsg{} // err error
userList = &UserMessageList{} // jxMsg = &JXMsg{}
) // userList = &UserMessageList{}
// )
data, err := json.Marshal(msg) //
if err != nil { // data, err := json.Marshal(msg)
return // if err != nil {
} // return
// }
if vendorID == VendorIDMT { //
var MtSingleChat = mtwmapi.SingleChat{} // if vendorID == VendorIDMT {
err = json.Unmarshal(data, &MtSingleChat) // var MtSingleChat = mtwmapi.SingleChat{}
jxMsg = &JXMsg{ // err = json.Unmarshal(data, &MtSingleChat)
SendType: SendTypeJx, // jxMsg = &JXMsg{
Data: MtSingleChat, // SendType: SendTypeJx,
} // Data: MtSingleChat,
userList = &UserMessageList{ // }
VendorID: VendorIDMT, // userList = &UserMessageList{
UserID: utils.Int2Str(MtSingleChat.OpenUserID), // VendorID: VendorIDMT,
LatestMsg: MtSingleChat.MsgContent, // UserID: utils.Int2Str(MtSingleChat.OpenUserID),
LatestTime: MtSingleChat.Cts, // LatestMsg: MtSingleChat.MsgContent,
} // LatestTime: MtSingleChat.Cts,
} // }
if vendorID == VendorIDELM { // }
var ElmData = ebaiapi.ImMessageSend{} // if vendorID == VendorIDELM {
err = json.Unmarshal(data, &ElmData) // var ElmData = ebaiapi.ImMessageSend{}
jxMsg = &JXMsg{ // err = json.Unmarshal(data, &ElmData)
SendType: SendTypeJx, // jxMsg = &JXMsg{
Data: ElmData, // SendType: SendTypeJx,
} // Data: ElmData,
userList = &UserMessageList{ // }
VendorID: VendorIDMT, // userList = &UserMessageList{
UserID: ElmData.PayLoad.GroupID, // VendorID: VendorIDMT,
LatestMsg: ElmData.PayLoad.Content, // UserID: ElmData.PayLoad.GroupID,
LatestTime: int(ElmData.PayLoad.CreateTime), // LatestMsg: ElmData.PayLoad.Content,
} // LatestTime: int(ElmData.PayLoad.CreateTime),
} // }
// }
//1 存储详细聊天记录list //
if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil { // //1 存储详细聊天记录list
return // if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
} // return
//2 存储展示列表时单条数据 // }
if err = SetUserList(jxMsg, userList, vendorID, elmAppID); err != nil { // //2 存储展示列表时单条数据
return // if err = SetUserList(jxMsg, userList, vendorID, elmAppID); err != nil {
} // return
} // }
//}
// ReadMsgFromVendor 读取数据并存储到redis //
func ReadMsgFromVendor(vendorID int, elmAppID string, msg []byte) { //// ReadMsgFromVendor 读取数据并存储到redis
if string(msg) == "" { //func ReadMsgFromVendor(vendorID int, elmAppID string, msg []byte) {
return // if string(msg) == "" {
} // return
var ( // }
err error // var (
vendorStoreID string // err error
jxMsg = &JXMsg{} // vendorStoreID string
userList = &UserMessageList{} // jxMsg = &JXMsg{}
) // userList = &UserMessageList{}
if vendorID == VendorIDMT { // )
var MtSingleChat = mtwmapi.SingleChat{} // if vendorID == VendorIDMT {
err = json.Unmarshal(msg, &MtSingleChat) // var MtSingleChat = mtwmapi.SingleChat{}
jxMsg = &JXMsg{ // err = json.Unmarshal(msg, &MtSingleChat)
SendType: SendTypeMt, // jxMsg = &JXMsg{
Data: MtSingleChat, // SendType: SendTypeMt,
} // Data: MtSingleChat,
userList = &UserMessageList{ // }
VendorID: VendorIDMT, // userList = &UserMessageList{
UserID: utils.Int2Str(MtSingleChat.OpenUserID), // VendorID: VendorIDMT,
LatestMsg: MtSingleChat.MsgContent, // UserID: utils.Int2Str(MtSingleChat.OpenUserID),
LatestTime: MtSingleChat.Cts, // LatestMsg: MtSingleChat.MsgContent,
} // LatestTime: MtSingleChat.Cts,
vendorStoreID = MtSingleChat.AppPoiCode // }
} // vendorStoreID = MtSingleChat.AppPoiCode
if vendorID == VendorIDELM { // }
var ElmData = ebaiapi.ImMessageSend{} // if vendorID == VendorIDELM {
err = json.Unmarshal(msg, &ElmData) // var ElmData = ebaiapi.ImMessageSend{}
jxMsg = &JXMsg{ // err = json.Unmarshal(msg, &ElmData)
SendType: SendTypeElm, // jxMsg = &JXMsg{
Data: ElmData, // SendType: SendTypeElm,
} // Data: ElmData,
userList = &UserMessageList{ // }
VendorID: VendorIDMT, // userList = &UserMessageList{
UserID: ElmData.PayLoad.GroupID, // VendorID: VendorIDMT,
LatestMsg: ElmData.PayLoad.Content, // UserID: ElmData.PayLoad.GroupID,
LatestTime: int(ElmData.PayLoad.CreateTime), // LatestMsg: ElmData.PayLoad.Content,
} // LatestTime: int(ElmData.PayLoad.CreateTime),
} // }
// }
//1 存储详细聊天记录list //
if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil { // //1 存储详细聊天记录list
return // if err = SetMessageDetail(jxMsg, vendorID, elmAppID); err != nil {
} // return
//2 存储展示列表时单条数据 // }
if err = SetUserList(jxMsg, userList, vendorID, elmAppID); err != nil { // //2 存储展示列表时单条数据
return // if err = SetUserList(jxMsg, userList, vendorID, elmAppID); err != nil {
} // return
//3 cid推送新消息 // }
err = PushMsgByCid(vendorStoreID, vendorID) // //3 cid推送新消息
//4 长链接通知给客户端 // err = PushMsgByCid(vendorStoreID, vendorID)
ToClientChan <- clientInfo{Code: SuccessCode, Msg: fmt.Sprintf("%v", err), Data: jxMsg} // //4 长链接通知给客户端
} // ToClientChan <- clientInfo{Code: SuccessCode, Msg: fmt.Sprintf("%v", err), Data: jxMsg}
//}
// PushMsgByCid 通过cid push用户 //
func PushMsgByCid(vendorStoreID string, vendorID int) error { //// PushMsgByCid 通过cid push用户
if err := push.NotifyImNewMessage(vendorStoreID, vendorID); err != nil { //func PushMsgByCid(vendorStoreID string, vendorID int) error {
return err // if err := push.NotifyImNewMessage(vendorStoreID, vendorID); err != nil {
} // return err
return nil // }
} // return nil
//}
// SetMessageDetail 赋值 //
//格式 AppID:AppPoiCode:10:OpenUserID //// SetMessageDetail 赋值
func SetMessageDetail(req *JXMsg, vendorID int, elmAppID string) error { ////格式 AppID:AppPoiCode:10:OpenUserID
//生成京西消息ID detail //func SetMessageDetail(req *JXMsg, vendorID int, elmAppID string) error {
msgID := GenMsgDetailID(req, vendorID, elmAppID) // //生成京西消息ID detail
// msgID := GenMsgDetailID(req, vendorID, elmAppID)
data, _ := json.Marshal(req) //
err := rdb.RPush(msgID, string(data)) // data, _ := json.Marshal(req)
ok, err := rdb.ExpireResult(msgID, ExpireTimeDay) // err := rdb.RPush(msgID, string(data))
if err != nil || !ok { // ok, err := rdb.ExpireResult(msgID, ExpireTimeDay)
return err // if err != nil || !ok {
} // return err
return nil // }
} // return nil
//}
// SetUserList 赋值 //
//AppPoiCode:10 [userid1:{SingleChat},userid2:{}] //// SetUserList 赋值
func SetUserList(jxMsg *JXMsg, userList *UserMessageList, vendorID int, elmAppID string) error { ////AppPoiCode:10 [userid1:{SingleChat},userid2:{}]
//生成msgID //func SetUserList(jxMsg *JXMsg, userList *UserMessageList, vendorID int, elmAppID string) error {
msgID := GenMsgListID(jxMsg, vendorID, elmAppID) // //生成msgID
// msgID := GenMsgListID(jxMsg, vendorID, elmAppID)
//获取未读消息条数并删除旧数据 //
cnt, err := GetNewAndTrim(msgID, userList.UserID) // //获取未读消息条数并删除旧数据
if cnt > 0 { // cnt, err := GetNewAndTrim(msgID, userList.UserID)
userList.NewMessageNum = cnt // if cnt > 0 {
} else { // userList.NewMessageNum = cnt
userList.NewMessageNum = 1 // } else {
} // userList.NewMessageNum = 1
//存储当前数据 // }
data, _ := json.Marshal(userList) // //存储当前数据
err = rdb.RPush(msgID, string(data)) // data, _ := json.Marshal(userList)
// err = rdb.RPush(msgID, string(data))
ok, err := rdb.ExpireResult(msgID, ExpireTimeDay) //
if err != nil || !ok { // ok, err := rdb.ExpireResult(msgID, ExpireTimeDay)
return err // if err != nil || !ok {
} // return err
return nil // }
} // return nil
//}
// GetNewAndTrim 获取未读条数并清除旧数据 //
func GetNewAndTrim(key string, flag string) (cnt int, err error) { //// GetNewAndTrim 获取未读条数并清除旧数据
cnt = 0 //func GetNewAndTrim(key string, flag string) (cnt int, err error) {
if n, err := rdb.Exists(key); n > 0 && err == nil { // cnt = 0
s2 := rdb.LRange(key) // if n, err := rdb.Exists(key); n > 0 && err == nil {
for i := 0; i < len(s2); i++ { // s2 := rdb.LRange(key)
v := UserMessageList{} // for i := 0; i < len(s2); i++ {
_ = json.Unmarshal([]byte(s2[i]), &v) // v := UserMessageList{}
if v.UserID == flag { // _ = json.Unmarshal([]byte(s2[i]), &v)
err = rdb.LSet(key, i, "del") // if v.UserID == flag {
err = rdb.LRem(key, 0, "del") // err = rdb.LSet(key, i, "del")
s2 = append(s2[:i], s2[i+1:]...) // err = rdb.LRem(key, 0, "del")
i-- // s2 = append(s2[:i], s2[i+1:]...)
if v.NewMessageNum == 0 { //目前为首条 // i--
cnt++ //赋值1 // if v.NewMessageNum == 0 { //目前为首条
} else { // cnt++ //赋值1
cnt = v.NewMessageNum // } else {
} // cnt = v.NewMessageNum
} // }
} // }
} else { // }
return 0, nil // } else {
} // return 0, nil
return cnt, err // }
} // return cnt, err
//}
// GenMsgDetailID 生成查询详细聊天记录ID //
func GenMsgDetailID(jxMsg *JXMsg, vendorID int, elmAppID string) (msgID string) { //// GenMsgDetailID 生成查询详细聊天记录ID
if vendorID == VendorIDMT { //func GenMsgDetailID(jxMsg *JXMsg, vendorID int, elmAppID string) (msgID string) {
var d1 = jxMsg.Data.(mtwmapi.SingleChat) // if vendorID == VendorIDMT {
msgID = utils.Int2Str(d1.AppID) + ":" + d1.AppPoiCode + ":10:" + utils.Int2Str(d1.OpenUserID) // var d1 = jxMsg.Data.(mtwmapi.SingleChat)
} // msgID = utils.Int2Str(d1.AppID) + ":" + d1.AppPoiCode + ":10:" + utils.Int2Str(d1.OpenUserID)
if vendorID == VendorIDELM { // }
var d2 = jxMsg.Data.(ebaiapi.ImMessageSend) // if vendorID == VendorIDELM {
msgID = elmAppID + ":" + d2.PlatformShopID + ":11:" + d2.PayLoad.GroupID // var d2 = jxMsg.Data.(ebaiapi.ImMessageSend)
} // msgID = elmAppID + ":" + d2.PlatformShopID + ":11:" + d2.PayLoad.GroupID
return msgID // }
} // return msgID
//}
// GenMsgListID 生成展示列表时单条数据ID部分 //
func GenMsgListID(jxMsg *JXMsg, vendorID int, elmAppID string) (msgID string) { //// GenMsgListID 生成展示列表时单条数据ID部分
if vendorID == VendorIDMT { //func GenMsgListID(jxMsg *JXMsg, vendorID int, elmAppID string) (msgID string) {
var d1 = jxMsg.Data.(mtwmapi.SingleChat) // if vendorID == VendorIDMT {
msgID = utils.Int2Str(d1.AppID) + ":" + d1.AppPoiCode + ":10" // var d1 = jxMsg.Data.(mtwmapi.SingleChat)
} // msgID = utils.Int2Str(d1.AppID) + ":" + d1.AppPoiCode + ":10"
if vendorID == VendorIDELM { // }
var d2 = jxMsg.Data.(ebaiapi.ImMessageSend) // if vendorID == VendorIDELM {
msgID = elmAppID + ":" + d2.PlatformShopID + ":11" // var d2 = jxMsg.Data.(ebaiapi.ImMessageSend)
} // msgID = elmAppID + ":" + d2.PlatformShopID + ":11"
return msgID // }
} // return msgID
//}
// GetImUserList 获取门店用户聊天列表 //
func GetImUserList(req []RelInfo) (retVal []interface{}, err error) { //// GetImUserList 获取门店用户聊天列表
if len(req) == 0 { //func GetImUserList(req []RelInfo) (retVal []interface{}, err error) {
return nil, errors.New("msgID不允许为空") // if len(req) == 0 {
} // return nil, errors.New("msgID不允许为空")
var keys []string // }
for _, i := range req { // var keys []string
key := i.AppID + ":" + i.VendorStoreID + ":" + i.VendorID // for _, i := range req {
keys = append(keys, key) // key := i.AppID + ":" + i.VendorStoreID + ":" + i.VendorID
} // keys = append(keys, key)
for _, j := range keys { // }
temp := rdb.Get(j) // for _, j := range keys {
retVal = append(retVal, temp) // temp := rdb.Get(j)
} // retVal = append(retVal, temp)
return retVal, err // }
} // return retVal, err
//}
// GetImChatDetail 获取门店用户聊天详情 //
func GetImChatDetail(req []UserRelInfo) (retVal []interface{}, err error) { //// GetImChatDetail 获取门店用户聊天详情
if len(req) == 0 { //func GetImChatDetail(req []UserRelInfo) (retVal []interface{}, err error) {
return nil, errors.New("msgID不允许为空") // if len(req) == 0 {
} // return nil, errors.New("msgID不允许为空")
var keys []string // }
for _, i := range req { // var keys []string
key := i.AppID + ":" + i.VendorStoreID + ":" + i.VendorID + ":" + i.UserID // for _, i := range req {
keys = append(keys, key) // key := i.AppID + ":" + i.VendorStoreID + ":" + i.VendorID + ":" + i.UserID
} // keys = append(keys, key)
for _, j := range keys { // }
temp := rdb.Get(j) // for _, j := range keys {
retVal = append(retVal, temp) // temp := rdb.Get(j)
} // retVal = append(retVal, temp)
return retVal, err // }
} // return retVal, err
//}
// SetJxMsgRead 设置jx消息已读 userID(美团openUserID;饿了么groupID) //
func SetJxMsgRead(appID, vendorStoreID, vendorID, userID string) error { //// SetJxMsgRead 设置jx消息已读 userID(美团openUserID;饿了么groupID)
key := appID + ":" + vendorStoreID + ":" + vendorID //func SetJxMsgRead(appID, vendorStoreID, vendorID, userID string) error {
if n, err := rdb.Exists(key); n > 0 && err == nil { // key := appID + ":" + vendorStoreID + ":" + vendorID
s2 := rdb.LRange(key) // if n, err := rdb.Exists(key); n > 0 && err == nil {
for i := 0; i < len(s2); i++ { // s2 := rdb.LRange(key)
v := UserMessageList{} // for i := 0; i < len(s2); i++ {
_ = json.Unmarshal([]byte(s2[i]), &v) // v := UserMessageList{}
if v.UserID == userID { // _ = json.Unmarshal([]byte(s2[i]), &v)
err = rdb.LSet(key, i, "del") // if v.UserID == userID {
err = rdb.LRem(key, 0, "del") // err = rdb.LSet(key, i, "del")
s2 = append(s2[:i], s2[i+1:]...) // err = rdb.LRem(key, 0, "del")
i-- // s2 = append(s2[:i], s2[i+1:]...)
} // i--
} // }
} // }
return nil // }
} // return nil
//}

View File

@@ -1,275 +1,276 @@
package im package im
import ( //
"encoding/json" //import (
"flag" // "encoding/json"
"fmt" // "flag"
"git.rosy.net.cn/baseapi/utils" // "fmt"
"io" // "git.rosy.net.cn/baseapi/utils"
"log" // "io"
"net" // "log"
"net/http" // "net"
"sync" // "net/http"
"time" // "sync"
// "time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi" //
"git.rosy.net.cn/jx-callback/globals/api" // "git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"github.com/gazeboxu/mapstructure" // "git.rosy.net.cn/jx-callback/globals/api"
"github.com/gorilla/websocket" // "github.com/gazeboxu/mapstructure"
"gopkg.in/ini.v1" // "github.com/gorilla/websocket"
) // "gopkg.in/ini.v1"
//)
// ClientManager 连接管理 //
type ClientManager struct { //// ClientManager 连接管理
ClientIdMap map[string]*Client // 全部的连接 //type ClientManager struct {
ClientIdMapLock sync.RWMutex // 读写锁 // ClientIdMap map[string]*Client // 全部的连接
// ClientIdMapLock sync.RWMutex // 读写锁
Connect chan *Client // 连接处理 //
DisConnect chan *Client // 断开连接处理 // Connect chan *Client // 连接处理
// DisConnect chan *Client // 断开连接处理
GroupLock sync.RWMutex //
Groups map[string][]string // GroupLock sync.RWMutex
// Groups map[string][]string
SystemClientsLock sync.RWMutex //
SystemClients map[string][]string // SystemClientsLock sync.RWMutex
} // SystemClients map[string][]string
//}
// Client 客户端连接信息 //
type Client struct { //// Client 客户端连接信息
ClientId string // 标识ID //type Client struct {
Socket *websocket.Conn // 用户连接 // ClientId string // 标识ID
ConnectTime uint64 // 首次连接时间 // Socket *websocket.Conn // 用户连接
IsDeleted bool // 是否删除或下线 // ConnectTime uint64 // 首次连接时间
UserId string // 业务端标识用户ID // IsDeleted bool // 是否删除或下线
//Extend string // 扩展字段,用户可以自定义 // UserId string // 业务端标识用户ID
//GroupList []string // //Extend string // 扩展字段,用户可以自定义
} // //GroupList []string
//}
//channel通道结构体 //
type clientInfo struct { ////channel通道结构体
ClientId string `json:"clientId" validate:"required"` //链接ID //type clientInfo struct {
Data interface{}
SendUserId string
MessageId string
Code int
Msg string
}
// RetData 统一返回值结构体
type RetData struct {
Code int `json:"code"` //响应code
Msg string `json:"msg"` //响应msg success/fail
Data interface{} `json:"data"` //信息
//MessageType string `json:"messageType"` //消息类型 heart-心跳检测send-发送消息receive-接收消息
//MessageId string `json:"messageId"` //发送/接收信息 id
//UserId string `json:"userId"` //必须是平台方userID
}
type global struct {
LocalHost string //本机内网IP
ServerList map[string]string
ServerListLock sync.RWMutex
}
type commonConf struct {
HttpPort string
RPCPort string
Cluster bool
CryptoKey string
}
// SendData 客户端写入参数
type SendData struct {
// ClientId string `json:"clientId" validate:"required"` //链接ID // ClientId string `json:"clientId" validate:"required"` //链接ID
VendorID int `json:"vendorID"` //消息来源平台ID // Data interface{}
Data interface{} `json:"data"` //发送给平台 美团/饿了么消息结构体 // SendUserId string
//返回值 // MessageId string
//Code int `json:"code"` // Code int
//Msg string `json:"msg"` // Msg string
//SendUserId string `json:"sendUserId"` //}
} //
//// RetData 统一返回值结构体
// JXMsg 京西消息结构体 //type RetData struct {
type JXMsg struct { // Code int `json:"code"` //响应code
SendType string `json:"sendType"` //消息发送方 jx-商家mt-美团elm-饿了么 // Msg string `json:"msg"` //响应msg success/fail
Data interface{} `json:"data"` //美团/饿了么 单聊消 // Data interface{} `json:"data"` //信
} //
// //MessageType string `json:"messageType"` //消息类型 heart-心跳检测send-发送消息receive-接收消息
// GetUserListReq 获取门店用户聊天列表 // //MessageId string `json:"messageId"` //发送/接收信息 id
type GetUserListReq struct { // //UserId string `json:"userId"` //必须是平台方userID
VendorStoreID string `json:"vendorStoreID"` //平台门店id //}
VendorID string `json:"vendorID"` //平台标识id //
AppID string `json:"appID"` //应用ID //type global struct {
} // LocalHost string //本机内网IP
// ServerList map[string]string
type GetChatDetailReq struct { // ServerListLock sync.RWMutex
VendorStoreID string `json:"vendorStoreID"` //平台门店id //}
VendorID string `json:"vendorID"` //平台标识id //type commonConf struct {
AppID string `json:"appID"` //应用ID // HttpPort string
UserID string `json:"userID"` //userID/groupID // RPCPort string
} // Cluster bool
// CryptoKey string
// UserMessageList 用户消息列表 //}
type UserMessageList struct { //
VendorID int `json:"vendorID"` //平台品牌 10-美团 11-饿了么 //// SendData 客户端写入参数
UserID string `json:"userID"` //用户ID //type SendData struct {
NewMessageNum int `json:"NewMessageNum"` //新消息数量 // //ClientId string `json:"clientId" validate:"required"` //链接ID
LatestMsg string `json:"latestMsg"` //最新一条消息 // VendorID int `json:"vendorID"` //消息来源平台ID
LatestTime int `json:"latestTime"` //最新一条消息发送时间 // Data interface{} `json:"data"` //发送给平台 美团/饿了么消息结构体
} // //返回值
// //Code int `json:"code"`
type RelInfo struct { // //Msg string `json:"msg"`
VendorStoreID string `json:"vendorStoreID"` //平台门店id // //SendUserId string `json:"sendUserId"`
VendorID string `json:"vendorID"` //平台标识id //}
AppID string `json:"appID"` //应用ID //
} //// JXMsg 京西消息结构体
//type JXMsg struct {
type UserRelInfo struct { // SendType string `json:"sendType"` //消息发送方 jx-商家mt-美团elm-饿了么
VendorStoreID string `json:"vendorStoreID"` //平台门店id // Data interface{} `json:"data"` //美团/饿了么 单聊消息
VendorID string `json:"vendorID"` //平台标识id //}
AppID string `json:"appID"` //应用ID //
UserID string `json:"userID"` //用户id/groupID //// GetUserListReq 获取门店用户聊天列表
} //type GetUserListReq struct {
// VendorStoreID string `json:"vendorStoreID"` //平台门店id
var ( // VendorID string `json:"vendorID"` //平台标识id
cfg *ini.File // AppID string `json:"appID"` //应用ID
rdb = api.Cacher //}
Manager = NewClientManager() // 管理者 //
CommonSetting = &commonConf{} //type GetChatDetailReq struct {
GlobalSetting = &global{} // VendorStoreID string `json:"vendorStoreID"` //平台门店id
ToClientChan chan clientInfo // VendorID string `json:"vendorID"` //平台标识id
heartbeatInterval = 60 * time.Second // 心跳间隔 // AppID string `json:"appID"` //应用ID
HeartCheckMsg = "~#HHHBBB#~" //心跳检测消息 // UserID string `json:"userID"` //userID/groupID
HeartCheckSuccess = "HB" //成功发送返回心跳消息 //}
VendorIDMT = 10 //im美团 //
VendorIDELM = 11 //im饿了么 //// UserMessageList 用户消息列表
SendTypeJx = "jx" //京西客户端发送方标识 //type UserMessageList struct {
SendTypeMt = "mt" //美团用户发送方标识符 // VendorID int `json:"vendorID"` //平台品牌 10-美团 11-饿了么
SendTypeElm = "elm" //饿了么用户发送方标识符 // UserID string `json:"userID"` //用户ID
MTIMPushUrl = "wss://wpush.meituan.com/websocket" //buildPushConnect建立长连接 // NewMessageNum int `json:"NewMessageNum"` //新消息数量
) // LatestMsg string `json:"latestMsg"` //最新一条消息
// LatestTime int `json:"latestTime"` //最新一条消息发送时间
const ( //}
ExpireTimeDay = 24 * time.Hour //redis一天过期时间 //
maxMessageSize = 8192 // 最大的消息大小 //type RelInfo struct {
) // VendorStoreID string `json:"vendorStoreID"` //平台门店id
// VendorID string `json:"vendorID"` //平台标识id
type renderData struct { // AppID string `json:"appID"` //应用ID
ClientId string `json:"clientId"` //}
} //
//type UserRelInfo struct {
const ( // VendorStoreID string `json:"vendorStoreID"` //平台门店id
SuccessCode = 0 // VendorID string `json:"vendorID"` //平台标识id
SuccessMsg = "success" // AppID string `json:"appID"` //应用ID
Fail = -1 // UserID string `json:"userID"` //用户id/groupID
FailMsg = "fail" //}
//
SYSTEM_ID_ERROR = -1001 //var (
ONLINE_MESSAGE_CODE = 1001 // cfg *ini.File
OFFLINE_MESSAGE_CODE = 1002 // rdb = api.Cacher
) // Manager = NewClientManager() // 管理者
// CommonSetting = &commonConf{}
// Render 统一返回值 // GlobalSetting = &global{}
func Render(conn *websocket.Conn, messageId string, code int, message string, data interface{}) error { // ToClientChan chan clientInfo
return conn.WriteJSON(RetData{ // heartbeatInterval = 60 * time.Second // 心跳间隔
Code: code, // HeartCheckMsg = "~#HHHBBB#~" //心跳检测消息
Msg: message, // HeartCheckSuccess = "HB" //成功发送返回心跳消息
Data: data, // VendorIDMT = 10 //im美团
}) // VendorIDELM = 11 //im饿了么
} // SendTypeJx = "jx" //京西客户端发送方标识
// SendTypeMt = "mt" //美团用户发送方标识符
func ClientRender(w http.ResponseWriter, code int, msg string, data interface{}) (str string) { // SendTypeElm = "elm" //饿了么用户发送方标识符
var retData RetData // MTIMPushUrl = "wss://wpush.meituan.com/websocket" //buildPushConnect建立长连接
//)
retData.Code = code //
retData.Msg = msg //const (
retData.Data = data // ExpireTimeDay = 24 * time.Hour //redis一天过期时间
// maxMessageSize = 8192 // 最大的消息大小
retJson, _ := json.Marshal(retData) //)
str = string(retJson) //
//type renderData struct {
w.Header().Set("Content-Type", "application/json; charset=utf-8") // ClientId string `json:"clientId"`
_, _ = io.WriteString(w, str) //}
return //
} //const (
// SuccessCode = 0
func ConnRender(conn *websocket.Conn, data interface{}) (err error) { // SuccessMsg = "success"
err = conn.WriteJSON(RetData{ // Fail = -1
Code: SuccessCode, // FailMsg = "fail"
Msg: "success", //
Data: data, // SYSTEM_ID_ERROR = -1001
}) // ONLINE_MESSAGE_CODE = 1001
return // OFFLINE_MESSAGE_CODE = 1002
} //)
//
// Default 给默认 //// Render 统一返回
func Default() { //func Render(conn *websocket.Conn, messageId string, code int, message string, data interface{}) error {
CommonSetting = &commonConf{ // return conn.WriteJSON(RetData{
HttpPort: "6000", // Code: code,
RPCPort: "7000", // Msg: message,
Cluster: false, // Data: data,
CryptoKey: "Adba723b7fe06819", // })
} //}
//
GlobalSetting = &global{ //func ClientRender(w http.ResponseWriter, code int, msg string, data interface{}) (str string) {
LocalHost: getIntranetIp(), // var retData RetData
ServerList: make(map[string]string), //
} // retData.Code = code
} // retData.Msg = msg
// retData.Data = data
// Setup 初始化全局设置变量 //
func Setup() { // retJson, _ := json.Marshal(retData)
configFile := flag.String("c", "conf/app.ini", "-c conf/app.ini") // str = string(retJson)
//
var err error // w.Header().Set("Content-Type", "application/json; charset=utf-8")
cfg, err = ini.Load(*configFile) // _, _ = io.WriteString(w, str)
if err != nil { // return
log.Fatalf("setting.Setup, fail to parse 'conf/app.ini': %v", err) //}
} //
//func ConnRender(conn *websocket.Conn, data interface{}) (err error) {
mapTo("common", CommonSetting) // err = conn.WriteJSON(RetData{
// Code: SuccessCode,
GlobalSetting = &global{ // Msg: "success",
LocalHost: getIntranetIp(), // Data: data,
ServerList: make(map[string]string), // })
} // return
fmt.Printf("LocalHost=%s\n ServerList=%s\n", GlobalSetting.LocalHost, utils.Format4Output(GlobalSetting.ServerList, false)) //}
} //
//// Default 给默认值
// mapTo map section //func Default() {
func mapTo(section string, v interface{}) { // CommonSetting = &commonConf{
err := cfg.Section(section).MapTo(v) // HttpPort: "6000",
if err != nil { // RPCPort: "7000",
log.Fatalf("Cfg.MapTo %s err: %v", section, err) // Cluster: false,
} // CryptoKey: "Adba723b7fe06819",
} // }
//
//获取本机IP // GlobalSetting = &global{
func getIntranetIp() string { // LocalHost: getIntranetIp(),
addrs, _ := net.InterfaceAddrs() // ServerList: make(map[string]string),
for _, addr := range addrs { // }
// 检查ip地址判断是否回环地址 //}
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { //
if ipnet.IP.To4() != nil { //// Setup 初始化全局设置变量
return ipnet.IP.String() //func Setup() {
} // configFile := flag.String("c", "conf/app.ini", "-c conf/app.ini")
//
} // var err error
} // cfg, err = ini.Load(*configFile)
return "" // if err != nil {
} // log.Fatalf("setting.Setup, fail to parse 'conf/app.ini': %v", err)
// }
// GenFullUrl 组装完整websocket url以及生成clientID //
func GenFullUrl() (fullUrl string) { // mapTo("common", CommonSetting)
resp, err := api.MtwmAPI.GetConnectionToken() //
if err != nil { // GlobalSetting = &global{
return "" // LocalHost: getIntranetIp(),
} // ServerList: make(map[string]string),
retVal := mtwmapi.GetConnTokenResp{} // }
err = mapstructure.Decode(resp, &retVal) // fmt.Printf("LocalHost=%s\n ServerList=%s\n", GlobalSetting.LocalHost, utils.Format4Output(GlobalSetting.ServerList, false))
fullUrl = MTIMPushUrl + "/" + retVal.AppKey + "/" + retVal.ConnectionToken //}
//clientID = api.MtwmAPI.GetAppID() + ":" + retVal.ConnectionToken //
//打印输出 //// mapTo map section
//fmt.Printf("Create websocket connect failCount:%d", retVal.UserCount) //func mapTo(section string, v interface{}) {
return fullUrl // err := cfg.Section(section).MapTo(v)
} // if err != nil {
// log.Fatalf("Cfg.MapTo %s err: %v", section, err)
// }
//}
//
////获取本机IP
//func getIntranetIp() string {
// addrs, _ := net.InterfaceAddrs()
// for _, addr := range addrs {
// // 检查ip地址判断是否回环地址
// if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
// if ipnet.IP.To4() != nil {
// return ipnet.IP.String()
// }
//
// }
// }
// return ""
//}
//
//// GenFullUrl 组装完整websocket url以及生成clientID
//func GenFullUrl() (fullUrl string) {
// resp, err := api.MtwmAPI.GetConnectionToken()
// if err != nil {
// return ""
// }
// retVal := mtwmapi.GetConnTokenResp{}
// err = mapstructure.Decode(resp, &retVal)
// fullUrl = MTIMPushUrl + "/" + retVal.AppKey + "/" + retVal.ConnectionToken
// //clientID = api.MtwmAPI.GetAppID() + ":" + retVal.ConnectionToken
// //打印输出
// //fmt.Printf("Create websocket connect failCount:%d", retVal.UserCount)
// return fullUrl
//}

View File

@@ -1,263 +1,264 @@
package im package im
import ( //
"errors" //import (
"fmt" // "errors"
"net/http" // "fmt"
"time" // "net/http"
// "time"
"git.rosy.net.cn/baseapi/utils" //
// "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals" //
"github.com/gorilla/websocket" // "git.rosy.net.cn/jx-callback/globals"
) // "github.com/gorilla/websocket"
//)
func Init() { //
//初始化 //func Init() {
ToClientChan = make(chan clientInfo, 1000) // //初始化
//写入全局变量 // ToClientChan = make(chan clientInfo, 1000)
//Default() // //写入全局变量
// //Default()
Setup() //
//建立长链接 // Setup()
//StartWebSocket(res, req) // //建立长链接
Send([]byte(HeartCheckMsg)) // //StartWebSocket(res, req)
// Send([]byte(HeartCheckMsg))
//启动定时器 //
PingTimer() // //启动定时器
// PingTimer()
go WriteMessage() //
// go WriteMessage()
go Manager.Start() //
// go Manager.Start()
fmt.Printf("服务器启动成功,端口号:%s\n", CommonSetting.HttpPort) //
} // fmt.Printf("服务器启动成功,端口号:%s\n", CommonSetting.HttpPort)
//}
func Run(w http.ResponseWriter, r *http.Request) { //
conn, err := (&websocket.Upgrader{ //func Run(w http.ResponseWriter, r *http.Request) {
ReadBufferSize: 1024, // conn, err := (&websocket.Upgrader{
WriteBufferSize: 1024, // ReadBufferSize: 1024,
// 允许所有CORS跨域请求 // WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { // // 允许所有CORS跨域请求
return true // CheckOrigin: func(r *http.Request) bool {
}, // return true
}).Upgrade(w, r, nil) // },
if err != nil { // }).Upgrade(w, r, nil)
globals.SugarLogger.Debugf("upgrade error: %v", err) // if err != nil {
http.NotFound(w, r) // globals.SugarLogger.Debugf("upgrade error: %v", err)
return // http.NotFound(w, r)
} // return
// }
//设置读取消息大小上线 //
conn.SetReadLimit(maxMessageSize) // //设置读取消息大小上线
// conn.SetReadLimit(maxMessageSize)
clientID := r.FormValue("clientId") //
clientSocket := NewClient(clientID, conn) // clientID := r.FormValue("clientId")
// clientSocket := NewClient(clientID, conn)
//读取客户端消息 //
clientSocket.Read() // //读取客户端消息
// clientSocket.Read()
if err = ConnRender(conn, renderData{ClientId: clientID}); err != nil { //
_ = conn.Close() // if err = ConnRender(conn, renderData{ClientId: clientID}); err != nil {
return // _ = conn.Close()
} // return
// }
// 用户连接事件 //
Manager.Connect <- clientSocket // // 用户连接事件
} // Manager.Connect <- clientSocket
//}
func StartWebSocket(conn *websocket.Conn, clientID string, err error) { //
//func StartWebSocket(conn *websocket.Conn, clientID string, err error) {
//设置读取消息大小上线 //
conn.SetReadLimit(maxMessageSize) // //设置读取消息大小上线
// conn.SetReadLimit(maxMessageSize)
clientSocket := NewClient(clientID, conn) //
// clientSocket := NewClient(clientID, conn)
//读取客户端消息 //
clientSocket.Read() // //读取客户端消息
// clientSocket.Read()
if err = ConnRender(conn, renderData{ClientId: clientID}); err != nil { //
_ = conn.Close() // if err = ConnRender(conn, renderData{ClientId: clientID}); err != nil {
return // _ = conn.Close()
} // return
// }
// 用户连接事件 //
Manager.Connect <- clientSocket // // 用户连接事件
// Manager.Connect <- clientSocket
} //
//}
// PingTimer 定时器发送心跳 //
func PingTimer() { //// PingTimer 定时器发送心跳
go func() { //func PingTimer() {
ticker := time.NewTicker(heartbeatInterval) // go func() {
defer ticker.Stop() // ticker := time.NewTicker(heartbeatInterval)
//测试用 // defer ticker.Stop()
i := 0 // //测试用
for { // i := 0
i++ // for {
<-ticker.C // i++
for clientId, conn := range Manager.AllClient() { // <-ticker.C
if err := conn.Socket.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second)); err != nil { // for clientId, conn := range Manager.AllClient() {
Manager.DisConnect <- conn // if err := conn.Socket.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second)); err != nil {
globals.SugarLogger.Debugf("发送心跳失败: %s 总连接数:%d", clientId, Manager.Count()) // Manager.DisConnect <- conn
} // globals.SugarLogger.Debugf("发送心跳失败: %s 总连接数:%d", clientId, Manager.Count())
if err := ConnRender(conn.Socket, renderData{ClientId: clientId}); err != nil { // }
return // if err := ConnRender(conn.Socket, renderData{ClientId: clientId}); err != nil {
} // return
globals.SugarLogger.Debugf("clientId=%s,i=%d", clientId, i) // }
} // globals.SugarLogger.Debugf("clientId=%s,i=%d", clientId, i)
} // }
}() // }
} // }()
//}
// WriteMessage 监听并发送给客户端信息 //
func WriteMessage() { //// WriteMessage 监听并发送给客户端信息
i := 0 //func WriteMessage() {
for { // i := 0
clientInfo := <-ToClientChan // for {
//广播发送通知所有客户端 // clientInfo := <-ToClientChan
i++ // //广播发送通知所有客户端
fmt.Printf("WriteMessage clientInfo=%s i=%d", utils.Format4Output(clientInfo, false), i) // i++
if Manager.AllClient() != nil { // fmt.Printf("WriteMessage clientInfo=%s i=%d", utils.Format4Output(clientInfo, false), i)
for _, conn := range Manager.AllClient() { // if Manager.AllClient() != nil {
if err := Render(conn.Socket, clientInfo.MessageId, clientInfo.Code, clientInfo.Msg, clientInfo.Data); err != nil { // for _, conn := range Manager.AllClient() {
Manager.DisConnect <- conn
}
}
} else {
globals.SugarLogger.Debugf("无客户端连接,请检查")
return
}
//if conn, err := Manager.GetByClientId(clientInfo.ClientId); err == nil && conn != nil {
// if err := Render(conn.Socket, clientInfo.MessageId, clientInfo.Code, clientInfo.Msg, clientInfo.Data); err != nil { // if err := Render(conn.Socket, clientInfo.MessageId, clientInfo.Code, clientInfo.Msg, clientInfo.Data); err != nil {
// Manager.DisConnect <- conn // Manager.DisConnect <- conn
// } // }
// } // }
} // } else {
} // globals.SugarLogger.Debugf("无客户端连接,请检查")
// return
// Start 管道处理程序 // }
func (manager *ClientManager) Start() { // //if conn, err := Manager.GetByClientId(clientInfo.ClientId); err == nil && conn != nil {
for { // // if err := Render(conn.Socket, clientInfo.MessageId, clientInfo.Code, clientInfo.Msg, clientInfo.Data); err != nil {
select { // // Manager.DisConnect <- conn
case client := <-manager.Connect: // // }
// 建立连接事件 // //}
manager.EventConnect(client) // }
case conn := <-manager.DisConnect: //}
// 断开连接事件 //
manager.EventDisconnect(conn) //// Start 管道处理程序
} //func (manager *ClientManager) Start() {
} // for {
} // select {
// case client := <-manager.Connect:
//从客户端读取数据 // // 建立连接事件
func (c *Client) Read() { // manager.EventConnect(client)
go func() { // case conn := <-manager.DisConnect:
for { // // 断开连接事件
messageType, msg, err := c.Socket.ReadMessage() // manager.EventDisconnect(conn)
if err != nil { // }
if messageType == -1 && websocket.IsCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) { // }
Manager.DisConnect <- c //}
return //
} else if messageType != websocket.PingMessage { ////从客户端读取数据
return //func (c *Client) Read() {
} // go func() {
} else { // for {
SendToVendor(msg) // messageType, msg, err := c.Socket.ReadMessage()
} // if err != nil {
} // if messageType == -1 && websocket.IsCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
}() // Manager.DisConnect <- c
} // return
// } else if messageType != websocket.PingMessage {
// 以下为连接事件操作******************************************* // return
// }
// EventConnect 建立连接事件 // } else {
func (manager *ClientManager) EventConnect(client *Client) { // SendToVendor(msg)
manager.AddClient(client) // }
} // }
// }()
// EventDisconnect 断开连接事件 //}
func (manager *ClientManager) EventDisconnect(client *Client) { //
//关闭连接 //// 以下为连接事件操作*******************************************
_ = client.Socket.Close() //
manager.DelClient(client) //// EventConnect 建立连接事件
//标记销毁 //func (manager *ClientManager) EventConnect(client *Client) {
client.IsDeleted = true // manager.AddClient(client)
client = nil //}
} //
//// EventDisconnect 断开连接事件
//以下为客户端Client操作******************************************* //func (manager *ClientManager) EventDisconnect(client *Client) {
// //关闭连接
// NewClient 初始化Client // _ = client.Socket.Close()
func NewClient(clientId string, socket *websocket.Conn) *Client { // manager.DelClient(client)
return &Client{ // //标记销毁
ClientId: clientId, // client.IsDeleted = true
Socket: socket, // client = nil
ConnectTime: uint64(time.Now().Unix()), //}
IsDeleted: false, //
} ////以下为客户端Client操作*******************************************
} //
//// NewClient 初始化Client
// AddClient 添加客户端 //func NewClient(clientId string, socket *websocket.Conn) *Client {
func (manager *ClientManager) AddClient(client *Client) { // return &Client{
manager.ClientIdMapLock.Lock() // ClientId: clientId,
defer manager.ClientIdMapLock.Unlock() // Socket: socket,
// ConnectTime: uint64(time.Now().Unix()),
manager.ClientIdMap[client.ClientId] = client // IsDeleted: false,
} // }
//}
// DelClient 删除客户端 //
func (manager *ClientManager) DelClient(client *Client) { //// AddClient 添加客户端
manager.delClientIdMap(client.ClientId) //func (manager *ClientManager) AddClient(client *Client) {
// manager.ClientIdMapLock.Lock()
} // defer manager.ClientIdMapLock.Unlock()
//
// 删除clientIdMap // manager.ClientIdMap[client.ClientId] = client
func (manager *ClientManager) delClientIdMap(clientId string) { //}
manager.ClientIdMapLock.Lock() //
defer manager.ClientIdMapLock.Unlock() //// DelClient 删除客户端
//func (manager *ClientManager) DelClient(client *Client) {
delete(manager.ClientIdMap, clientId) // manager.delClientIdMap(client.ClientId)
} //
//}
// GetByClientId 通过clientId获取client //
func (manager *ClientManager) GetByClientId(clientId string) (*Client, error) { //// 删除clientIdMap
manager.ClientIdMapLock.RLock() //func (manager *ClientManager) delClientIdMap(clientId string) {
defer manager.ClientIdMapLock.RUnlock() // manager.ClientIdMapLock.Lock()
// defer manager.ClientIdMapLock.Unlock()
if client, ok := manager.ClientIdMap[clientId]; !ok { //
return nil, errors.New("客户端不存在") // delete(manager.ClientIdMap, clientId)
} else { //}
return client, nil //
} //// GetByClientId 通过clientId获取client
} //func (manager *ClientManager) GetByClientId(clientId string) (*Client, error) {
// manager.ClientIdMapLock.RLock()
// AllClient 获取所有的客户端 // defer manager.ClientIdMapLock.RUnlock()
func (manager *ClientManager) AllClient() map[string]*Client { //
manager.ClientIdMapLock.RLock() // if client, ok := manager.ClientIdMap[clientId]; !ok {
defer manager.ClientIdMapLock.RUnlock() // return nil, errors.New("客户端不存在")
// } else {
return manager.ClientIdMap // return client, nil
} // }
//}
//与客户端的交互操作************************* //
//// AllClient 获取所有的客户端
// NewClientManager 初始化客户端管理 //func (manager *ClientManager) AllClient() map[string]*Client {
func NewClientManager() (clientManager *ClientManager) { // manager.ClientIdMapLock.RLock()
clientManager = &ClientManager{ // defer manager.ClientIdMapLock.RUnlock()
ClientIdMap: make(map[string]*Client), //
Connect: make(chan *Client, 10000), // return manager.ClientIdMap
DisConnect: make(chan *Client, 10000), //}
Groups: make(map[string][]string, 100), //
SystemClients: make(map[string][]string, 100), ////与客户端的交互操作*************************
} //
//// NewClientManager 初始化客户端管理
return //func NewClientManager() (clientManager *ClientManager) {
} // clientManager = &ClientManager{
// ClientIdMap: make(map[string]*Client),
// Count 获取客户端数量 // Connect: make(chan *Client, 10000),
func (manager *ClientManager) Count() int { // DisConnect: make(chan *Client, 10000),
manager.ClientIdMapLock.RLock() // Groups: make(map[string][]string, 100),
defer manager.ClientIdMapLock.RUnlock() // SystemClients: make(map[string][]string, 100),
return len(manager.ClientIdMap) // }
} //
// return
//}
//
//// Count 获取客户端数量
//func (manager *ClientManager) Count() int {
// manager.ClientIdMapLock.RLock()
// defer manager.ClientIdMapLock.RUnlock()
// return len(manager.ClientIdMap)
//}

View File

@@ -1,105 +1,106 @@
package controllers package controllers
import ( //
"encoding/json" //import (
"net/http" // "encoding/json"
// "net/http"
"git.rosy.net.cn/jx-callback/globals" //
// "git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/business/partner/purchase/im" //
"github.com/astaxie/beego/server/web" // "git.rosy.net.cn/jx-callback/business/partner/purchase/im"
) // "github.com/astaxie/beego/server/web"
//)
type IMController struct { //
web.Controller //type IMController struct {
} // web.Controller
// @Title IM初始化长链接
// @Description IM初始化长链接
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /StartWebSocket [get]
func (c *IMController) StartWebSocket() {
upgrader.CheckOrigin = func(r *http.Request) bool {
return true
}
ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
if err != nil {
globals.SugarLogger.Errorf("upgrade error: %v", err)
return
}
defer ws.Close()
clientID := c.GetString("clientID")
globals.SugarLogger.Debugf("clientID=%s", clientID)
im.StartWebSocket(ws, clientID, err)
}
// @Title IM获取门店用户聊天列表
// @Description IM获取门店用户聊天列表
// @Param token header string true "认证token"
// @Param payLoad formData string true "平台应用映射关系"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetIMUserList [get]
func (c *IMController) GetIMUserList() {
c.callGetIMUserList(func(params *tImGetIMUserListParams) (retVal interface{}, errCode string, err error) {
var relInfo []im.RelInfo
if err = json.Unmarshal([]byte(params.PayLoad), &relInfo); err != nil {
retVal, err = im.GetImUserList(relInfo)
}
return retVal, "", err
})
}
// @Title IM获取单个用户聊天详情
// @Description IM获取单个用户聊天详情
// @Param token header string true "认证token"
// @Param payLoad formData string true "平台用户应用映射关系"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetImChatDetail [get]
func (c *IMController) GetImChatDetail() {
c.callGetImChatDetail(func(params *tImGetImChatDetailParams) (retVal interface{}, errCode string, err error) {
var temp []im.UserRelInfo
if err = json.Unmarshal([]byte(params.PayLoad), &temp); err == nil {
retVal, err = im.GetImChatDetail(temp)
}
return retVal, "", err
})
}
// @Title IM设置门店与单个用户已读
// @Description IM设置门店与单个用户已读
// @Param token header string true "认证token"
// @Param appID formData string true "应用id"
// @Param vendorStoreID formData string true "平台门店id"
// @Param vendorID formData string true "平台id"
// @Param userID formData string true "用户id/会话id"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SetImMsgRead [post]
func (c *IMController) SetImMsgRead() {
c.callSetImMsgRead(func(params *tImSetImMsgReadParams) (retVal interface{}, errCode string, err error) {
err = im.SetJxMsgRead(params.AppID, params.VendorStoreID, params.VendorID, params.UserID)
return nil, "", err
})
}
// @Title 向平台商发送信息
// @Description 向平台商发送信息
// @Param token header string true "认证token"
// @Param sendData formData string true "平台商消息结构体"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SendToVendor [post]
//func (c *IMController) SendToVendor() {
// c.callSendToVendor(func(params *tImSendToVendorParams) (retVal interface{}, errCode string, err error) {
// var sendData im.SendData
// if err = json.Unmarshal([]byte(params.SendData), &sendData); err == nil {
// im.SendToVendor(sendData)
//} //}
//
//// @Title IM初始化长链接
//// @Description IM初始化长链接
//// @Success 200 {object} controllers.CallResult
//// @Failure 200 {object} controllers.CallResult
//// @router /StartWebSocket [get]
//func (c *IMController) StartWebSocket() {
// upgrader.CheckOrigin = func(r *http.Request) bool {
// return true
// }
// ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
// if err != nil {
// globals.SugarLogger.Errorf("upgrade error: %v", err)
// return
// }
// defer ws.Close()
//
// clientID := c.GetString("clientID")
// globals.SugarLogger.Debugf("clientID=%s", clientID)
//
// im.StartWebSocket(ws, clientID, err)
//}
//
//// @Title IM获取门店用户聊天列表
//// @Description IM获取门店用户聊天列表
//// @Param token header string true "认证token"
//// @Param payLoad formData string true "平台应用映射关系"
//// @Success 200 {object} controllers.CallResult
//// @Failure 200 {object} controllers.CallResult
//// @router /GetIMUserList [get]
//func (c *IMController) GetIMUserList() {
// c.callGetIMUserList(func(params *tImGetIMUserListParams) (retVal interface{}, errCode string, err error) {
// var relInfo []im.RelInfo
// if err = json.Unmarshal([]byte(params.PayLoad), &relInfo); err != nil {
// retVal, err = im.GetImUserList(relInfo)
// }
// return retVal, "", err
// })
//}
//
//// @Title IM获取单个用户聊天详情
//// @Description IM获取单个用户聊天详情
//// @Param token header string true "认证token"
//// @Param payLoad formData string true "平台用户应用映射关系"
//// @Success 200 {object} controllers.CallResult
//// @Failure 200 {object} controllers.CallResult
//// @router /GetImChatDetail [get]
//func (c *IMController) GetImChatDetail() {
// c.callGetImChatDetail(func(params *tImGetImChatDetailParams) (retVal interface{}, errCode string, err error) {
// var temp []im.UserRelInfo
// if err = json.Unmarshal([]byte(params.PayLoad), &temp); err == nil {
// retVal, err = im.GetImChatDetail(temp)
// }
// return retVal, "", err
// })
//}
//
//// @Title IM设置门店与单个用户已读
//// @Description IM设置门店与单个用户已读
//// @Param token header string true "认证token"
//// @Param appID formData string true "应用id"
//// @Param vendorStoreID formData string true "平台门店id"
//// @Param vendorID formData string true "平台id"
//// @Param userID formData string true "用户id/会话id"
//// @Success 200 {object} controllers.CallResult
//// @Failure 200 {object} controllers.CallResult
//// @router /SetImMsgRead [post]
//func (c *IMController) SetImMsgRead() {
// c.callSetImMsgRead(func(params *tImSetImMsgReadParams) (retVal interface{}, errCode string, err error) {
// err = im.SetJxMsgRead(params.AppID, params.VendorStoreID, params.VendorID, params.UserID)
// return nil, "", err // return nil, "", err
// }) // })
//} //}
//
//// @Title 向平台商发送信息
//// @Description 向平台商发送信息
//// @Param token header string true "认证token"
//// @Param sendData formData string true "平台商消息结构体"
//// @Success 200 {object} controllers.CallResult
//// @Failure 200 {object} controllers.CallResult
//// @router /SendToVendor [post]
////func (c *IMController) SendToVendor() {
//// c.callSendToVendor(func(params *tImSendToVendorParams) (retVal interface{}, errCode string, err error) {
//// var sendData im.SendData
//// if err = json.Unmarshal([]byte(params.SendData), &sendData); err == nil {
//// im.SendToVendor(sendData)
//// }
//// return nil, "", err
//// })
////}

View File

@@ -4332,30 +4332,30 @@ func init() {
Filters: nil, Filters: nil,
Params: nil}) Params: nil})
//im //im
web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"], //web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"],
web.ControllerComments{ // web.ControllerComments{
Method: "GetIMUserList", // Method: "GetIMUserList",
Router: `/GetIMUserList`, // Router: `/GetIMUserList`,
AllowHTTPMethods: []string{"get"}, // AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(), // MethodParams: param.Make(),
Filters: nil, // Filters: nil,
Params: nil}) // Params: nil})
web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"], //web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"],
web.ControllerComments{ // web.ControllerComments{
Method: "GetImChatDetail", // Method: "GetImChatDetail",
Router: `/GetImChatDetail`, // Router: `/GetImChatDetail`,
AllowHTTPMethods: []string{"get"}, // AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(), // MethodParams: param.Make(),
Filters: nil, // Filters: nil,
Params: nil}) // Params: nil})
web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"], //web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"],
web.ControllerComments{ // web.ControllerComments{
Method: "SetImMsgRead", // Method: "SetImMsgRead",
Router: `/SetImMsgRead`, // Router: `/SetImMsgRead`,
AllowHTTPMethods: []string{"post"}, // AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(), // MethodParams: param.Make(),
Filters: nil, // Filters: nil,
Params: nil}) // Params: nil})
web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"], web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"] = append(web.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:IMController"],
web.ControllerComments{ web.ControllerComments{
Method: "StartWebSocket", Method: "StartWebSocket",

View File

@@ -165,11 +165,11 @@ func init() {
&controllers.VersionController{}, &controllers.VersionController{},
), ),
), ),
web.NSNamespace("/im", //web.NSNamespace("/im",
web.NSInclude( // web.NSInclude(
&controllers.IMController{}, // &controllers.IMController{},
), // ),
), //),
) )
web.AddNamespace(ns) web.AddNamespace(ns)