// copy everything from the pty master to the websocket // using base64 encoding for now due to limitations in term.js func sendPtyOutputToConnection(conn *websocket.Conn, reader io.ReadCloser, finalizer *ReadWriteRoutingFinalizer) { defer closeConn(conn, finalizer) buf := make([]byte, 8192) var buffer bytes.Buffer for { n, err := reader.Read(buf) if err != nil { if !isNormalPtyError(err) { log.Printf("Failed to read from pty: %s", err) } return } i, err := normalizeBuffer(&buffer, buf, n) if err != nil { log.Printf("Cound't normalize byte buffer to UTF-8 sequence, due to an error: %s", err.Error()) return } if err = conn.WriteMessage(websocket.TextMessage, buffer.Bytes()); err != nil { log.Printf("Failed to send websocket message: %s, due to occurred error %s", string(buffer.Bytes()), err.Error()) return } buffer.Reset() if i < n { buffer.Write(buf[i:n]) } } }
// read from the web socket, copying to the pty master // messages are expected to be text and base64 encoded func sendConnectionInputToPty(conn *websocket.Conn, reader io.ReadCloser, f *os.File, finalizer *ReadWriteRoutingFinalizer) { defer closeReader(reader, f, finalizer) for { mt, payload, err := conn.ReadMessage() if err != nil { if !isNormalWsError(err) { log.Printf("conn.ReadMessage failed: %s\n", err) } return } switch mt { case websocket.BinaryMessage: log.Printf("Ignoring binary message: %q\n", payload) case websocket.TextMessage: var msg WebSocketMessage if err := json.Unmarshal(payload, &msg); err != nil { log.Printf("Invalid message %s\n", err) continue } if errMsg := handleMessage(msg, f); errMsg != nil { log.Printf(errMsg.Error()) return } default: log.Printf("Invalid websocket message type %d\n", mt) return } } }
// transfers data from channel to physical connection, // tries to transform data to json. func transferAsJson(conn *websocket.Conn, c chan interface{}) { for message := range c { err := conn.WriteJSON(message) if err != nil { log.Printf("Couldn't write message to the channel. Message: %T, %v", message, message) } } }
func closeConn(conn *websocket.Conn, finalizer *ReadWriteRoutingFinalizer) { defer finalizer.Unlock() finalizer.Lock() if !finalizer.writeDone { conn.Close() finalizer.writeDone = true fmt.Println("Terminal writer closed.") } }
// Reads the message from the websocket connection until error is received, // returns the channel which should be used for reading such messages. func readMessages(conn *websocket.Conn) chan *WsMessage { messagesChan := make(chan *WsMessage) go func() { for { _, bytes, err := conn.ReadMessage() messagesChan <- &WsMessage{err: err, bytes: bytes} if err != nil { close(messagesChan) break } } }() return messagesChan }