package commander import ( "bytes" "errors" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/proto" "golang.org/x/sync/errgroup" "io" "os/exec" ) type CommandExecutor struct{} func (*CommandExecutor) Execute(command *proto.Command) (fc *proto.FinishedCommand, err error) { fc = new(proto.FinishedCommand) fc.Id = command.Id cmd := exec.Command(command.Command[0], command.Command[1:]...) var stdin io.WriteCloser 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 waitErr := cmd.Wait(); waitErr != nil { var exitErr *exec.ExitError if !errors.As(waitErr, &exitErr) { return nil, waitErr } fc.Status = int32(exitErr.ExitCode()) } else { fc.Status = int32(cmd.ProcessState.ExitCode()) } if err := eg.Wait(); err != nil { return nil, err } fc.Status = int32(cmd.ProcessState.ExitCode()) fc.Stdout = stdoutbuf.String() fc.Stderr = stderrbuf.String() return }