265 lines
6.5 KiB
Go
265 lines
6.5 KiB
Go
|
package ws
|
|||
|
|
|||
|
import (
|
|||
|
"encoding/json"
|
|||
|
"fmt"
|
|||
|
"github.com/gin-gonic/gin"
|
|||
|
"github.com/gorilla/websocket"
|
|||
|
"kefu/models"
|
|||
|
"kefu/types"
|
|||
|
"log"
|
|||
|
"net/http"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
type User struct {
|
|||
|
Conn *websocket.Conn
|
|||
|
Name string
|
|||
|
Id string
|
|||
|
Avator string
|
|||
|
To_id string
|
|||
|
Ent_id string
|
|||
|
Role_id string
|
|||
|
Mux sync.Mutex
|
|||
|
UpdateTime time.Time
|
|||
|
}
|
|||
|
type UserConnection struct {
|
|||
|
Mux sync.Mutex
|
|||
|
Users []*User
|
|||
|
}
|
|||
|
|
|||
|
// 客服链接全局变量
|
|||
|
var KefuList = make(map[string]*UserConnection)
|
|||
|
|
|||
|
// 客服
|
|||
|
func NewKefuServer(c *gin.Context) {
|
|||
|
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
|||
|
if err != nil {
|
|||
|
http.NotFound(c.Writer, c.Request)
|
|||
|
log.Print("upgrade:", err)
|
|||
|
return
|
|||
|
}
|
|||
|
kefuId, _ := c.Get("kefu_id")
|
|||
|
kefuName, _ := c.Get("kefu_name")
|
|||
|
kefuInfo := models.FindUserById(kefuId)
|
|||
|
if kefuInfo.ID == 0 {
|
|||
|
errStr := "客服用户不存在:" + kefuName.(string)
|
|||
|
log.Println(errStr)
|
|||
|
conn.WriteMessage(websocket.TextMessage, []byte(errStr))
|
|||
|
conn.Close()
|
|||
|
return
|
|||
|
}
|
|||
|
var kefu User
|
|||
|
kefu.Id = kefuInfo.Name
|
|||
|
kefu.Name = kefuInfo.Nickname
|
|||
|
kefu.Avator = kefuInfo.Avator
|
|||
|
kefu.Role_id = kefuInfo.RoleId
|
|||
|
if kefuInfo.RoleId <= "2" {
|
|||
|
kefu.Ent_id = fmt.Sprintf("%d", kefuInfo.ID)
|
|||
|
} else {
|
|||
|
kefu.Ent_id = fmt.Sprintf("%d", kefuInfo.Pid)
|
|||
|
}
|
|||
|
kefu.Conn = conn
|
|||
|
AddKefuToList(&kefu)
|
|||
|
//更新客服正在接待数量
|
|||
|
go models.UpdateUserRecNumZero(kefuInfo.Name, VisitorCount(kefuInfo.Name))
|
|||
|
for {
|
|||
|
//接受消息
|
|||
|
//var receive []byte
|
|||
|
_, _, err := conn.ReadMessage()
|
|||
|
//每次读到消息,循环一圈我的conn
|
|||
|
kefuConnection, ok := KefuList[kefuInfo.Name]
|
|||
|
if !ok || len(kefuConnection.Users) == 0 {
|
|||
|
conn.Close()
|
|||
|
return
|
|||
|
}
|
|||
|
//kefuConnection.Users = removeUsersConn(kefuConnection.Users, conn)
|
|||
|
var newKefuConns []*User
|
|||
|
flag := false
|
|||
|
for _, kefuConn := range kefuConnection.Users {
|
|||
|
if kefuConn.Conn != conn {
|
|||
|
newKefuConns = append(newKefuConns, kefuConn)
|
|||
|
} else {
|
|||
|
//找到我了
|
|||
|
flag = true
|
|||
|
}
|
|||
|
}
|
|||
|
//如果链接关闭了,把其他conn加进去就可以了
|
|||
|
if err != nil {
|
|||
|
log.Println("客服ws链接失败:ws/user.go,客服离开 ", kefuInfo.Name, err)
|
|||
|
conn.Close()
|
|||
|
kefuConnection.Users = newKefuConns
|
|||
|
kefuConnection.Mux.Lock()
|
|||
|
KefuList[kefuInfo.Name] = kefuConnection
|
|||
|
kefuConnection.Mux.Unlock()
|
|||
|
return
|
|||
|
}
|
|||
|
////链接没关闭,但是循环一圈没我这个链接
|
|||
|
if !flag {
|
|||
|
conn.Close()
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
func AddKefuToList(kefu *User) {
|
|||
|
var newKefuConns = []*User{kefu}
|
|||
|
kefuConnection, ok := KefuList[kefu.Id]
|
|||
|
if !ok {
|
|||
|
kefuConnection = &UserConnection{
|
|||
|
Users: newKefuConns,
|
|||
|
}
|
|||
|
KefuList[kefu.Id] = kefuConnection
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
unreadNum := models.CountMessage("kefu_id = ? and mes_type='visitor' and status = 'unread'", kefu.Id)
|
|||
|
msg := TypeMessage{
|
|||
|
Type: "unread_num",
|
|||
|
Data: unreadNum,
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
err := kefu.Conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
if err != nil {
|
|||
|
kefu.Conn.Close()
|
|||
|
log.Println("客服ws链接失败:", kefu.Id, err)
|
|||
|
}
|
|||
|
if len(kefuConnection.Users) != 0 {
|
|||
|
for _, otherKefu := range kefuConnection.Users {
|
|||
|
err := otherKefu.Conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
if err == nil {
|
|||
|
newKefuConns = append(newKefuConns, otherKefu)
|
|||
|
} else {
|
|||
|
otherKefu.Conn.Close()
|
|||
|
log.Println("客服ws链接失败:", kefu.Id, err)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
kefuConnection.Users = newKefuConns
|
|||
|
log.Println("客服ws链接成功:客服来了 ", kefu.Id, kefu.Name)
|
|||
|
kefuConnection.Mux.Lock()
|
|||
|
KefuList[kefu.Id] = kefuConnection
|
|||
|
kefuConnection.Mux.Unlock()
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 给超管发消息
|
|||
|
func SuperAdminMessage(str []byte) {
|
|||
|
return
|
|||
|
//给超管发
|
|||
|
}
|
|||
|
|
|||
|
// 访客给客服发消息
|
|||
|
func VisitorSendToKefu(kefuName string, visitorInfo models.Visitor, content string) {
|
|||
|
msgId := models.CreateMessage(kefuName, visitorInfo.VisitorId, content, "visitor", visitorInfo.EntId, "read")
|
|||
|
msg := TypeMessage{
|
|||
|
Type: "message",
|
|||
|
Data: ClientMessage{
|
|||
|
MsgId: msgId,
|
|||
|
Avator: visitorInfo.Avator,
|
|||
|
Id: visitorInfo.VisitorId,
|
|||
|
VisitorId: visitorInfo.VisitorId,
|
|||
|
Name: visitorInfo.Name,
|
|||
|
ToId: kefuName,
|
|||
|
Content: content,
|
|||
|
Time: time.Now().Format("2006-01-02 15:04:05"),
|
|||
|
IsKefu: "no",
|
|||
|
},
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
OneKefuMessage(kefuName, str)
|
|||
|
}
|
|||
|
|
|||
|
// 给指定客服发消息
|
|||
|
func OneKefuMessage(toId string, str []byte) {
|
|||
|
//新版
|
|||
|
kefuConnection, ok := KefuList[toId]
|
|||
|
if ok && len(kefuConnection.Users) > 0 {
|
|||
|
for _, kefu := range kefuConnection.Users {
|
|||
|
kefu.Mux.Lock()
|
|||
|
error := kefu.Conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
kefu.Mux.Unlock()
|
|||
|
if error != nil {
|
|||
|
log.Println("send_kefu_message", error, string(str))
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
SuperAdminMessage(str)
|
|||
|
}
|
|||
|
func KefuMessage(visitorId, content string, kefuInfo models.User) {
|
|||
|
msg := TypeMessage{
|
|||
|
Type: "message",
|
|||
|
Data: ClientMessage{
|
|||
|
Name: kefuInfo.Nickname,
|
|||
|
Avator: kefuInfo.Avator,
|
|||
|
Id: visitorId,
|
|||
|
Time: time.Now().Format("2006-01-02 15:04:05"),
|
|||
|
ToId: visitorId,
|
|||
|
Content: content,
|
|||
|
IsKefu: "yes",
|
|||
|
},
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
OneKefuMessage(kefuInfo.Name, str)
|
|||
|
}
|
|||
|
|
|||
|
// 给客服客户端发送消息判断客户端是否在线
|
|||
|
func SendPingToKefuClient() {
|
|||
|
for kefuId, kefuConnection := range KefuList {
|
|||
|
var newKefuConns []*User
|
|||
|
//lastDay := tools.GetPastDate(10)
|
|||
|
//unreadNum := models.CountMessage("kefu_id = ? and created_at > ? and mes_type='visitor' and status = 'unread'", kefuId, lastDay)
|
|||
|
var (
|
|||
|
entId string
|
|||
|
)
|
|||
|
for _, kefuConn := range kefuConnection.Users {
|
|||
|
entId = kefuConn.Ent_id
|
|||
|
if kefuConn == nil {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
msg := TypeMessage{
|
|||
|
Type: "ping",
|
|||
|
//Data: unreadNum,
|
|||
|
}
|
|||
|
str, _ := json.Marshal(msg)
|
|||
|
kefuConn.Mux.Lock()
|
|||
|
err := kefuConn.Conn.WriteMessage(websocket.TextMessage, str)
|
|||
|
kefuConn.Mux.Unlock()
|
|||
|
if err == nil {
|
|||
|
newKefuConns = append(newKefuConns, kefuConn)
|
|||
|
} else {
|
|||
|
log.Println("客服ws链接失败:", err)
|
|||
|
}
|
|||
|
}
|
|||
|
kefuConnection.Users = newKefuConns
|
|||
|
if len(newKefuConns) > 0 {
|
|||
|
kefuConnection.Mux.Lock()
|
|||
|
KefuList[kefuId] = kefuConnection
|
|||
|
kefuConnection.Mux.Unlock()
|
|||
|
} else {
|
|||
|
online := &models.UpDownLine{
|
|||
|
EntId: entId,
|
|||
|
KefuName: kefuId,
|
|||
|
OnlineStatus: 2,
|
|||
|
ClientIp: "system clean",
|
|||
|
CreatedAt: types.Time{},
|
|||
|
}
|
|||
|
online.AddUpDownLine()
|
|||
|
go models.UpdateUserRecNumZero(kefuId, 0)
|
|||
|
delete(KefuList, kefuId)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 删除切片数据
|
|||
|
func removeUsersConn(s []*User, conn *websocket.Conn) []*User {
|
|||
|
for i := 0; i < len(s); i++ {
|
|||
|
if s[i].Conn == conn {
|
|||
|
s = append(s[:i], s[i+1:]...)
|
|||
|
i--
|
|||
|
}
|
|||
|
}
|
|||
|
return s
|
|||
|
}
|