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.
187 lines
4.3 KiB
187 lines
4.3 KiB
package ws
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/rs/zerolog/log"
|
|
"gopkg.in/olahol/melody.v1"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// 根据主活动划分房间 ==> 适配现有的可以
|
|
// 在主活动开始的时候
|
|
// HandleConnect 处理房间号
|
|
// HandleMessage 处理逻辑函数 包括登录, 同步 .... 发送到特定的用户
|
|
// HandleDisconnect 处理房间删除, 链接删除
|
|
|
|
// 登录, 用户注册
|
|
// tag 或者 ?activity_id=? 作为一个标志
|
|
|
|
// 同步消息 => 发送给所有的用户 使用协程池
|
|
|
|
// NewWebSocket
|
|
// Connect
|
|
// Disconnect
|
|
// Message
|
|
// Run
|
|
|
|
var N = NewNode()
|
|
|
|
type Node struct {
|
|
conns map[*melody.Session]*Client
|
|
main *Client // 通过client 发送信息
|
|
rooms map[string]*Room // 房间
|
|
handles map[string]logic // 逻辑函数
|
|
rwmux *sync.RWMutex
|
|
}
|
|
|
|
func NewNode() *Node {
|
|
node := new(Node)
|
|
node.conns = make(map[*melody.Session]*Client, 0)
|
|
node.main = new(Client)
|
|
node.rooms = make(map[string]*Room, 0)
|
|
node.handles = make(map[string]logic, 0)
|
|
node.rwmux = new(sync.RWMutex)
|
|
return node
|
|
}
|
|
|
|
func (t *Node) handleMelodyConnect(client *Client) {
|
|
log.Printf("[websocket] [ws] [room:%s] [client:%s] %s\n", client.RoomId, client.Id, client.Request.URL)
|
|
}
|
|
|
|
// 处理msg
|
|
func (t *Node) handleMelodyMessage(client *Client, msg *Message) {
|
|
if !client.Online && msg.Type != TypeLogin {
|
|
_ = client.WriteJson(map[string]interface{}{
|
|
"msg": "尚未登录",
|
|
"code": 504,
|
|
})
|
|
//client.Write([]byte("尚未登录"))
|
|
return
|
|
}
|
|
|
|
if fn, ok := t.handles[msg.Type]; ok {
|
|
fn(client, msg)
|
|
}
|
|
log.Printf("[websocket] [message] [room:%s] [client:%s] %v\n", client.RoomId, client.Id, msg)
|
|
}
|
|
|
|
// 删掉注册的
|
|
func (t *Node) handleMelodyDisconnect(client *Client) {
|
|
if client.Online && strings.HasPrefix(client.Id, IDCustomer) {
|
|
if client.Pid == 0 { // 主账号下线 通知子账号
|
|
msg := &Message{
|
|
Type: TypeNotice,
|
|
Dest: 0,
|
|
Tag: IDCustomer,
|
|
RoomId: client.RoomId,
|
|
From: client.Id,
|
|
Data: map[string]interface{}{
|
|
"id": client.AccountId,
|
|
"content": "主账号下线",
|
|
},
|
|
}
|
|
t.Send(msg)
|
|
} else { // 子账号下线 通知主账号
|
|
msg := &Message{
|
|
Type: TypeNotice,
|
|
Dest: client.Pid,
|
|
Tag: IDCustomer,
|
|
RoomId: client.RoomId,
|
|
From: client.Id,
|
|
Data: map[string]interface{}{
|
|
"id": client.AccountId,
|
|
"content": "子账号下线",
|
|
},
|
|
}
|
|
t.Send(msg)
|
|
}
|
|
}
|
|
// 释放内存
|
|
if room, ok := t.rooms[client.RoomId]; ok {
|
|
room.DeleteClient(client.Id)
|
|
if room.Len() <= 0 {
|
|
t.DeleteRoom(room.Id)
|
|
}
|
|
}
|
|
log.Printf("[websocket] [disconnect] [room:%s] [client:%s] online=>%v\n", client.RoomId, client.Id, client.Online)
|
|
}
|
|
|
|
func (t *Node) RegisterLogic(name string, fn logic) {
|
|
t.handles[name] = fn
|
|
}
|
|
|
|
func (t *Node) RegisterClient(c *Client) error {
|
|
if room, ok := t.rooms[c.RoomId]; ok {
|
|
room.rwmux.Lock()
|
|
defer room.rwmux.Unlock()
|
|
room.clients[c.Id] = c
|
|
return nil
|
|
}
|
|
return errors.New("加入房间失败")
|
|
}
|
|
|
|
// 所有人同步
|
|
func (t *Node) BroadcastAll(msg *Message, c *Client) {
|
|
// 发送给连上ws的所有人
|
|
m := msg.Encode()
|
|
for _, client := range t.conns {
|
|
if client == c {
|
|
continue
|
|
}
|
|
_ = client.Write(m)
|
|
}
|
|
}
|
|
|
|
func (t *Node) Send(msg *Message) {
|
|
if msg.Dest == 0 && msg.Tag == "" { // 代表发送给所有人
|
|
t.Broadcast(msg)
|
|
} else if msg.Dest == 0 && msg.Tag != "" { // 代表发给某个团体
|
|
t.BroadcastTag(msg)
|
|
} else if msg.Dest != 0 && msg.Tag != "" {
|
|
t.BroadcastDest(msg)
|
|
} else {
|
|
log.Printf("[websocket] [send] msg=>%v", msg)
|
|
}
|
|
}
|
|
|
|
// 发送给所有的
|
|
// delete 删除 room client
|
|
func (t *Node) Broadcast(msg *Message) {
|
|
m := msg.Encode()
|
|
if room, ok := t.rooms[msg.RoomId]; ok && room != nil {
|
|
for _, client := range room.clients {
|
|
if client.Id != msg.From {
|
|
_ = client.Write(m)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Node) BroadcastTag(msg *Message) {
|
|
m := msg.Encode()
|
|
if room, ok := t.rooms[msg.RoomId]; ok {
|
|
for _, client := range room.clients {
|
|
if client.AccountType == msg.Tag && client.Id != msg.From {
|
|
_ = client.Write(m)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Node) BroadcastDest(msg *Message) {
|
|
m := msg.Encode()
|
|
if room, ok := t.rooms[msg.RoomId]; ok {
|
|
client := room.clients[fmt.Sprintf("%s:%d", msg.Tag, msg.Dest)]
|
|
if client.Id != msg.From {
|
|
_ = client.Write(m)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Node) DeleteRoom(roomId string) {
|
|
t.rwmux.Lock()
|
|
defer t.rwmux.Unlock()
|
|
delete(t.rooms, roomId)
|
|
}
|