使用不带命令的 PTY

在 creack/pty 中为这个问题打开了一个问题,但实际上我认为它可能属于这里,因为它可能更多地与我对库的使用有关,而不是库的任何问题。

我正在使用一个websocket api,它发送 stdin 消息并从命令接收 stdout 和 stderr 输出以及退出代码。

比如这个API用在web UI中,发送和接收的消息串如下

http://img2.mukewang.com/63a95d720001aea411130656.jpg

此 Web UI 使用xterm.js提供类似终端的输入 ui,并将响应(包括 ansi 转义序列)解释为终端输出。

我正在构建一个终端应用程序,它希望利用相同的 API,因此类似于“终端中的终端”,其中将标准输入发送到 API,并在我的应用程序中呈现接收到的响应。

我想使用 creack/pty 作为响应解释器,处理 ansi 转义序列等,并持有终端会话的视图,我可以将其读入字符串并呈现到我的应用程序的屏幕上。

所以流程大致是这样的:

  • stdin 发送到 websocket 连接

  • 收到回复

  • 写对 pty 的回应

  • 读取整个 pty 到字符串

  • 将字符串渲染到屏幕

  • 重复

如果我以这种方式使用 creack/pty,我实际上没有启动命令 - 它只是一个很好的框,可以为我解释 ansi 转义序列并允许我检索终端的当前“字符串视图”。

这是我尝试获取无命令 pty、写入并从中读取的尝试:

package main


import (

    "bytes"

    "fmt"

    "github.com/creack/pty"

    "io"

    "os"

)


func getPtyWithoutCommand() (*os.File, error) {

    // this function just pty.StartWithAttrs with command-specific stuff commented out

    pty, tty, err := pty.Open()

    if err != nil {

        return nil, err

    }

    defer func() { _ = tty.Close() }() // Best effort.


    // if sz != nil {

    //  if err := Setsize(pty, sz); err != nil {

    //      _ = pty.Close() // Best effort.

    //      return nil, err

    //  }

    // }

    // if c.Stdout == nil {

    //  c.Stdout = tty

    // }

    // if c.Stderr == nil {

    //  c.Stderr = tty

    // }

    // if c.Stdin == nil {

    //  c.Stdin = tty

    // }

    //

    // c.SysProcAttr = attrs

    //

    // if err := c.Start(); err != nil {

    //  _ = pty.Close() // Best effort.

    //  return nil, err

    // }

    return pty, err

}


func main() {

    myPty, err := getPtyWithoutCommand()

    if err != nil {

        panic(err)

    }


    _, err = myPty.Write([]byte("test\n"))

    if err != nil {

        panic(err)

    }

    _, err = myPty.Write([]byte{4}) // EOT

    if err != nil {

        panic(err)

    }


    buf := new(bytes.Buffer)

    _, err = io.Copy(buf, myPty)

    if err != nil {

        panic(err)

    }

    fmt.Println(buf.String())

}

我收到以下错误


❯ go run test.go

panic: write /dev/ptmx: input/output error


goroutine 1 [running]:

main.main()

        test.go:52 +0x19c

exit status 2

我正在努力做的事情是理智的吗?有没有更好的方法来实现我的目标?


小唯快跑啊
浏览 85回答 1
1回答

隔江千里

我正在处理一个类似的问题,而 creack 的 pty 可能对于你想要的东西来说有点太抽象了。我刚刚使用了 golang 标准 xterm 终端仿真器https://pkg.go.dev/golang.org/x/term和一个管道。这是我的意思的一个例子的部分片段。您的 stdin 流被送入stdin_writer并且您的 stdout 被写入writer,不要忘记Flush()!stdin_reader, stdin_writer := io.Pipe()reader := bufio.NewReader(stdin_reader)stdout_writer := bytes.Buffer{}writer := bufio.NewWriter(&stdout_writer)rw := bufio.NewReadWriter(reader, writer)t := term.NewTerminal(rw, prompt)// constantly be reading linesgo func() {    for {        line, err := t.ReadLine()        if err == io.EOF {            log.Printf("got EOF")        }        if err != nil {            log.Printf("got err")        }        if line == "" {            continue        }        log.Printf("LINE: %s", line)    }}()
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go