互动
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
4.3 KiB

5 years ago
  1. package ws
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/rs/zerolog/log"
  6. "gopkg.in/olahol/melody.v1"
  7. "strings"
  8. "sync"
  9. )
  10. // 根据主活动划分房间 ==> 适配现有的可以
  11. // 在主活动开始的时候
  12. // HandleConnect 处理房间号
  13. // HandleMessage 处理逻辑函数 包括登录, 同步 .... 发送到特定的用户
  14. // HandleDisconnect 处理房间删除, 链接删除
  15. // 登录, 用户注册
  16. // tag 或者 ?activity_id=? 作为一个标志
  17. // 同步消息 => 发送给所有的用户 使用协程池
  18. // NewWebSocket
  19. // Connect
  20. // Disconnect
  21. // Message
  22. // Run
  23. var N = NewNode()
  24. type Node struct {
  25. conns map[*melody.Session]*Client
  26. main *Client // 通过client 发送信息
  27. rooms map[string]*Room // 房间
  28. handles map[string]logic // 逻辑函数
  29. rwmux *sync.RWMutex
  30. }
  31. func NewNode() *Node {
  32. node := new(Node)
  33. node.conns = make(map[*melody.Session]*Client, 0)
  34. node.main = new(Client)
  35. node.rooms = make(map[string]*Room, 0)
  36. node.handles = make(map[string]logic, 0)
  37. node.rwmux = new(sync.RWMutex)
  38. return node
  39. }
  40. func (t *Node) handleMelodyConnect(client *Client) {
  41. log.Printf("[websocket] [ws] [room:%s] [client:%s] %s\n", client.RoomId, client.Id, client.Request.URL)
  42. }
  43. // 处理msg
  44. func (t *Node) handleMelodyMessage(client *Client, msg *Message) {
  45. if !client.Online && msg.Type != TypeLogin {
  46. _ = client.WriteJson(map[string]interface{}{
  47. "msg": "尚未登录",
  48. "code": 504,
  49. })
  50. return
  51. }
  52. if fn, ok := t.handles[msg.Type]; ok {
  53. fn(client, msg)
  54. }
  55. log.Printf("[websocket] [message] [room:%s] [client:%s] %v\n", client.RoomId, client.Id, msg)
  56. }
  57. // 删掉注册的
  58. func (t *Node) handleMelodyDisconnect(client *Client) {
  59. if client.Online && strings.HasPrefix(client.Id, IDCustomer) {
  60. if client.Pid == 0 { // 主账号下线 通知子账号
  61. msg := &Message{
  62. Type: TypeNotice,
  63. Dest: 0,
  64. Tag: IDCustomer,
  65. RoomId: client.RoomId,
  66. From: client.Id,
  67. Data: map[string]interface{}{
  68. "id": client.AccountId,
  69. "content": "主账号下线",
  70. },
  71. }
  72. t.Send(msg)
  73. } else { // 子账号下线 通知主账号
  74. msg := &Message{
  75. Type: TypeNotice,
  76. Dest: client.Pid,
  77. Tag: IDCustomer,
  78. RoomId: client.RoomId,
  79. From: client.Id,
  80. Data: map[string]interface{}{
  81. "id": client.AccountId,
  82. "content": "子账号下线",
  83. },
  84. }
  85. t.Send(msg)
  86. }
  87. }
  88. // 释放内存
  89. if room, ok := t.rooms[client.RoomId]; ok {
  90. room.DeleteClient(client.Id)
  91. if room.Len() <= 0 {
  92. t.DeleteRoom(room.Id)
  93. }
  94. }
  95. log.Printf("[websocket] [disconnect] [room:%s] [client:%s] online=>%v\n", client.RoomId, client.Id, client.Online)
  96. }
  97. func (t *Node) RegisterLogic(name string, fn logic) {
  98. t.handles[name] = fn
  99. }
  100. func (t *Node) RegisterClient(c *Client) error {
  101. if room, ok := t.rooms[c.RoomId]; ok {
  102. room.rwmux.Lock()
  103. defer room.rwmux.Unlock()
  104. room.clients[c.Id] = c
  105. return nil
  106. }
  107. return errors.New("加入房间失败")
  108. }
  109. // 所有人同步
  110. func (t *Node) BroadcastAll(msg *Message, c *Client) {
  111. // 发送给连上ws的所有人
  112. m := msg.Encode()
  113. for _, client := range t.conns {
  114. if client == c {
  115. continue
  116. }
  117. _ = client.Write(m)
  118. }
  119. }
  120. func (t *Node) Send(msg *Message) {
  121. if msg.Dest == 0 && msg.Tag == "" { // 代表发送给所有人
  122. t.Broadcast(msg)
  123. } else if msg.Dest == 0 && msg.Tag != "" { // 代表发给某个团体
  124. t.BroadcastTag(msg)
  125. } else if msg.Dest != 0 && msg.Tag != "" {
  126. t.BroadcastDest(msg)
  127. } else {
  128. log.Printf("[websocket] [send] msg=>%v", msg)
  129. }
  130. }
  131. // 发送给所有的
  132. // delete 删除 room client
  133. func (t *Node) Broadcast(msg *Message) {
  134. m := msg.Encode()
  135. if room, ok := t.rooms[msg.RoomId]; ok && room != nil {
  136. for _, client := range room.clients {
  137. if client.Id != msg.From {
  138. _ = client.Write(m)
  139. }
  140. }
  141. }
  142. }
  143. func (t *Node) BroadcastTag(msg *Message) {
  144. m := msg.Encode()
  145. if room, ok := t.rooms[msg.RoomId]; ok {
  146. for _, client := range room.clients {
  147. if client.AccountType == msg.Tag && client.Id != msg.From {
  148. _ = client.Write(m)
  149. }
  150. }
  151. }
  152. }
  153. func (t *Node) BroadcastDest(msg *Message) {
  154. m := msg.Encode()
  155. if room, ok := t.rooms[msg.RoomId]; ok {
  156. client := room.clients[fmt.Sprintf("%s:%d", msg.Tag, msg.Dest)]
  157. if client.Id != msg.From {
  158. _ = client.Write(m)
  159. }
  160. }
  161. }
  162. func (t *Node) DeleteRoom(roomId string) {
  163. t.rwmux.Lock()
  164. defer t.rwmux.Unlock()
  165. delete(t.rooms, roomId)
  166. }