chat.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. package controller
  2. import (
  3. "encoding/json"
  4. "github.com/gin-gonic/gin"
  5. "github.com/gorilla/websocket"
  6. "github.com/wenstudio/gofly/models"
  7. "github.com/wenstudio/gofly/ws"
  8. "log"
  9. "net/http"
  10. "sort"
  11. "time"
  12. )
  13. type vistor struct {
  14. conn *websocket.Conn
  15. name string
  16. id string
  17. avator string
  18. to_id string
  19. }
  20. type Message struct {
  21. conn *websocket.Conn
  22. c *gin.Context
  23. content []byte
  24. messageType int
  25. }
  26. var clientList = make(map[string]*vistor)
  27. var kefuList = make(map[string][]*websocket.Conn)
  28. var message = make(chan *Message)
  29. type TypeMessage struct {
  30. Type interface{} `json:"type"`
  31. Data interface{} `json:"data"`
  32. }
  33. type ClientMessage struct {
  34. Name string `json:"name"`
  35. Avator string `json:"avator"`
  36. Id string `json:"id"`
  37. VisitorId string `json:"visitor_id"`
  38. Group string `json:"group"`
  39. Time string `json:"time"`
  40. ToId string `json:"to_id"`
  41. Content string `json:"content"`
  42. City string `json:"city"`
  43. ClientIp string `json:"client_ip"`
  44. Refer string `json:"refer"`
  45. }
  46. //定时检测客户端是否在线
  47. func init() {
  48. upgrader = websocket.Upgrader{
  49. ReadBufferSize: 1024,
  50. WriteBufferSize: 1024,
  51. CheckOrigin: func(r *http.Request) bool {
  52. return true
  53. },
  54. }
  55. go UpdateVisitorStatusCron()
  56. go singleBroadcaster()
  57. //go sendPingOnlineUsers()
  58. //sendPingToClient()
  59. }
  60. func NewChatServer(c *gin.Context) {
  61. conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
  62. if err != nil {
  63. log.Print("upgrade:", err)
  64. return
  65. }
  66. for {
  67. //接受消息
  68. var receive []byte
  69. var recevString string
  70. messageType, receive, err := conn.ReadMessage()
  71. if err != nil {
  72. for uid, visitor := range clientList {
  73. if visitor.conn == conn {
  74. log.Println("删除用户", uid)
  75. delete(clientList, uid)
  76. models.UpdateVisitorStatus(uid, 0)
  77. userInfo := make(map[string]string)
  78. userInfo["uid"] = uid
  79. userInfo["name"] = visitor.name
  80. msg := TypeMessage{
  81. Type: "userOffline",
  82. Data: userInfo,
  83. }
  84. str, _ := json.Marshal(msg)
  85. kefuConns := kefuList[visitor.to_id]
  86. if kefuConns != nil {
  87. for _, kefuConn := range kefuConns {
  88. kefuConn.WriteMessage(websocket.TextMessage, str)
  89. }
  90. }
  91. //新版
  92. mKefuConns := ws.KefuList[visitor.to_id]
  93. if mKefuConns != nil {
  94. for _, kefu := range mKefuConns {
  95. kefu.Conn.WriteMessage(websocket.TextMessage, str)
  96. }
  97. }
  98. sendPingOnlineUsers()
  99. }
  100. }
  101. log.Println(err)
  102. return
  103. }
  104. recevString = string(receive)
  105. log.Println("客户端:", recevString)
  106. message <- &Message{
  107. conn: conn,
  108. content: receive,
  109. c: c,
  110. messageType: messageType,
  111. }
  112. }
  113. }
  114. //发送给客户客服上线
  115. func SendKefuOnline(clientMsg ClientMessage, conn *websocket.Conn) {
  116. sendMsg := TypeMessage{
  117. Type: "kfOnline",
  118. Data: ClientMessage{
  119. Name: clientMsg.Name,
  120. Avator: clientMsg.Avator,
  121. Id: clientMsg.Id,
  122. Group: clientMsg.Group,
  123. Time: time.Now().Format("2006-01-02 15:04:05"),
  124. Content: "客服上线",
  125. },
  126. }
  127. jsonStrByte, _ := json.Marshal(sendMsg)
  128. conn.WriteMessage(websocket.TextMessage, jsonStrByte)
  129. }
  130. //发送通知
  131. func SendNotice(msg string, conn *websocket.Conn) {
  132. sendMsg := TypeMessage{
  133. Type: "notice",
  134. Data: msg,
  135. }
  136. jsonStrByte, _ := json.Marshal(sendMsg)
  137. conn.WriteMessage(websocket.TextMessage, jsonStrByte)
  138. }
  139. //定时给客户端发送消息判断客户端是否在线
  140. func sendPingToClient() {
  141. msg := TypeMessage{
  142. Type: "ping",
  143. }
  144. go func() {
  145. for {
  146. str, _ := json.Marshal(msg)
  147. for uid, user := range clientList {
  148. err := user.conn.WriteMessage(websocket.TextMessage, str)
  149. if err != nil {
  150. delete(clientList, uid)
  151. models.UpdateVisitorStatus(uid, 0)
  152. }
  153. }
  154. for kefuId, kfConns := range kefuList {
  155. var newkfConns = make([]*websocket.Conn, 0)
  156. for _, kefuConn := range kfConns {
  157. if kefuConn == nil {
  158. continue
  159. }
  160. err := kefuConn.WriteMessage(websocket.TextMessage, str)
  161. if err == nil {
  162. newkfConns = append(newkfConns, kefuConn)
  163. }
  164. }
  165. if newkfConns == nil {
  166. delete(kefuList, kefuId)
  167. } else {
  168. kefuList[kefuId] = newkfConns
  169. }
  170. }
  171. time.Sleep(15 * time.Second)
  172. }
  173. }()
  174. }
  175. //定时给更新数据库状态
  176. func UpdateVisitorStatusCron() {
  177. for {
  178. visitors := models.FindVisitorsOnline()
  179. for _, visitor := range visitors {
  180. if visitor.VisitorId == "" {
  181. continue
  182. }
  183. _, ok := clientList[visitor.VisitorId]
  184. if !ok {
  185. models.UpdateVisitorStatus(visitor.VisitorId, 0)
  186. }
  187. }
  188. time.Sleep(60 * time.Second)
  189. }
  190. }
  191. //定时推送当前在线用户
  192. func sendPingOnlineUsers() {
  193. var visitorIds []string
  194. for visitorId, _ := range clientList {
  195. visitorIds = append(visitorIds, visitorId)
  196. }
  197. sort.Strings(visitorIds)
  198. for kefuId, kfConns := range kefuList {
  199. result := make([]map[string]string, 0)
  200. for _, visitorId := range visitorIds {
  201. user := clientList[visitorId]
  202. userInfo := make(map[string]string)
  203. userInfo["uid"] = user.id
  204. userInfo["username"] = user.name
  205. userInfo["avator"] = user.avator
  206. if user.to_id == kefuId {
  207. result = append(result, userInfo)
  208. }
  209. }
  210. msg := TypeMessage{
  211. Type: "allUsers",
  212. Data: result,
  213. }
  214. str, _ := json.Marshal(msg)
  215. var newkfConns = make([]*websocket.Conn, 0)
  216. for _, kefuConn := range kfConns {
  217. err := kefuConn.WriteMessage(websocket.TextMessage, str)
  218. if err == nil {
  219. newkfConns = append(newkfConns, kefuConn)
  220. }
  221. }
  222. if len(newkfConns) == 0 {
  223. delete(kefuList, kefuId)
  224. } else {
  225. kefuList[kefuId] = newkfConns
  226. }
  227. }
  228. }
  229. //后端广播发送消息
  230. func singleBroadcaster() {
  231. for {
  232. message := <-message
  233. //log.Println("debug:",message)
  234. var typeMsg TypeMessage
  235. var clientMsg ClientMessage
  236. json.Unmarshal(message.content, &typeMsg)
  237. conn := message.conn
  238. if typeMsg.Type == nil || typeMsg.Data == nil {
  239. continue
  240. }
  241. msgType := typeMsg.Type.(string)
  242. msgData, _ := json.Marshal(typeMsg.Data)
  243. switch msgType {
  244. //用户上线
  245. case "userInit":
  246. json.Unmarshal(msgData, &clientMsg)
  247. vistorInfo := models.FindVisitorByVistorId(clientMsg.VisitorId)
  248. if vistorInfo.VisitorId == "" {
  249. SendNotice("访客数据不存在", conn)
  250. continue
  251. }
  252. //用户id对应的连接
  253. user := &vistor{
  254. conn: conn,
  255. name: clientMsg.Name,
  256. avator: clientMsg.Avator,
  257. id: clientMsg.VisitorId,
  258. to_id: clientMsg.ToId,
  259. }
  260. clientList[clientMsg.VisitorId] = user
  261. //插入数据表
  262. models.UpdateVisitor(clientMsg.VisitorId, 1, clientMsg.ClientIp, message.c.ClientIP(), clientMsg.Refer)
  263. //models.CreateVisitor(clientMsg.Name,clientMsg.Avator,message.c.ClientIP(),clientMsg.ToId,clientMsg.VisitorId,clientMsg.Refer,clientMsg.City,clientMsg.ClientIp)
  264. userInfo := make(map[string]string)
  265. userInfo["uid"] = user.id
  266. userInfo["username"] = user.name
  267. userInfo["avator"] = user.avator
  268. msg := TypeMessage{
  269. Type: "userOnline",
  270. Data: userInfo,
  271. }
  272. str, _ := json.Marshal(msg)
  273. //新版
  274. mKefuConns := ws.KefuList[user.to_id]
  275. if mKefuConns != nil {
  276. for _, kefu := range mKefuConns {
  277. kefu.Conn.WriteMessage(websocket.TextMessage, str)
  278. }
  279. }
  280. //兼容旧版
  281. kefuConns := kefuList[user.to_id]
  282. if kefuConns != nil {
  283. for k, kefuConn := range kefuConns {
  284. log.Println(k, "xxxxxxxx")
  285. kefuConn.WriteMessage(websocket.TextMessage, str)
  286. }
  287. }
  288. //客户上线发微信通知
  289. go SendServerJiang(userInfo["username"])
  290. sendPingOnlineUsers()
  291. //客服上线
  292. case "kfOnline":
  293. json.Unmarshal(msgData, &clientMsg)
  294. //客服id对应的连接
  295. var newKefuConns = []*websocket.Conn{conn}
  296. kefuConns := kefuList[clientMsg.Id]
  297. if kefuConns != nil {
  298. newKefuConns = append(newKefuConns, kefuConns...)
  299. }
  300. log.Println(newKefuConns)
  301. kefuList[clientMsg.Id] = newKefuConns
  302. //发送给客户
  303. if len(clientList) == 0 {
  304. continue
  305. }
  306. sendPingOnlineUsers()
  307. //客服接手
  308. case "kfConnect":
  309. json.Unmarshal(msgData, &clientMsg)
  310. visitor, ok := clientList[clientMsg.ToId]
  311. if visitor == nil || !ok {
  312. continue
  313. }
  314. SendKefuOnline(clientMsg, visitor.conn)
  315. //心跳
  316. case "ping":
  317. msg := TypeMessage{
  318. Type: "pong",
  319. }
  320. str, _ := json.Marshal(msg)
  321. conn.WriteMessage(websocket.TextMessage, str)
  322. }
  323. }
  324. }