sampler-fork/data/item.go

185 lines
3.4 KiB
Go
Raw Normal View History

2019-01-31 23:40:05 +00:00
package data
import (
2019-04-07 15:09:24 +00:00
"bufio"
"errors"
2019-03-14 03:01:44 +00:00
ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/config"
2019-04-07 15:09:24 +00:00
"io"
2019-03-21 02:23:08 +00:00
"os"
2019-01-31 23:40:05 +00:00
"os/exec"
"strings"
2019-04-07 15:09:24 +00:00
"time"
2019-01-31 23:40:05 +00:00
)
type Item struct {
2019-04-07 15:09:24 +00:00
Label string
SampleScript string
InitScript *string
TransformScript *string
Color *ui.Color
2019-04-07 15:17:28 +00:00
RateMs int
2019-04-07 15:09:24 +00:00
InteractiveShell *InteractiveShell
}
2019-04-07 15:09:24 +00:00
type InteractiveShell struct {
StdoutCh chan string
StderrCh chan string
Stdin io.WriteCloser
Cmd *exec.Cmd
}
2019-04-07 15:17:28 +00:00
func NewItems(cfgs []config.Item, rateMs int) []*Item {
2019-04-07 15:09:24 +00:00
items := make([]*Item, 0)
for _, i := range cfgs {
2019-04-07 15:09:24 +00:00
item := &Item{
Label: *i.Label,
SampleScript: *i.SampleScript,
InitScript: i.InitScript,
TransformScript: i.TransformScript,
2019-04-07 15:09:24 +00:00
Color: i.Color,
2019-04-07 15:17:28 +00:00
RateMs: rateMs,
2019-04-07 15:09:24 +00:00
}
items = append(items, item)
}
return items
2019-01-31 23:40:05 +00:00
}
2019-04-07 15:09:24 +00:00
func (i *Item) nextValue(variables []string) (string, error) {
2019-01-31 23:40:05 +00:00
2019-04-07 15:09:24 +00:00
if i.InitScript != nil && i.InteractiveShell == nil {
err := i.initInteractiveShell(variables)
if err != nil {
return "", err
}
}
2019-03-21 02:23:08 +00:00
2019-04-07 15:09:24 +00:00
if i.InitScript != nil {
return i.executeInteractiveShellCmd(variables)
} else {
return i.executeCmd(variables)
2019-03-21 02:23:08 +00:00
}
2019-04-07 15:09:24 +00:00
}
func (i *Item) executeCmd(variables []string) (string, error) {
cmd := exec.Command("sh", "-c", i.SampleScript)
enrichEnvVariables(cmd, variables)
2019-03-21 02:23:08 +00:00
output, err := cmd.Output()
2019-01-31 23:40:05 +00:00
if err != nil {
return "", err
}
return strings.TrimSpace(string(output)), nil
}
2019-04-07 15:09:24 +00:00
func (i *Item) initInteractiveShell(variables []string) error {
cmd := exec.Command("sh", "-c", *i.InitScript)
enrichEnvVariables(cmd, 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()
}
}()
i.InteractiveShell = &InteractiveShell{
StdoutCh: stdoutCh,
StderrCh: stderrCh,
Stdin: stdin,
Cmd: cmd,
}
err = cmd.Start()
if err != nil {
return err
}
return nil
}
func (i *Item) executeInteractiveShellCmd(variables []string) (string, error) {
_, err := io.WriteString(i.InteractiveShell.Stdin, i.SampleScript+"\n")
if err != nil {
return "", err
}
timeout := make(chan bool, 1)
go func() {
time.Sleep(time.Duration(i.RateMs / 2))
2019-04-07 15:09:24 +00:00
timeout <- true
}()
var resultText strings.Builder
var errorText strings.Builder
for {
select {
case stdout := <-i.InteractiveShell.StdoutCh:
if len(stdout) > 0 {
resultText.WriteString(stdout)
resultText.WriteString("\n")
}
case stderr := <-i.InteractiveShell.StderrCh:
if len(stderr) > 0 {
errorText.WriteString(stderr)
errorText.WriteString("\n")
}
case <-timeout:
if errorText.Len() > 0 {
return "", errors.New(errorText.String())
} else {
return i.transformInteractiveShellCmd(resultText.String())
}
}
}
}
func (i *Item) transformInteractiveShellCmd(sample string) (string, error) {
result := sample
if i.TransformScript != nil {
result = result // TODO
}
2019-04-07 18:26:20 +00:00
return result, nil
2019-04-07 15:09:24 +00:00
}
func enrichEnvVariables(cmd *exec.Cmd, variables []string) {
cmd.Env = os.Environ()
for _, variable := range variables {
cmd.Env = append(cmd.Env, variable)
}
}