package main import ( "encoding/json" "errors" "io/ioutil" "log" "net/http" "os/exec" "github.com/gorilla/websocket" "gopkg.in/yaml.v2" ) type baseMessage struct { MessageType string `json:"messageType"` } // message type "buttonPress" type buttonPressMessage struct { ButtonIndex int `json:"buttonIndex"` Long bool `json:"long"` } type buttonLayoutConfig struct { Buttons []buttonConfig `yaml:"buttons" json:"buttons"` } type buttonConfig struct { Title string `yaml:"title" json:"title"` Exec string `yaml:"exec"` Pos int `yaml:"pos" json:"pos"` } var upgrader = websocket.Upgrader{} var buttonLayout buttonLayoutConfig func upgradeWebsocket(w http.ResponseWriter, r *http.Request) { c, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Print("Failed to upgrade connection:", err) return } log.Print("New device connected") eventLoop(c) } func eventLoop(c *websocket.Conn) { defer c.Close() for { _, rawMessage, err := c.ReadMessage() if err != nil { log.Println("Failed to read message: ", err) break } var base baseMessage err = json.Unmarshal(rawMessage, &base) if err != nil { log.Printf("Failed to parse base message: %s", err.Error()) continue } response, err := handleMessage(base, rawMessage) if err != nil { log.Printf("Failed to handle message: %s", err.Error()) } else { if response != nil { c.WriteMessage(websocket.TextMessage, *response) } } } } // handleMessage forwards the message to the handler func handleMessage(base baseMessage, raw []byte) (*[]byte, error) { switch base.MessageType { case "buttonPress": var msg buttonPressMessage err := json.Unmarshal(raw, &msg) if err != nil { return nil, err } handleButtonPress(msg) case "layout": val, err := json.Marshal(buttonLayout) return &val, err default: return nil, errors.New("Unmachted message type: " + base.MessageType) } return nil, nil } // handleButtonPress handle the press of a button on the app func handleButtonPress(msg buttonPressMessage) { log.Printf("Button press. Index: %d", msg.ButtonIndex) // Find button in layout for i := 0; i < len(buttonLayout.Buttons); i++ { if buttonLayout.Buttons[i].Pos == msg.ButtonIndex { command := buttonLayout.Buttons[i].Exec go runCommand(command) break } } } func runCommand(command string) { cmd := exec.Command("sh", "-c", command) cmd.Run() } // loadLayout loads the layout file func loadLayout(filePath string) (*buttonLayoutConfig, error) { file, err := ioutil.ReadFile(filePath) if err != nil { return nil, err } var layout buttonLayoutConfig err = yaml.Unmarshal(file, &layout) if err != nil { return nil, err } return &layout, nil } func main() { loadedLayout, err := loadLayout("exampleLayout.yaml") if err != nil { log.Fatalf("Failed to load layout: %s", err.Error()) } buttonLayout = *loadedLayout http.HandleFunc("/ws", upgradeWebsocket) log.Fatal(http.ListenAndServe(":8069", nil)) }