92 lines
1.8 KiB
Go
92 lines
1.8 KiB
Go
package engine
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"socksrevivepc/internal/oscmd"
|
|
)
|
|
|
|
type ManagedProcess struct {
|
|
cmd *exec.Cmd
|
|
name string
|
|
logger *Logger
|
|
mu sync.Mutex
|
|
done chan error
|
|
}
|
|
|
|
func StartProcess(ctx context.Context, root, name, exe string, args []string, logger *Logger) (*ManagedProcess, error) {
|
|
if strings.TrimSpace(exe) == "" {
|
|
return nil, errors.New(name + " executable path is empty")
|
|
}
|
|
if !filepath.IsAbs(exe) {
|
|
exe = filepath.Join(root, exe)
|
|
}
|
|
cmd := oscmd.CommandContext(ctx, exe, args...)
|
|
cmd.Dir = root
|
|
stdout, _ := cmd.StdoutPipe()
|
|
stderr, _ := cmd.StderrPipe()
|
|
p := &ManagedProcess{cmd: cmd, name: name, logger: logger, done: make(chan error, 1)}
|
|
if err := cmd.Start(); err != nil {
|
|
return nil, err
|
|
}
|
|
logger.Add("info", "%s started: %s %s", name, exe, strings.Join(args, " "))
|
|
go p.pipe(stdout, "info")
|
|
go p.pipe(stderr, "warn")
|
|
go func() {
|
|
err := cmd.Wait()
|
|
p.done <- err
|
|
if err != nil {
|
|
logger.Add("warn", "%s stopped: %v", name, err)
|
|
} else {
|
|
logger.Add("info", "%s stopped", name)
|
|
}
|
|
}()
|
|
return p, nil
|
|
}
|
|
|
|
func (p *ManagedProcess) Exited() (bool, error) {
|
|
if p == nil || p.done == nil {
|
|
return true, nil
|
|
}
|
|
select {
|
|
case err := <-p.done:
|
|
return true, err
|
|
default:
|
|
return false, nil
|
|
}
|
|
}
|
|
|
|
func (p *ManagedProcess) pipe(r io.Reader, level string) {
|
|
s := bufio.NewScanner(r)
|
|
for s.Scan() {
|
|
line := strings.TrimSpace(s.Text())
|
|
if line != "" {
|
|
p.logger.Add(level, "%s: %s", p.name, line)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p *ManagedProcess) Stop() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p == nil || p.cmd == nil || p.cmd.Process == nil {
|
|
return
|
|
}
|
|
if runtime.GOOS == "windows" {
|
|
_ = p.cmd.Process.Kill()
|
|
} else {
|
|
_ = p.cmd.Process.Signal(ioSignalInterrupt())
|
|
time.Sleep(500 * time.Millisecond)
|
|
_ = p.cmd.Process.Kill()
|
|
}
|
|
}
|