package commander import ( "bytes" "errors" "io" "os/exec" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto" "golang.org/x/sync/errgroup" ) type Commander struct { } func (*Commander) Execute(command *proto.Command) (*proto.FinishedCommand, error) { cmd := exec.Command(command.Command[0], command.Command[1:]...) var ( stdin io.WriteCloser err error ) if command.Stdin != nil { stdin, err = cmd.StdinPipe() if err != nil { return nil, err } } stdout, err1 := cmd.StdoutPipe() stderr, err2 := cmd.StderrPipe() if err := errors.Join(err1, err2); err != nil { return nil, err } if err := cmd.Start(); err != nil { return nil, err } if command.Stdin != nil { io.WriteString(stdin, *command.Stdin) if err := stdin.Close(); err != nil { return nil, err } } eg := new(errgroup.Group) stdoutbuf := new(bytes.Buffer) stderrbuf := new(bytes.Buffer) eg.Go(func() error { _, err := io.Copy(stdoutbuf, stdout) return err }) eg.Go(func() error { _, err := io.Copy(stderrbuf, stderr) return err }) if err := cmd.Wait(); err != nil { return nil, err } if err := eg.Wait(); err != nil { return nil, err } return &proto.FinishedCommand{ Id: command.Id, Status: int32(cmd.ProcessState.ExitCode()), Stdout: stdoutbuf.String(), Stderr: stderrbuf.String(), }, nil }