package controllers import ( "encoding/json" "fmt" "time" "github.com/gofiber/websocket/v2" "github.com/google/uuid" "go.uber.org/zap" ) type WsHandler func(messageType int, p []byte) bool type Client struct { ID string Conn *websocket.Conn } type MessageBody struct { Type string Data string } var clients = make(map[string]*Client) var handlers = make([]WsHandler, 0) func GlobalWebSocket(c *websocket.Conn) { sid := c.Cookies("sid") if sid == "" { sid = uuid.New().String() } client := &Client{ID: sid, Conn: c} clients[sid] = client defer func() { delete(clients, sid) c.Close() }() fmt.Println("Client connected:", sid) // 60 秒未收到任何 Pong/消息就判定断线 c.SetReadDeadline(time.Now().Add(60 * time.Second)) c.SetPongHandler(func(appData string) error { fmt.Println("📡 收到 pong 响应") c.SetReadDeadline(time.Now().Add(60 * time.Second)) return nil }) // 启动心跳 goroutine go func() { ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() for range ticker.C { if err := c.WriteMessage(websocket.PingMessage, []byte("ping")); err != nil { fmt.Println("❌ 发送 ping 失败,关闭连接:", err) c.Close() return } fmt.Println("🟢 发送 ping") } }() for { // 读取消息 msgType, msg, err := c.ReadMessage() if err != nil { zap.L().Error("GlobalWebSocket read err", zap.String("err", err.Error())) break } fmt.Printf("[%s] recv: %s\n", sid, string(msg)) // 处理消息 for _, handler := range handlers { ok := handler(msgType, msg) if ok { break } } } } func sendGlobalWebSocketMessage(body MessageBody) { for _, client := range clients { if client == nil { continue } payload, err := json.Marshal(body) if err != nil { zap.L().Error("json序列化失败", zap.String("err", err.Error())) continue } client.Conn.WriteMessage(websocket.TextMessage, []byte(payload)) } } func RegisterGlobalWebSocketHandle(f WsHandler) { handlers = append(handlers, f) } // 以下实现发送各种消息的接口