| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- package controller
- import (
- "encoding/json"
- "git.wanbits.cc/sin/flytalk/models"
- "git.wanbits.cc/sin/flytalk/ws"
- "github.com/gin-gonic/gin"
- "github.com/gorilla/websocket"
- "log"
- "net/http"
- "sort"
- "time"
- )
- type vistor struct {
- conn *websocket.Conn
- name string
- id string
- avator string
- to_id string
- }
- type Message struct {
- conn *websocket.Conn
- c *gin.Context
- content []byte
- messageType int
- }
- var clientList = make(map[string]*vistor)
- var kefuList = make(map[string][]*websocket.Conn)
- var message = make(chan *Message)
- type TypeMessage struct {
- Type interface{} `json:"type"`
- Data interface{} `json:"data"`
- }
- type ClientMessage struct {
- Name string `json:"name"`
- Avator string `json:"avator"`
- Id string `json:"id"`
- VisitorId string `json:"visitor_id"`
- Group string `json:"group"`
- Time string `json:"time"`
- ToId string `json:"to_id"`
- Content string `json:"content"`
- City string `json:"city"`
- ClientIp string `json:"client_ip"`
- Refer string `json:"refer"`
- }
- //定时检测客户端是否在线
- func init() {
- upgrader = websocket.Upgrader{
- ReadBufferSize: 1024,
- WriteBufferSize: 1024,
- CheckOrigin: func(r *http.Request) bool {
- return true
- },
- }
- go UpdateVisitorStatusCron()
- go singleBroadcaster()
- //go sendPingOnlineUsers()
- //sendPingToClient()
- }
- func NewChatServer(c *gin.Context) {
- conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
- if err != nil {
- log.Print("upgrade:", err)
- return
- }
- for {
- //接受消息
- var receive []byte
- var recevString string
- messageType, receive, err := conn.ReadMessage()
- if err != nil {
- for uid, visitor := range clientList {
- if visitor.conn == conn {
- log.Println("删除用户", uid)
- delete(clientList, uid)
- models.UpdateVisitorStatus(uid, 0)
- userInfo := make(map[string]string)
- userInfo["uid"] = uid
- userInfo["name"] = visitor.name
- msg := TypeMessage{
- Type: "userOffline",
- Data: userInfo,
- }
- str, _ := json.Marshal(msg)
- kefuConns := kefuList[visitor.to_id]
- if kefuConns != nil {
- for _, kefuConn := range kefuConns {
- kefuConn.WriteMessage(websocket.TextMessage, str)
- }
- }
- //新版
- mKefuConns := ws.KefuList[visitor.to_id]
- if mKefuConns != nil {
- for _, kefu := range mKefuConns {
- kefu.Conn.WriteMessage(websocket.TextMessage, str)
- }
- }
- sendPingOnlineUsers()
- }
- }
- log.Println(err)
- return
- }
- recevString = string(receive)
- log.Println("客户端:", recevString)
- message <- &Message{
- conn: conn,
- content: receive,
- c: c,
- messageType: messageType,
- }
- }
- }
- //发送给客户客服上线
- func SendKefuOnline(clientMsg ClientMessage, conn *websocket.Conn) {
- sendMsg := TypeMessage{
- Type: "kfOnline",
- Data: ClientMessage{
- Name: clientMsg.Name,
- Avator: clientMsg.Avator,
- Id: clientMsg.Id,
- Group: clientMsg.Group,
- Time: time.Now().Format("2006-01-02 15:04:05"),
- Content: "客服上线",
- },
- }
- jsonStrByte, _ := json.Marshal(sendMsg)
- conn.WriteMessage(websocket.TextMessage, jsonStrByte)
- }
- //发送通知
- func SendNotice(msg string, conn *websocket.Conn) {
- sendMsg := TypeMessage{
- Type: "notice",
- Data: msg,
- }
- jsonStrByte, _ := json.Marshal(sendMsg)
- conn.WriteMessage(websocket.TextMessage, jsonStrByte)
- }
- //定时给客户端发送消息判断客户端是否在线
- func sendPingToClient() {
- msg := TypeMessage{
- Type: "ping",
- }
- go func() {
- for {
- str, _ := json.Marshal(msg)
- for uid, user := range clientList {
- err := user.conn.WriteMessage(websocket.TextMessage, str)
- if err != nil {
- delete(clientList, uid)
- models.UpdateVisitorStatus(uid, 0)
- }
- }
- for kefuId, kfConns := range kefuList {
- var newkfConns = make([]*websocket.Conn, 0)
- for _, kefuConn := range kfConns {
- if kefuConn == nil {
- continue
- }
- err := kefuConn.WriteMessage(websocket.TextMessage, str)
- if err == nil {
- newkfConns = append(newkfConns, kefuConn)
- }
- }
- if newkfConns == nil {
- delete(kefuList, kefuId)
- } else {
- kefuList[kefuId] = newkfConns
- }
- }
- time.Sleep(15 * time.Second)
- }
- }()
- }
- //定时给更新数据库状态
- func UpdateVisitorStatusCron() {
- for {
- visitors := models.FindVisitorsOnline()
- for _, visitor := range visitors {
- if visitor.VisitorId == "" {
- continue
- }
- _, ok := clientList[visitor.VisitorId]
- if !ok {
- models.UpdateVisitorStatus(visitor.VisitorId, 0)
- }
- }
- time.Sleep(60 * time.Second)
- }
- }
- //定时推送当前在线用户
- func sendPingOnlineUsers() {
- var visitorIds []string
- for visitorId, _ := range clientList {
- visitorIds = append(visitorIds, visitorId)
- }
- sort.Strings(visitorIds)
- for kefuId, kfConns := range kefuList {
- result := make([]map[string]string, 0)
- for _, visitorId := range visitorIds {
- user := clientList[visitorId]
- userInfo := make(map[string]string)
- userInfo["uid"] = user.id
- userInfo["username"] = user.name
- userInfo["avator"] = user.avator
- if user.to_id == kefuId {
- result = append(result, userInfo)
- }
- }
- msg := TypeMessage{
- Type: "allUsers",
- Data: result,
- }
- str, _ := json.Marshal(msg)
- var newkfConns = make([]*websocket.Conn, 0)
- for _, kefuConn := range kfConns {
- err := kefuConn.WriteMessage(websocket.TextMessage, str)
- if err == nil {
- newkfConns = append(newkfConns, kefuConn)
- }
- }
- if len(newkfConns) == 0 {
- delete(kefuList, kefuId)
- } else {
- kefuList[kefuId] = newkfConns
- }
- }
- }
- //后端广播发送消息
- func singleBroadcaster() {
- for {
- message := <-message
- //log.Println("debug:",message)
- var typeMsg TypeMessage
- var clientMsg ClientMessage
- json.Unmarshal(message.content, &typeMsg)
- conn := message.conn
- if typeMsg.Type == nil || typeMsg.Data == nil {
- continue
- }
- msgType := typeMsg.Type.(string)
- msgData, _ := json.Marshal(typeMsg.Data)
- switch msgType {
- //用户上线
- case "userInit":
- json.Unmarshal(msgData, &clientMsg)
- vistorInfo := models.FindVisitorByVistorId(clientMsg.VisitorId)
- if vistorInfo.VisitorId == "" {
- SendNotice("访客数据不存在", conn)
- continue
- }
- //用户id对应的连接
- user := &vistor{
- conn: conn,
- name: clientMsg.Name,
- avator: clientMsg.Avator,
- id: clientMsg.VisitorId,
- to_id: clientMsg.ToId,
- }
- clientList[clientMsg.VisitorId] = user
- //插入数据表
- models.UpdateVisitor(clientMsg.VisitorId, 1, clientMsg.ClientIp, message.c.ClientIP(), clientMsg.Refer)
- //models.CreateVisitor(clientMsg.Name,clientMsg.Avator,message.c.ClientIP(),clientMsg.ToId,clientMsg.VisitorId,clientMsg.Refer,clientMsg.City,clientMsg.ClientIp)
- userInfo := make(map[string]string)
- userInfo["uid"] = user.id
- userInfo["username"] = user.name
- userInfo["avator"] = user.avator
- msg := TypeMessage{
- Type: "userOnline",
- Data: userInfo,
- }
- str, _ := json.Marshal(msg)
- //新版
- mKefuConns := ws.KefuList[user.to_id]
- if mKefuConns != nil {
- for _, kefu := range mKefuConns {
- kefu.Conn.WriteMessage(websocket.TextMessage, str)
- }
- }
- //兼容旧版
- kefuConns := kefuList[user.to_id]
- if kefuConns != nil {
- for k, kefuConn := range kefuConns {
- log.Println(k, "xxxxxxxx")
- kefuConn.WriteMessage(websocket.TextMessage, str)
- }
- }
- //客户上线发微信通知
- go SendServerJiang(userInfo["username"])
- sendPingOnlineUsers()
- //客服上线
- case "kfOnline":
- json.Unmarshal(msgData, &clientMsg)
- //客服id对应的连接
- var newKefuConns = []*websocket.Conn{conn}
- kefuConns := kefuList[clientMsg.Id]
- if kefuConns != nil {
- newKefuConns = append(newKefuConns, kefuConns...)
- }
- log.Println(newKefuConns)
- kefuList[clientMsg.Id] = newKefuConns
- //发送给客户
- if len(clientList) == 0 {
- continue
- }
- sendPingOnlineUsers()
- //客服接手
- case "kfConnect":
- json.Unmarshal(msgData, &clientMsg)
- visitor, ok := clientList[clientMsg.ToId]
- if visitor == nil || !ok {
- continue
- }
- SendKefuOnline(clientMsg, visitor.conn)
- //心跳
- case "ping":
- msg := TypeMessage{
- Type: "pong",
- }
- str, _ := json.Marshal(msg)
- conn.WriteMessage(websocket.TextMessage, str)
- }
- }
- }
|