diff options
Diffstat (limited to 'cmd/dolmetschctld/web_socket.go')
-rw-r--r-- | cmd/dolmetschctld/web_socket.go | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/cmd/dolmetschctld/web_socket.go b/cmd/dolmetschctld/web_socket.go new file mode 100644 index 0000000..2e90b70 --- /dev/null +++ b/cmd/dolmetschctld/web_socket.go @@ -0,0 +1,118 @@ +// +// dolmetschctl +// +// +// Copyright (C) 2019 Christian Pointner <equinox@spreadspace.org> +// +// 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 <http://www.gnu.org/licenses/>. +// + +package main + +import ( + "encoding/json" + "io" + "io/ioutil" + "log" + "net/http" + + "github.com/gorilla/websocket" +) + +type webSocketRequest struct { + Command string `json:"command"` + Args []string `json:"arguments"` +} + +type webSocketResponseBase struct { + ResponseCode int `json:"response-code"` + Type string `json:"type"` +} + +type webSocketResponseError struct { + webSocketResponseBase + ErrorString string `json:"error"` +} + +type webSocketResponseState struct { + webSocketResponseBase + webState +} + +func sendWebSocketResponse(ws *websocket.Conn, rd interface{}) { + if err := ws.WriteJSON(rd); err != nil { + log.Println("Web(socket) client", ws.RemoteAddr(), "write error:", err) + } +} + +func sendWebSocketErrorResponse(ws *websocket.Conn, code int, errStr string) { + rd := &webSocketResponseError{} + rd.ResponseCode = code + rd.Type = "error" + rd.ErrorString = errStr + sendWebSocketResponse(ws, rd) +} + +func webSocketHandleCommand(ws *websocket.Conn, sm *StateMachine, req webSocketRequest) { + switch req.Command { + case "state": + var result webSocketResponseState + result.ResponseCode = http.StatusOK + result.Type = "state" + result.State, result.Ratio, result.Lang = sm.GetState() + sendWebSocketResponse(ws, result) + default: + sendWebSocketErrorResponse(ws, http.StatusBadRequest, "unkown command: '"+req.Command+"'") + } +} + +func webSocketHandler(sm *StateMachine, w http.ResponseWriter, r *http.Request) { + ws, err := websocket.Upgrade(w, r, nil, 64*1024, 64*1024) + if _, ok := err.(websocket.HandshakeError); ok { + http.Error(w, "Not a websocket handshake", 400) + return + } else if err != nil { + log.Println("Web(socket) client", ws.RemoteAddr(), "error:", err) + return + } + log.Println("Web(socket) client", ws.RemoteAddr(), "connected") + + for { + t, r, err := ws.NextReader() + if err != nil { + log.Println("Web(socket) Client", ws.RemoteAddr(), "disconnected:", err) + return + } + + switch t { + case websocket.TextMessage: + var req webSocketRequest + if err := json.NewDecoder(r).Decode(&req); err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + log.Println("Web(socket) client", ws.RemoteAddr(), "request error:", err) + sendWebSocketErrorResponse(ws, http.StatusBadRequest, err.Error()) + return + } + + webSocketHandleCommand(ws, sm, req) + case websocket.BinaryMessage: + sendWebSocketErrorResponse(ws, http.StatusBadRequest, "binary messages are not allowed") + io.Copy(ioutil.Discard, r) // consume all the data + } + } +} |