package ws import ( "encoding/json" "net/http" "time" "github.com/gorilla/websocket" ) func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request) { conn, err := wsg.validateAndUpgradeConnection(w, r) if err != nil { return } if wsg.bodySizeBytes > 0 { conn.SetReadLimit(wsg.bodySizeBytes) } else { conn.SetReadLimit(1 << 20) // sensible default 1MiB } _ = conn.SetReadDeadline(time.Now().Add(60 * time.Second)) conn.SetPongHandler(func(appData string) error { _ = conn.SetReadDeadline(time.Now().Add(60 * time.Second)) return nil }) typ, data, err := conn.ReadMessage() if err != nil { wsg.sendWebsocketError(conn, "Internal Server Error", 500, true) wsg.logger.Error("Failed to read handshake.", "remote", conn.RemoteAddr().String(), "err", err) return } if typ != websocket.TextMessage && typ != websocket.BinaryMessage { wsg.sendWebsocketError(conn, "Initial message must be a handshake.", 400, true) wsg.logger.Warn("Invalid handshake message type.", "remote", conn.RemoteAddr().String()) return } var handshake Handshake if err := json.Unmarshal(data, &handshake); err != nil { wsg.sendWebsocketError(conn, "Malformed handshake.", 400, true) wsg.logger.Warn("Malformed handshake.", "remote", conn.RemoteAddr().String(), "err", err) return } switch handshake.Type { case "mod": var mhs ModHandshake if err := json.Unmarshal(handshake.Data, &mhs); err != nil { wsg.sendWebsocketError(conn, "Malformed mod handshake.", 400, true) wsg.logger.Warn("Malformed mod handshake.", "remote", conn.RemoteAddr().String(), "err", err) return } if mhs.ServerID == "" || mhs.ChannelID == "" { wsg.sendWebsocketError(conn, "Malformed mod handshake.", 400, true) return } if !wsg.registerConn(conn, "mod", mhs.ChannelID, mhs.ServerID) { wsg.sendWebsocketError(conn, "Failed to register mod.", 500, true) return } _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "mod"}) wsg.registry.FlushChannelWithSender(mhs.ChannelID, wsg.flush) wsg.logger.Info("Mod connected via Websocket.", "remote", conn.RemoteAddr().String()) go wsg.read(conn, "mod", mhs.ChannelID) case "bot": var bhs BotHandshake if err := json.Unmarshal(handshake.Data, &bhs); err != nil { wsg.sendWebsocketError(conn, "Malformed bot handshake.", 400, true) return } if bhs.ChannelId == "" { wsg.sendWebsocketError(conn, "Malformed bot handshake.", 400, true) return } if !wsg.registerConn(conn, "bot", bhs.ChannelId, "") { wsg.sendWebsocketError(conn, "Bot already connected.", 409, true) return } _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "bot"}) wsg.registry.FlushAllToBotWithSender(wsg.flush) wsg.logger.Info("Bot connected via Websocket.", "remote", conn.RemoteAddr().String()) go wsg.read(conn, "bot", bhs.ChannelId) default: wsg.sendWebsocketError(conn, "Unknown handshake.", 400, true) wsg.logger.Warn("Unknown connection type.", "remote", conn.RemoteAddr().String(), "type", handshake.Type) return } } func (wsg *WebsocketGateway) handleHealth(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) _ = json.NewEncoder(w).Encode(map[string]interface{}{"status": "healthy"}) }