You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
starainrt/starshell.go

162 lines
3.3 KiB
Go

package starainrt
import (
"context"
"errors"
"io"
"os"
"os/exec"
"syscall"
"time"
)
type StarShell struct {
outfile *io.ReadCloser
infile *io.WriteCloser
errfile *io.ReadCloser
cmd *exec.Cmd
running bool
stopSign context.Context
stopFunc context.CancelFunc
stdout []byte
errout []byte
runerr error
exitcode int
}
func NewStarShell(command string, args ...string) (*StarShell, error) {
shell := new(StarShell)
shell.stopSign, shell.stopFunc = context.WithCancel(context.Background())
cmd := exec.CommandContext(shell.stopSign, command, args...)
shell.cmd = cmd
infile, err := shell.cmd.StdinPipe()
if err != nil {
return shell, err
}
shell.infile = &infile
errfile, err := shell.cmd.StderrPipe()
if err != nil {
return shell, err
}
shell.errfile = &errfile
outfile, err := shell.cmd.StdoutPipe()
if err != nil {
return shell, err
}
shell.outfile = &outfile
shell.runerr = nil
shell.exitcode = -999
return shell, nil
}
func (starcli *StarShell) Start() error {
if err := starcli.cmd.Start(); err != nil {
return err
}
starcli.running = true
go func() {
err := starcli.cmd.Wait()
if err != nil {
starcli.runerr = err
}
starcli.exitcode = starcli.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
starcli.running = false
}()
go starcli.queryResult()
go starcli.queryErrResult()
return nil
}
func (starcli *StarShell) queryResult() error {
for starcli.running {
out := make([]byte, 65535)
n, err := (*starcli.outfile).Read(out)
if n != 0 {
for i := 0; i < n; i++ {
starcli.stdout = append(starcli.stdout, out[i])
}
}
if err != nil {
if err == io.EOF {
break
} else {
starcli.runerr = err
return err
}
}
time.Sleep(time.Microsecond * 100)
}
return nil
}
func (starcli *StarShell) queryErrResult() error {
for starcli.running {
out := make([]byte, 65535)
n, err := (*starcli.errfile).Read(out)
if n != 0 {
for i := 0; i < n; i++ {
starcli.errout = append(starcli.errout, out[i])
}
}
if err != nil {
if err == io.EOF {
break
} else {
starcli.runerr = err
return err
}
}
time.Sleep(time.Microsecond * 100)
}
return nil
}
func (starcli *StarShell) GetResult() (string, error) {
np := len(starcli.stdout)
res1 := string(starcli.stdout[0:np])
starcli.stdout = starcli.stdout[np:]
np = len(starcli.errout)
res2 := string(starcli.errout[0:np])
starcli.errout = starcli.errout[np:]
if len(res2) == 0 && starcli.runerr != nil {
res2 = starcli.runerr.Error()
}
if len(res2) == 0 {
return res1, nil
}
return res1, errors.New(res2)
}
func (starcli *StarShell) Exec(cmd string, wait int) (string, error) {
(*starcli.infile).Write([]byte(cmd + "\n"))
time.Sleep(time.Millisecond * time.Duration(wait))
return starcli.GetResult()
}
func (starcli *StarShell) WriteCmd(cmdstr string) {
(*starcli.infile).Write([]byte(cmdstr + "\n"))
return
}
func (starcli *StarShell) ExitCode() int {
return starcli.exitcode
}
func (starcli *StarShell) Kill() {
starcli.stopFunc()
starcli.running = false
}
func (starcli *StarShell) IsRunning() bool {
return starcli.running
}
func (starcli *StarShell) GetPid() int {
return starcli.cmd.Process.Pid
}
func (starcli *StarShell) Signal(sig os.Signal) error {
return starcli.cmd.Process.Signal(sig)
}