func (context *clientContext) processSend() { if err := context.sendInitialize(); err != nil { log.Printf(err.Error()) return } buf := make([]byte, 1024) utf8f := utf8reader.New(context.pty) for { size, err := utf8f.Read(buf) if err != nil { log.Printf("Command exited for: %s", context.request.RemoteAddr) return } writer, err := context.connection.NextWriter(websocket.TextMessage) if err != nil { return } writer.Write([]byte{Output}) writer.Write(buf[:size]) writer.Close() } }
func (app *App) generateHandler() func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { log.Printf("New client connected: %s", r.RemoteAddr) upgrader := websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, Subprotocols: []string{"gotty"}, } if r.Method != "GET" { http.Error(w, "Method not allowed", 405) return } conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Print("Failed to upgrade connection") return } cmd := exec.Command(app.Command[0], app.Command[1:]...) fio, err := pty.Start(cmd) if err != nil { log.Print("Failed to execute command") return } exit := make(chan bool, 2) go func() { defer func() { exit <- true }() buf := make([]byte, 1024) utf8f := utf8reader.New(fio) for { size, err := utf8f.Read(buf) if err != nil { log.Printf("command exited for: %s", r.RemoteAddr) return } writer, err := conn.NextWriter(websocket.TextMessage) if err != nil { return } writer.Write(buf[:size]) writer.Close() } }() go func() { defer func() { exit <- true }() for { _, data, err := conn.ReadMessage() if err != nil { return } switch data[0] { case '0': if !app.PermitWrite { break } _, err := fio.Write(data[1:]) if err != nil { return } case '1': var remoteCmd command err = json.Unmarshal(data[1:], &remoteCmd) if err != nil { log.Print("Malformed remote command") return } switch remoteCmd.Name { case "resize_terminal": rows := remoteCmd.Arguments["rows"] switch rows.(type) { case float64: default: log.Print("Malformed remote command") return } cols := remoteCmd.Arguments["columns"] switch cols.(type) { case float64: default: log.Print("Malformed remote command") return } window := struct { row uint16 col uint16 x uint16 y uint16 }{ uint16(rows.(float64)), uint16(cols.(float64)), 0, 0, } syscall.Syscall( syscall.SYS_IOCTL, fio.Fd(), syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(&window)), ) } default: log.Print("Unknown message type") return } } }() go func() { <-exit if app.PermitWrite { fio.Write([]byte{4}) } fio.Close() conn.Close() log.Printf("Connection closed: %s", r.RemoteAddr) }() } }