Example #1
0
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()
	}
}
Example #2
0
File: app.go Project: Jypy/gotty
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)
		}()
	}
}