package rcon import ( "encoding/json" "fmt" "net/url" "time" "github.com/gorilla/websocket" ) // RconRequest is the JSON payload sent to Rust's WebRCON. type RconRequest struct { Identifier int `json:"Identifier"` Message string `json:"Message"` Name string `json:"Name"` } // RconResponse is the JSON payload received from Rust's WebRCON. type RconResponse struct { Identifier int `json:"Identifier"` Message string `json:"Message"` Type string `json:"Type"` } // SendCommand opens a WebSocket to the Rust server's RCON port, sends // a single command, reads the response, and closes the connection. func SendCommand(port int, password string, command string) (string, error) { u := url.URL{ Scheme: "ws", Host: fmt.Sprintf("127.0.0.1:%d", port), Path: fmt.Sprintf("/%s", password), } dialer := websocket.Dialer{ HandshakeTimeout: 5 * time.Second, } conn, _, err := dialer.Dial(u.String(), nil) if err != nil { return "", fmt.Errorf("rcon dial failed: %w", err) } defer conn.Close() // Set read deadline conn.SetReadDeadline(time.Now().Add(10 * time.Second)) req := RconRequest{ Identifier: 1, Message: command, Name: "Corrosion", } data, err := json.Marshal(req) if err != nil { return "", fmt.Errorf("rcon marshal failed: %w", err) } if err := conn.WriteMessage(websocket.TextMessage, data); err != nil { return "", fmt.Errorf("rcon write failed: %w", err) } // Read response — may get multiple messages (Generic, Warning, etc.) // We want the first response with our Identifier. for { _, message, err := conn.ReadMessage() if err != nil { return "", fmt.Errorf("rcon read failed: %w", err) } var resp RconResponse if err := json.Unmarshal(message, &resp); err != nil { continue // skip unparseable messages } if resp.Identifier == req.Identifier { return resp.Message, nil } } }