2025-06-12 09:07:49 +00:00
|
|
|
|
// Package ws -----------------------------
|
|
|
|
|
// @file : client.go
|
|
|
|
|
// @author : JJXu
|
|
|
|
|
// @contact : wavingbear@163.com
|
|
|
|
|
// @time : 2022/10/21 18:18:05
|
|
|
|
|
// -------------------------------------------
|
|
|
|
|
package ws
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
|
uuid "github.com/satori/go.uuid"
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
"log"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
// 注册事件最大等待时间
|
|
|
|
|
limitRegisterWaitTime = time.Second * 6
|
|
|
|
|
limitReadTime = time.Second * 5
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// NewClient 创建客户端实例
|
|
|
|
|
//
|
|
|
|
|
// param userId 用户id
|
|
|
|
|
// param uid 用户uuid
|
|
|
|
|
// param conn 客户端websocket连接对象
|
|
|
|
|
// return *Client
|
|
|
|
|
func NewClient(userId int64, uid string, conn *websocket.Conn, room *ChatRoom) *Client {
|
|
|
|
|
uidobj, _ := uuid.NewV4()
|
|
|
|
|
var v = &Client{
|
|
|
|
|
Room: room,
|
|
|
|
|
UserId: userId,
|
|
|
|
|
Uuid: uid,
|
|
|
|
|
ClientId: strings.Replace(uidobj.String(), "-", "", -1),
|
|
|
|
|
Conn: conn,
|
|
|
|
|
Send: make(chan []byte, 500),
|
|
|
|
|
}
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
|
Room *ChatRoom `json:"-" `
|
|
|
|
|
UserId int64 `json:"userId" ` //用户id
|
|
|
|
|
Uuid string `json:"uuid"` //画家uid
|
|
|
|
|
ClientId string `json:"clientId"` //为用户不同设备分配不同的客户端ID
|
|
|
|
|
Conn *websocket.Conn `json:"-"`
|
|
|
|
|
Send chan []byte
|
|
|
|
|
SessionId string `json:"sessionId"` //会话ID,同一个用户多客户端登录,会话ID相同
|
|
|
|
|
Waiter bool `json:"waiter"` //是否是客服
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) Reading(ctx context.Context, handleFunc ...func(sourceData []byte, cli *Client)) {
|
|
|
|
|
defer func() {
|
|
|
|
|
c.Room.UnRegister <- c
|
|
|
|
|
ctx.Done()
|
|
|
|
|
return
|
|
|
|
|
}()
|
|
|
|
|
//c.Conn.SetReadLimit(maxMessageSize)
|
|
|
|
|
c.Conn.SetReadDeadline(time.Now().Add(pongWait))
|
|
|
|
|
//接收到ping命令后,更新读取时间
|
|
|
|
|
c.Conn.SetPongHandler(func(string) error {
|
|
|
|
|
c.Conn.SetReadDeadline(time.Now().Add(pongWait))
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
for {
|
|
|
|
|
msgType, byteData, err := c.Conn.ReadMessage()
|
|
|
|
|
if msgType == -1 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
|
|
|
|
log.Println("ws连接已关闭", zap.Error(err))
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if handleFunc != nil {
|
|
|
|
|
handleFunc[0](byteData, c)
|
|
|
|
|
} else {
|
|
|
|
|
HandleMessage(byteData, c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func (c *Client) WriteWait() {
|
|
|
|
|
ticker := time.NewTicker(pingPeriod)
|
|
|
|
|
defer func() {
|
|
|
|
|
ticker.Stop()
|
|
|
|
|
c.Conn.Close()
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case msg, ok := <-c.Send:
|
|
|
|
|
if !ok {
|
|
|
|
|
// 聊天室关闭了管道
|
|
|
|
|
c.Conn.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(writeWait))
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-06-17 01:31:47 +00:00
|
|
|
|
// 设置写入超时
|
|
|
|
|
err := c.Conn.SetWriteDeadline(time.Now().Add(writeWait))
|
|
|
|
|
fmt.Printf("设置写超时 err check:%v\n", err)
|
|
|
|
|
fmt.Printf("发送消息:%+v\n", string(msg))
|
|
|
|
|
err = c.Conn.WriteMessage(websocket.TextMessage, msg)
|
|
|
|
|
fmt.Printf("发送消息结束 err check:%v\n", err)
|
2025-06-12 09:07:49 +00:00
|
|
|
|
case <-ticker.C:
|
2025-06-17 01:31:47 +00:00
|
|
|
|
fmt.Println("ping websocket client")
|
|
|
|
|
err := c.Conn.SetWriteDeadline(time.Now().Add(writeWait))
|
|
|
|
|
fmt.Printf("ping 设置写超时 err check:%v\n", err)
|
2025-06-12 09:07:49 +00:00
|
|
|
|
if err := c.Conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(pongWait)); err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|