80 lines
1.8 KiB
Go
80 lines
1.8 KiB
Go
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
|
|
}
|