package server import ( "encoding/json" "sync" "github.com/gorilla/websocket" "github.com/labstack/echo/v4" ) var upgrader = websocket.Upgrader{} type WebsocketHandler interface { Handle(message map[string]any, senderId string, sockets map[string]*websocket.Conn) } type WebsocketServer struct { router *echo.Echo sockets map[string]*websocket.Conn handlers []WebsocketHandler socketsMutex *sync.Mutex } func (s *WebsocketServer) Initialize(authenticator *Authenticator) { s.socketsMutex = &sync.Mutex{} s.sockets = make(map[string]*websocket.Conn) s.router.Use(authenticator.Authenticate("/ws", []string{})) s.router.GET("/ws", s.handle) } func (s *WebsocketServer) handle(context echo.Context) error { authContext := context.(AuthContext) senderId := getAuthenticatedId(authContext) ws, err := upgrader.Upgrade(context.Response(), context.Request(), nil) s.socketsMutex.Lock() s.sockets[senderId] = ws s.socketsMutex.Unlock() if err != nil { return err } defer func() { ws.Close() s.socketsMutex.Lock() delete(s.sockets, senderId) s.socketsMutex.Unlock() }() for { messageType, messageBytes, err := ws.ReadMessage() if err != nil { return err } if messageType == websocket.TextMessage { var messageObject map[string]any json.Unmarshal(messageBytes, &messageObject) for _, handler := range s.handlers { handler.Handle(messageObject, senderId, s.sockets) } } } } func getAuthenticatedId(authContext AuthContext) string { if authContext.User != nil { return authContext.User.ID } if authContext.Integration != nil { return authContext.Integration.ID } return "" } func (s *WebsocketServer) AddHandler(handler WebsocketHandler) { s.handlers = append(s.handlers, handler) } func (s *WebsocketServer) SetRouter(router *echo.Echo) { s.router = router }