package ws import ( "log" "sync" "time" "github.com/gorilla/websocket" ) type WebSocketPool struct { conns map[string][]*websocket.Conn sync.RWMutex } // 创建新的连接池 func NewWebSocketPool() *WebSocketPool { return &WebSocketPool{ conns: make(map[string][]*websocket.Conn), } } // 添加一个 WebSocket 连接到指定 appID 下 func (p *WebSocketPool) Add(appID string, conn *websocket.Conn) { p.Lock() defer p.Unlock() p.conns[appID] = append(p.conns[appID], conn) } // 从连接池中移除一个连接 func (p *WebSocketPool) Remove(appID string, conn *websocket.Conn) { p.Lock() defer p.Unlock() if conns, ok := p.conns[appID]; ok { for i, c := range conns { if c == conn { p.conns[appID] = append(conns[:i], conns[i+1:]...) break } } if len(p.conns[appID]) == 0 { delete(p.conns, appID) } } } // 向指定 appID 的所有连接广播消息 func (p *WebSocketPool) Broadcast(appID string, message string) { p.RLock() defer p.RUnlock() if conns, ok := p.conns[appID]; ok { for _, conn := range conns { if err := conn.WriteMessage(websocket.TextMessage, []byte(message)); err != nil { log.Printf("[WebSocketPool] failed to send to appID=%s: %v", appID, err) } } } } // 清理掉线或不可用的连接(可定期调用) func (p *WebSocketPool) CleanInactive(appID string) { p.Lock() defer p.Unlock() if conns, ok := p.conns[appID]; ok { active := make([]*websocket.Conn, 0, len(conns)) for _, conn := range conns { if err := conn.WriteControl(websocket.PingMessage, []byte("ping"), time.Now().Add(1*time.Second)); err == nil { active = append(active, conn) } else { _ = conn.Close() } } if len(active) > 0 { p.conns[appID] = active } else { delete(p.conns, appID) } } }