diff --git a/util/command_darwin.go b/util/command/command_darwin.go similarity index 56% rename from util/command_darwin.go rename to util/command/command_darwin.go index 0e22a3c..1a663d2 100644 --- a/util/command_darwin.go +++ b/util/command/command_darwin.go @@ -1,9 +1,11 @@ -package util +package command import ( "bytes" + "errors" "fmt" "os/exec" + "strings" "syscall" "time" ) @@ -13,6 +15,7 @@ func ExecCommand(name string, args []string, timeout ...time.Duration) (out stri var ( stderr, stdout bytes.Buffer expire = 30 * time.Minute + errs []string ) if len(timeout) > 0 { @@ -23,25 +26,28 @@ func ExecCommand(name string, args []string, timeout ...time.Duration) (out stri cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Stdout = &stdout cmd.Stderr = &stderr + err = cmd.Start() + if err != nil { + err = fmt.Errorf("%s\n%s", err.Error(), stderr.String()) + return + } - isDone := make(chan bool, 1) - go func() { - err = cmd.Run() - if err != nil { - err = fmt.Errorf("%s\n%s", err.Error(), stderr.String()) - } - isDone <- true - }() - - select { - case <-isDone: - case <-time.After(expire): + time.AfterFunc(expire, func() { if cmd.Process != nil && cmd.Process.Pid != 0 { - err = fmt.Errorf("execute timeout: %v seconds.", expire.Seconds()) + errs = append(errs, fmt.Sprintf("execute timeout: %d min.", int(expire.Minutes()))) syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) cmd.Process.Kill() } + }) + + err = cmd.Wait() + if err != nil { + errs = append(errs, err.Error(), stderr.String()) } out = stdout.String() + if len(errs) > 0 { + errs = append(errs, out) + err = errors.New(strings.Join(errs, "\n\r")) + } return } diff --git a/util/command_linux.go b/util/command/command_linux.go similarity index 56% rename from util/command_linux.go rename to util/command/command_linux.go index 0e22a3c..1a663d2 100644 --- a/util/command_linux.go +++ b/util/command/command_linux.go @@ -1,9 +1,11 @@ -package util +package command import ( "bytes" + "errors" "fmt" "os/exec" + "strings" "syscall" "time" ) @@ -13,6 +15,7 @@ func ExecCommand(name string, args []string, timeout ...time.Duration) (out stri var ( stderr, stdout bytes.Buffer expire = 30 * time.Minute + errs []string ) if len(timeout) > 0 { @@ -23,25 +26,28 @@ func ExecCommand(name string, args []string, timeout ...time.Duration) (out stri cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Stdout = &stdout cmd.Stderr = &stderr + err = cmd.Start() + if err != nil { + err = fmt.Errorf("%s\n%s", err.Error(), stderr.String()) + return + } - isDone := make(chan bool, 1) - go func() { - err = cmd.Run() - if err != nil { - err = fmt.Errorf("%s\n%s", err.Error(), stderr.String()) - } - isDone <- true - }() - - select { - case <-isDone: - case <-time.After(expire): + time.AfterFunc(expire, func() { if cmd.Process != nil && cmd.Process.Pid != 0 { - err = fmt.Errorf("execute timeout: %v seconds.", expire.Seconds()) + errs = append(errs, fmt.Sprintf("execute timeout: %d min.", int(expire.Minutes()))) syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) cmd.Process.Kill() } + }) + + err = cmd.Wait() + if err != nil { + errs = append(errs, err.Error(), stderr.String()) } out = stdout.String() + if len(errs) > 0 { + errs = append(errs, out) + err = errors.New(strings.Join(errs, "\n\r")) + } return } diff --git a/util/command_windows.go b/util/command/command_windows.go similarity index 52% rename from util/command_windows.go rename to util/command/command_windows.go index 54f58a4..42ac721 100644 --- a/util/command_windows.go +++ b/util/command/command_windows.go @@ -1,9 +1,12 @@ -package util +package command import ( "bytes" + "errors" "fmt" + "os" "os/exec" + "strings" "syscall" "time" ) @@ -13,6 +16,7 @@ func ExecCommand(name string, args []string, timeout ...time.Duration) (out stri var ( stderr, stdout bytes.Buffer expire = 30 * time.Minute + errs []string ) if len(timeout) > 0 { @@ -25,23 +29,31 @@ func ExecCommand(name string, args []string, timeout ...time.Duration) (out stri cmd.Stdout = &stdout cmd.Stderr = &stderr - isDone := make(chan bool, 1) - go func() { - err = cmd.Run() - if err != nil { - err = fmt.Errorf("%s\n%s", err.Error(), stderr.String()) - } - isDone <- true - }() + err = cmd.Start() + if err != nil { + err = fmt.Errorf("%s\n%s", err.Error(), stderr.String()) + return + } - select { - case <-isDone: - case <-time.After(expire): + time.AfterFunc(expire, func() { if cmd.Process != nil && cmd.Process.Pid != 0 { - err = fmt.Errorf("execute timeout: %f minutes", expire.Minutes()) + errs = append(errs, fmt.Sprintf("execute timeout: %d min.", int(expire.Minutes()))) + if proc, errProc := os.FindProcess(cmd.Process.Pid); errProc == nil { + proc.Kill() + proc.Release() + } cmd.Process.Kill() } + }) + + err = cmd.Wait() + if err != nil { + errs = append(errs, err.Error(), stderr.String()) } out = stdout.String() + if len(errs) > 0 { + errs = append(errs, out) + err = errors.New(strings.Join(errs, "\n\r")) + } return } diff --git a/util/converter/converter.go b/util/converter/converter.go index ed26d80..045f3cb 100644 --- a/util/converter/converter.go +++ b/util/converter/converter.go @@ -5,6 +5,7 @@ import ( "compress/gzip" "fmt" "moredoc/util" + "moredoc/util/command" "os" "os/exec" "path/filepath" @@ -121,7 +122,7 @@ func (c *Converter) ConvertPDFToTxt(src string) (dst string, err error) { src, } c.logger.Info("convert pdf to txt", zap.String("cmd", mutool), zap.Strings("args", args)) - _, err = util.ExecCommand(mutool, args, c.timeout) + _, err = command.ExecCommand(mutool, args, c.timeout) if err != nil { c.logger.Error("convert pdf to txt", zap.String("cmd", mutool), zap.Strings("args", args), zap.Error(err)) return @@ -190,7 +191,7 @@ func (c *Converter) convertPDFToPage(src string, fromPage, toPage int, ext strin } c.logger.Info("convert pdf to page", zap.String("cmd", mutool), zap.Strings("args", args)) - _, err = util.ExecCommand(mutool, args, c.timeout) + _, err = command.ExecCommand(mutool, args, c.timeout) if err != nil { c.logger.Error("convert pdf to page", zap.String("cmd", mutool), zap.Strings("args", args), zap.Error(err)) return @@ -222,7 +223,7 @@ func (c *Converter) convertToPDFBySoffice(src string) (dst string, err error) { } args = append(args, src) c.logger.Info("convert to pdf by soffice", zap.String("cmd", soffice), zap.Strings("args", args)) - _, err = util.ExecCommand(soffice, args, c.timeout) + _, err = command.ExecCommand(soffice, args, c.timeout) if err != nil { c.logger.Error("convert to pdf by soffice", zap.String("cmd", soffice), zap.Strings("args", args), zap.Error(err)) } @@ -244,7 +245,7 @@ func (c *Converter) convertToPDFByCalibre(src string) (dst string, err error) { } os.MkdirAll(filepath.Dir(dst), os.ModePerm) c.logger.Info("convert to pdf by calibre", zap.String("cmd", ebookConvert), zap.Strings("args", args)) - _, err = util.ExecCommand(ebookConvert, args, c.timeout) + _, err = command.ExecCommand(ebookConvert, args, c.timeout) if err != nil { c.logger.Error("convert to pdf by calibre", zap.String("cmd", ebookConvert), zap.Strings("args", args), zap.Error(err)) } @@ -259,7 +260,7 @@ func (c *Converter) CountPDFPages(file string) (pages int, err error) { } c.logger.Info("count pdf pages", zap.String("cmd", mutool), zap.Strings("args", args)) var out string - out, err = util.ExecCommand(mutool, args, c.timeout) + out, err = command.ExecCommand(mutool, args, c.timeout) if err != nil { c.logger.Error("count pdf pages", zap.String("cmd", mutool), zap.Strings("args", args), zap.Error(err)) return @@ -307,7 +308,7 @@ func (c *Converter) CompressSVGBySVGO(svgFolder string) (err error) { } c.logger.Info("compress svg by svgo", zap.String("cmd", svgo), zap.Strings("args", args)) var out string - out, err = util.ExecCommand(svgo, args, c.timeout*10) + out, err = command.ExecCommand(svgo, args, c.timeout*10) if err != nil { c.logger.Error("compress svg by svgo", zap.String("cmd", svgo), zap.Strings("args", args), zap.Error(err)) } diff --git a/web/pages/admin/document/list.vue b/web/pages/admin/document/list.vue index b7bd3e5..bbaccd3 100644 --- a/web/pages/admin/document/list.vue +++ b/web/pages/admin/document/list.vue @@ -48,12 +48,16 @@ >