| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- // 客户端管理模块
- // 处理单个 WebSocket 客户端的连接、消息读取和发送
- package wsClient
- import (
- "encoding/json"
- "fmt"
- "github.com/gorilla/websocket" // WebSocket 库
- )
- // Client represents connection to a single chatting user
- // Client 表示一个聊天用户的连接
- // 每个 WebSocket 连接对应一个 Client 实例
- type Client struct {
- // 客户端名称 -- 用作唯一标识,进行查找用的 (门店端: shop_{shopId}_{userId}, 买家端: customer_{customId}_{userId})
- // 在消息中用于标识消息发送者
- name string
- // a socket is the web socket for this uer
- // WebSocket 连接对象,用于与浏览器端进行双向通信
- socket *websocket.Conn
- //receive is a channel to receive messages from other clients
- // 用于接收来自其他客户端的消息的 channel
- // 房间会将广播的消息发送到这个 channel
- receive chan []byte
- //room is where the client is chatting in
- // 客户端所在的聊天房间引用
- // 用于将发送的消息转发给房间
- room *Room
- // 新增的用户参数
- userInfo UserInfo
- }
- type UserInfo struct {
- UserId int32 `json:"userId"`
- Username string `json:"username"`
- CustomId int32 `json:"customId"`
- ShopId int32 `json:"shopId"`
- Platform string `json:"platform"`
- Type string `json:"type,omitempty"` // 客户端类型 -- shop:门店端, customer:客户端
- StaffId int32 `json:"staffId"`
- }
- // read 从 WebSocket 连接读取消息并转发给房间 (原作者说: Used to send messages)
- // 这个方法会阻塞运行直到连接断开或出现错误
- func (c *Client) read() {
- // close the connection when we are done
- defer c.socket.Close()
- // endlessly read messages from input
- for {
- // 从 WebSocket 连接读取消息
- // _ 表示忽略消息类型,msg 是消息内容,err 是错误
- _, msg, err := c.socket.ReadMessage()
- // break if there is an error
- if err != nil {
- return
- }
- // 构造要发送的消息对象,包含用户名和消息内容
- outgoing := map[string]string{
- "name": c.name, // 发送者用户名
- "message": string(msg), // 消息内容(转换为字符串)
- }
- // 将消息对象编码为 JSON 格式
- jsMessage, err := json.Marshal(outgoing)
- if err != nil {
- fmt.Println("Enconding failed!")
- continue
- }
- // 将编码后的消息和发送者信息一起发送到房间的 forward channel
- c.room.forward <- &message{
- content: jsMessage, // 消息内容
- sender: c, // 发送者(当前客户端)
- } // 房间会将这条消息分发给除发送者外的所有其他客户端(在 room.go 中 run() 方法 case msg := <-r.forward 中)
- }
- }
- // write 从 receive channel 读取消息并发送给客户端
- // 在独立的 goroutine 中运行,处理向客户端发送消息的任务
- func (c *Client) write() {
- defer c.socket.Close()
- // 循环从 receive channel 读取消息
- for msg := range c.receive {
- err := c.socket.WriteMessage(websocket.TextMessage, msg)
- if err != nil {
- return
- }
- }
- }
- // 根据房间参数生成客户端名称
- // 用于生成客户端的唯一标识,用作唯一标识,进行查找用的 (门店端: shop_{shopId}_{userId}, 买家端: customer_{customId}_{userId})
- func clientName(roomParams *RoomParams) string {
- // 首先根据 Type 来判断是门店端还是买家端
- if roomParams.Type == "shop" {
- return fmt.Sprintf("shop_%d_%d", roomParams.ShopId, roomParams.UserId)
- } else {
- return fmt.Sprintf("customer_%d_%d", roomParams.CustomId, roomParams.UserId)
- }
- }
|