// // dolmetschctl // // // Copyright (C) 2019 Christian Pointner // // This file is part of dolmetschctl. // // dolmetschctl is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // dolmetschctl is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with dolmetschctl. If not, see . // package main import ( "encoding/json" "fmt" "io" "io/ioutil" "log" "os" "time" "github.com/gorilla/websocket" "spreadspace.org/dolmetschctl/pkg/controller" "spreadspace.org/dolmetschctl/pkg/types" ) const ( blinkTime = 20 lang1 = "en" lang2 = "de" ) func wsReader(ws *websocket.Conn, ch chan<- types.WebSocketResponseFull) { defer close(ch) for { t, r, err := ws.NextReader() if err != nil { log.Println("websocket disconnected:", err) return } switch t { case websocket.TextMessage: var msg types.WebSocketResponseFull dec := json.NewDecoder(r) dec.DisallowUnknownFields() if err := dec.Decode(&msg); err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } log.Println("webclient response parse error:", err) return } ch <- msg case websocket.BinaryMessage: io.Copy(ioutil.Discard, r) // consume all the data } } } func handleControllerEvent(ctrl *controller.Controller, ws *websocket.Conn, ev controller.Event) error { if ev.Type != controller.ButtonPressed { return nil } lang := "" switch ev.Button { case 0: lang = "en" case 1: lang = "de" default: lang = "none" } return ws.WriteJSON(types.WebSocketRequest{Command: "language", Args: []string{lang}}) } func ledOnOrBlink(ctrl *controller.Controller, num uint8, state types.State) { if state == types.StateSettled { ctrl.LedOn(num) } else { ctrl.LedBlink(num, blinkTime) } } func handleWebSocketMessage(ctrl *controller.Controller, ws *websocket.Conn, msg types.WebSocketResponseFull) error { if msg.Type == "state" { switch msg.Lang { case lang1: ledOnOrBlink(ctrl, 0, msg.State) ctrl.LedOff(1) ctrl.LedOff(2) ctrl.LedOff(3) case lang2: ctrl.LedOff(0) ledOnOrBlink(ctrl, 1, msg.State) ctrl.LedOff(2) ctrl.LedOff(3) default: ctrl.LedOff(0) ctrl.LedOff(1) ledOnOrBlink(ctrl, 2, msg.State) ledOnOrBlink(ctrl, 3, msg.State) } } return nil } func run(ctrl *controller.Controller, ws *websocket.Conn) (error, bool) { ctrlCh := make(chan controller.Event, 100) unsub := ctrl.Subscribe(ctrlCh) defer close(unsub) wsCh := make(chan types.WebSocketResponseFull) go wsReader(ws, wsCh) if err := ws.WriteJSON(types.WebSocketRequest{Command: "subscribe"}); err != nil { return err, true } log.Printf("subscribed to state changes!") for { select { case ev, ok := <-ctrlCh: if !ok { return fmt.Errorf("controller channel was closed."), false } if err := handleControllerEvent(ctrl, ws, ev); err != nil { return err, true } case msg, ok := <-wsCh: if !ok { return fmt.Errorf("websocket channel was closed."), true } if err := handleWebSocketMessage(ctrl, ws, msg); err != nil { return err, true } } } } func main() { log.Println("hello world.") c, err := controller.NewController(controller.Config{Dev: "dolmetsch controller"}) if err != nil { log.Printf("Error opening the controller: %v", err) os.Exit(1) } defer c.Shutdown() if err = c.Init(); err != nil { log.Printf("Error initializeing the controller: %v", err) os.Exit(1) } log.Printf("controller successfully initialized!") for { ws, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8234/api/v1/socket", nil) if err != nil { log.Printf("Error connecting to daemon: %v", err) } else { log.Printf("successfully conncted!") err, restart := run(c, ws) if restart { log.Printf("run() returned temporary error: %v", err) } else { log.Printf("run() returned fatal error: %v", err) break } } log.Printf("will retry in one second...") time.Sleep(time.Second) } log.Printf("exiting.") }