converge/pkg/agent/terminal/pty_windows.go
2024-09-08 11:16:49 +02:00

87 lines
1.7 KiB
Go

package terminal
import (
"fmt"
"github.com/ActiveState/termtest/conpty"
"github.com/gliderlabs/ssh"
"io"
"log"
"os"
"syscall"
)
var PtySpawner = Spawner(func(sshSession ssh.Session, env []string, name string, args ...string) (Process, error) {
_, winCh, isPty := sshSession.Pty()
if !isPty {
return nil, fmt.Errorf("ssh session is not a pty")
}
cpty, err := conpty.New(80, 25)
if err != nil {
return nil, err
}
pid, _, err := cpty.Spawn(
name,
args,
&syscall.ProcAttr{
Env: env,
},
)
if err != nil {
cpty.Close()
return nil, err
}
log.Printf("New process with pid %d spawned\n", pid)
process, err := os.FindProcess(pid)
if err != nil {
cpty.Close()
return nil, fmt.Errorf("Failed to find process: %v", err)
}
go func() {
for win := range winCh {
err = cpty.Resize(uint16(win.Width), uint16(win.Height))
if err != nil {
log.Printf("Failed to resize terminal to %d x %d", win.Width, win.Height)
}
}
}()
return ptyProcess{
cpty: cpty,
process: process,
}, nil
})
type ptyProcess struct {
cpty *conpty.ConPty
process *os.Process
}
func (proc ptyProcess) Read(p []byte) (n int, err error) {
return proc.cpty.OutPipe().Read(p)
}
func (proc ptyProcess) Write(p []byte) (n int, err error) {
uintn, err := proc.cpty.Write(p)
return int(uintn), err
}
func (p ptyProcess) Pipe() io.ReadWriter {
return p
}
func (p ptyProcess) Kill() error {
return p.process.Kill()
}
func (p ptyProcess) Wait() error {
defer p.cpty.Close()
ps, err := p.process.Wait()
if err != nil {
return fmt.Errorf("Error waiting for process: %v", err)
}
if ps.ExitCode() != 0 {
return fmt.Errorf("exit code was: %d\n", ps.ExitCode())
}
return nil
}