Files
exec/ssh/ssh.go
2025-08-22 21:00:16 -03:00

125 lines
2.6 KiB
Go

package ssh
import (
"fmt"
"io"
"os"
"path"
"strings"
"golang.org/x/crypto/ssh"
"sirherobrine23.com.br/go-bds/exec"
)
var _ exec.Proc = (*Session)(nil)
type Session struct {
Client *ssh.Client
Rootfs string
SshExit *ssh.ExitError
Session *ssh.Session
}
func NewSession(client *ssh.Client) (*Session, error) {
session, err := client.NewSession()
if err != nil {
return nil, err
}
return &Session{Client: client, Session: session}, nil
}
func (session *Session) Close() error { return session.Session.Close() }
func (session *Session) Kill() error { return session.Signal(os.Kill) }
func (session *Session) Signal(s os.Signal) error {
return session.Session.Signal(ssh.Signal(s.String()))
}
func (session *Session) Wait() error { return session.Session.Wait() }
func (session *Session) ExitCode() (int, error) {
err := session.Session.Wait()
if err == nil {
return 0, nil
}
if exitErr, ok := err.(*ssh.ExitError); ok {
session.SshExit = exitErr
return exitErr.ExitStatus(), nil
}
return -1, err
}
func (session *Session) AttachStdin(r io.Reader) error {
if session.Session == nil {
return io.ErrUnexpectedEOF
}
session.Session.Stdin = r
return nil
}
func (session *Session) AttachStdout(w io.Writer) error {
if session.Session == nil {
return io.ErrUnexpectedEOF
}
session.Session.Stdout = w
return nil
}
func (session *Session) AttachStderr(w io.Writer) error {
if session.Session == nil {
return io.ErrUnexpectedEOF
}
session.Session.Stderr = w
return nil
}
func (session *Session) Start(command *exec.Exec) (err error) {
if session.Session == nil {
if session.Session, err = session.Client.NewSession(); err != nil {
return
}
}
for key, value := range command.Environment {
session.Session.Setenv(key, value)
}
var commandString string
if command.Cwd != "" {
commandString = "cd " + command.Cwd + ";"
}
if session.Rootfs != "" {
commandString = "cd " + session.Rootfs + ";"
if command.Cwd != "" {
commandString = "cd " + path.Join(session.Rootfs, command.Cwd) + ";"
}
}
if command.Stdin != nil {
session.Session.Stdin = command.Stdin
}
if command.Stdout != nil {
session.Session.Stdout = command.Stdout
session.Session.Stderr = command.Stdout
}
if command.Stderr != nil {
session.Session.Stderr = command.Stderr
}
commandStr, args := command.Arguments[0], command.Arguments[1:]
if err = session.Session.Start(fmt.Sprintf("%s%s %s; exit $?", commandString, commandStr, strings.Join(args, " "))); err != nil {
return
}
if command.Context != nil {
go func() {
<-command.Context.Done()
session.Session.Signal(ssh.SIGKILL)
}()
}
return nil
}