client.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package server
  2. import (
  3. "encoding/json"
  4. "time"
  5. "github.com/gin-gonic/gin"
  6. "github.com/google/uuid"
  7. "github.com/gorilla/websocket"
  8. "sikey.com/websocket/models"
  9. "sikey.com/websocket/repositories"
  10. "sikey.com/websocket/utils/zlog"
  11. )
  12. type Client struct {
  13. ctx *gin.Context
  14. UserId string
  15. hub *Hub
  16. UnderlyingConn *websocket.Conn
  17. isSimpleMsg bool // isSimpleMsg 是否是简单消息
  18. localization string // localization 国际码
  19. // Send message channel 发送消息
  20. // 当用户在线时会通过 Send channel 发送在线消息 但如果用户不在线,
  21. // 则会通过 SendOffline channel 发送离线消息
  22. Send chan *Message
  23. SendOffline chan *Message // SendOffline 发送离线消息
  24. readWait time.Duration // readWait 读超时
  25. writeWait time.Duration // writeWait 写超时
  26. pingWait time.Duration // pingWait 心跳超时
  27. repos *repositories.Repositories
  28. }
  29. func (c *Client) reader() {
  30. defer func() {
  31. c.hub.Disconnect <- c
  32. c.UnderlyingConn.Close()
  33. }()
  34. c.UnderlyingConn.SetReadDeadline(time.Now().Add(c.readWait))
  35. for {
  36. _, bytes, err := c.UnderlyingConn.ReadMessage()
  37. if err != nil {
  38. if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
  39. zlog.Errorf("error: %v", err)
  40. }
  41. break
  42. }
  43. message := deserializeMessage(bytes)
  44. switch message.Type {
  45. case MessageTypeUpChating, MessageTypeDownChating:
  46. // Chat dialogue messages
  47. chatingContent := message.Content.(ChatingContent)
  48. // Save message to database
  49. payload, _ := json.Marshal(chatingContent.Payload)
  50. messageId := uuid.NewString()
  51. err := c.repos.SessionRepository.CreateMessage(c.ctx, &models.SessionMessage{
  52. ID: messageId,
  53. SessionId: chatingContent.Receiver,
  54. Receiver: chatingContent.Receiver,
  55. Sender: c.UserId,
  56. Type: uint8(message.Type),
  57. ContentType: uint8(chatingContent.PayloadType),
  58. Content: string(payload),
  59. IsRead: false,
  60. })
  61. if err != nil {
  62. c.writeError(message.RequestId, err)
  63. continue
  64. }
  65. members, err := c.repos.SessionRepository.GetSessionMembersRemoveOneself(
  66. c.ctx, chatingContent.Receiver, c.UserId)
  67. if err != nil {
  68. c.writeError(message.RequestId, err)
  69. continue
  70. }
  71. for _, member := range members {
  72. var messaging = *message
  73. messaging.receiver = member.AccountId
  74. messaging.Content = chatingContent
  75. c.hub.Message <- &messaging
  76. }
  77. // Reply message id
  78. message.Content = &ContentReply{MessageId: messageId}
  79. }
  80. // Reply message
  81. if message.IsNeedReply() {
  82. c.Send <- newReplyMessage(message)
  83. // Reset read dead line, prevent Reader from shutting down
  84. c.UnderlyingConn.SetReadDeadline(time.Now().Add(c.pingWait))
  85. }
  86. }
  87. }
  88. func (c *Client) writer() {
  89. ticker := time.NewTicker(c.pingWait)
  90. defer func() {
  91. ticker.Stop()
  92. c.UnderlyingConn.Close()
  93. }()
  94. for {
  95. select {
  96. case message, ok := <-c.Send:
  97. c.UnderlyingConn.SetWriteDeadline(time.Now().Add(c.writeWait))
  98. if !ok {
  99. // The hub closed the channel.
  100. c.UnderlyingConn.WriteMessage(websocket.CloseMessage, []byte{})
  101. return
  102. }
  103. var err error
  104. err = c.UnderlyingConn.WriteMessage(websocket.TextMessage, serializationMessage(message))
  105. if err != nil {
  106. return
  107. }
  108. case <-ticker.C:
  109. // 到时间发送 ping 信号
  110. c.UnderlyingConn.SetWriteDeadline(time.Now().Add(c.writeWait))
  111. if err := c.UnderlyingConn.WriteMessage(websocket.PingMessage, nil); err != nil {
  112. return
  113. }
  114. }
  115. }
  116. }
  117. func (c *Client) writeError(requestId string, err error) {
  118. c.Send <- &Message{
  119. RequestId: requestId,
  120. Type: MessageTypeError,
  121. Content: ContentError{Err: err.Error()},
  122. }
  123. }