package routes import ( "log" "github.com/aziis98/lupus-lite/events" "github.com/aziis98/lupus-lite/util" "github.com/gofiber/fiber/v2" "github.com/gofiber/websocket/v2" ) type clientMessage struct { Type string `json:"type"` Event string `json:"event"` } type serverMessage struct { Event string `json:"event"` Data any `json:"data"` } // BindWebsocketToEventBus creates a WebSocket handler that can subscribe the socket to some events generated on the server, for example a message from the client like { type: "subscribe", event: "foo" } binds the connection to the event "foo" and forwards events and the associated data to client as JSON. func BindWebsocketToEventBus(eb *events.EventBus) fiber.Handler { return websocket.New(func(c *websocket.Conn) { clientId := util.GenerateRandomString(10) log.Printf("[%v] Connection started", clientId) defer log.Printf("[%v] Connection closed", clientId) listeners := []*events.Listener{} defer func() { for _, l := range listeners { eb.Unsubscribe(l) } }() done := make(chan error) for { var msg clientMessage if err := c.ReadJSON(&msg); err != nil { log.Printf(`[%v] Read error: %v`, clientId, err) return } log.Printf("[%v] Received: %v", clientId, msg) switch msg.Type { case "subscribe": newListener := eb.Subscribe( msg.Event, func(e interface{}) { log.Printf(`[%v] Sent message`, clientId) if err := c.WriteJSON(serverMessage{ Event: msg.Event, Data: e, }); err != nil { log.Printf(`[%v] Write error: %v`, clientId, err) done <- err } }, ) listeners = append(listeners, newListener) default: log.Printf("[%v] Unknown message type %q", clientId, msg.Type) return } select { case err := <-done: if err != nil { return } default: } } }) }