// Websocket debug tool // // Usage: ./websocket-linux-amd64 ws:///rpc // // This tools is intended to support development of the Websocket-based // application programming interface (API) of the Shelly Internet of Things // (IoT) devices. package main import ( "encoding/json" "log" "net/url" "os" "os/signal" "strings" "syscall" "time" "github.com/gorilla/websocket" ) func main() { log.SetFlags(0) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) var u url.URL = getURL() log.Printf("connecting to %s", u.String()) c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Fatal(err) } defer c.Close() go rx(c) getConfig(c) coverClose(c) time.Sleep(1 * time.Second) coverOpen(c) Await(syscall.SIGTERM, syscall.SIGINT) } func getURL() url.URL { if len(os.Args) != 2 { log.Fatalf("Exactly one argument expected but got %d.", len(os.Args) - 1) } maybeURL, err := url.Parse(os.Args[1]) if err != nil { log.Fatalf("Cannot parse given URL: %s", os.Args[1]) } return *maybeURL } func Await(signals ...os.Signal) { listener := make(chan os.Signal, 1) signal.Notify(listener, signals...) defer signal.Stop(listener) sig := <-listener log.Printf("Received OS signal '%v'\n", sig) } func getConfig(c *websocket.Conn) { tx(c, ` { "jsonrpc":"2.0", "id": 1, "src":"user_1", "method":"Sys.GetConfig", "params": { "id":2 } } `) } func coverClose(c *websocket.Conn) { tx(c, ` { "jsonrpc":"2.0", "id": 1, "src":"user_1", "method":"Cover.Close", "params": { "id":0 } } `) } func coverOpen(c *websocket.Conn) { tx(c, ` { "jsonrpc":"2.0", "id": 1, "src":"user_1", "method":"Cover.Open", "params": { "id":0 } } `) } func rx(c *websocket.Conn) { for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Println("") log.Println(quote(prettify(string(message)), "< ")) } } func tx(c *websocket.Conn, d string) { log.Println(quote(prettify(d), "> ")) err := c.WriteMessage(websocket.TextMessage, []byte(d)) if err != nil { log.Fatal(err) } } func prettify(input string) string { var parsed any err := json.Unmarshal([]byte(input), &parsed) if err != nil { log.Fatal(err) } pretty, err := json.MarshalIndent(parsed, "", " ") if err != nil { log.Fatal(err) } return string(pretty) } func quote(input string, quotation string) string { lines := strings.Split(input, "\n") for i, line := range lines { lines[i] = quotation + line } return strings.Join(lines, "\n") }