sampler-fork/data/int_shell.go

111 lines
1.9 KiB
Go

package data
import (
"bufio"
"errors"
"fmt"
"io"
"os/exec"
"strings"
"time"
)
type BasicInteractiveShell struct {
item *Item
variables []string
stdoutCh chan string
stderrCh chan string
stdin io.WriteCloser
cmd *exec.Cmd
errCount int
}
func (s *BasicInteractiveShell) init() error {
cmd := exec.Command("sh", "-c", *s.item.initScript)
enrichEnvVariables(cmd, s.variables)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return err
}
stdin, err := cmd.StdinPipe()
if err != nil {
return err
}
stdoutScanner := bufio.NewScanner(stdout)
stderrScanner := bufio.NewScanner(stderr)
stdoutCh := make(chan string)
stderrCh := make(chan string)
go func() {
for stdoutScanner.Scan() {
stdoutCh <- stdoutScanner.Text()
stderrCh <- stderrScanner.Text()
}
}()
s.stdoutCh = stdoutCh
s.stderrCh = stderrCh
s.stdin = stdin
s.cmd = cmd
err = cmd.Start()
if err != nil {
return err
}
return nil
}
func (s *BasicInteractiveShell) execute() (string, error) {
_, err := io.WriteString(s.stdin, s.item.sampleScript+"\n")
if err != nil {
s.errCount++
if s.errCount > errorThreshold {
s.item.ptyShell = nil // restart session
}
return "", errors.New(fmt.Sprintf("Failed to execute command: %s", err))
}
timeout := make(chan bool, 1)
go func() {
time.Sleep(time.Duration(s.item.rateMs / 2))
timeout <- true
}()
var resultText strings.Builder
var errorText strings.Builder
for {
select {
case stdout := <-s.stdoutCh:
if len(stdout) > 0 {
resultText.WriteString(stdout)
resultText.WriteString("\n")
}
case stderr := <-s.stderrCh:
if len(stderr) > 0 {
errorText.WriteString(stderr)
errorText.WriteString("\n")
}
case <-timeout:
if errorText.Len() > 0 {
return "", errors.New(errorText.String())
} else {
return resultText.String(), nil
}
}
}
}