golang读取键盘功能按键输入
需求
最近业务上需要做一个终端工具,能够直接连到docker容器中进行交互。
技术选型
docker官方提供了python sdk、go sdk和remote api。
https://docs.docker.com/engine/api/sdk/
因为我们需要提供命令行工具,因此采用golang进行开发。
遇到的问题
通过sdk可以正常和容器连接,但是在使用方向键、退格等功能按键时总是出现乱码,导致不能正常使用,
通过万能的google终于解决了golang读取输入键盘按键不能正常使用的问题,特此记录。
解决方案
ctx := context.Background()// 自定义http docker client,可以使用官方推荐初始化方式// cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())client, err := cmdutil.NewDockerTcpClient(task.ExecNode, GetApiPort())waiter, err := client.ContainerAttach(ctx, task.Info.ID, types.ContainerAttachOptions{Stderr: true,Stdout: true,Stdin: true,Stream: true,})go io.Copy(os.Stdout, waiter.Reader)go io.Copy(os.Stderr, waiter.Reader)// "golang.org/x/crypto/ssh/terminal"//此处是关键,需要将标准输入转成标准终端输入fd := os.Stdin.Fd()if terminal.IsTerminal(int(fd)) {oldState, err := terminal.MakeRaw(int(fd))if err != nil {zap.S().Fatalln(err)}defer terminal.Restore(int(fd), oldState)}go io.Copy(waiter.Conn, os.Stdin)if err != nil {panic(err)}//此处将阻塞直到容器被释放statusCh, errCh := client.ContainerWait(ctx, task.Info.ID, container.WaitConditionNotRunning)select {case err := <-errCh:if err != nil {panic(err)}case <-statusCh:}return err
参考:
https://github.com/fsouza/go-dockerclient/issues/707
https://stackoverflow.com/questions/58732588/accept-user-input-os-stdin-to-container-using-golang-docker-sdk-interactive-co