github.com/gogf/gf@v1.16.9/os/gproc/gproc_process.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gproc 8 9 import ( 10 "context" 11 "fmt" 12 "github.com/gogf/gf/errors/gcode" 13 "github.com/gogf/gf/errors/gerror" 14 "github.com/gogf/gf/internal/intlog" 15 "os" 16 "os/exec" 17 "runtime" 18 "strings" 19 ) 20 21 // Process is the struct for a single process. 22 type Process struct { 23 exec.Cmd 24 Manager *Manager 25 PPid int 26 } 27 28 // NewProcess creates and returns a new Process. 29 func NewProcess(path string, args []string, environment ...[]string) *Process { 30 env := os.Environ() 31 if len(environment) > 0 { 32 for k, v := range environment[0] { 33 env[k] = v 34 } 35 } 36 process := &Process{ 37 Manager: nil, 38 PPid: os.Getpid(), 39 Cmd: exec.Cmd{ 40 Args: []string{path}, 41 Path: path, 42 Stdin: os.Stdin, 43 Stdout: os.Stdout, 44 Stderr: os.Stderr, 45 Env: env, 46 ExtraFiles: make([]*os.File, 0), 47 }, 48 } 49 process.Dir, _ = os.Getwd() 50 if len(args) > 0 { 51 // Exclude of current binary path. 52 start := 0 53 if strings.EqualFold(path, args[0]) { 54 start = 1 55 } 56 process.Args = append(process.Args, args[start:]...) 57 } 58 return process 59 } 60 61 // NewProcessCmd creates and returns a process with given command and optional environment variable array. 62 func NewProcessCmd(cmd string, environment ...[]string) *Process { 63 return NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), environment...) 64 } 65 66 // Start starts executing the process in non-blocking way. 67 // It returns the pid if success, or else it returns an error. 68 func (p *Process) Start() (int, error) { 69 if p.Process != nil { 70 return p.Pid(), nil 71 } 72 p.Env = append(p.Env, fmt.Sprintf("%s=%d", envKeyPPid, p.PPid)) 73 if err := p.Cmd.Start(); err == nil { 74 if p.Manager != nil { 75 p.Manager.processes.Set(p.Process.Pid, p) 76 } 77 return p.Process.Pid, nil 78 } else { 79 return 0, err 80 } 81 } 82 83 // Run executes the process in blocking way. 84 func (p *Process) Run() error { 85 if _, err := p.Start(); err == nil { 86 return p.Wait() 87 } else { 88 return err 89 } 90 } 91 92 // Pid retrieves and returns the PID for the process. 93 func (p *Process) Pid() int { 94 if p.Process != nil { 95 return p.Process.Pid 96 } 97 return 0 98 } 99 100 // Send sends custom data to the process. 101 func (p *Process) Send(data []byte) error { 102 if p.Process != nil { 103 return Send(p.Process.Pid, data) 104 } 105 return gerror.NewCode(gcode.CodeInvalidParameter, "invalid process") 106 } 107 108 // Release releases any resources associated with the Process p, 109 // rendering it unusable in the future. 110 // Release only needs to be called if Wait is not. 111 func (p *Process) Release() error { 112 return p.Process.Release() 113 } 114 115 // Kill causes the Process to exit immediately. 116 func (p *Process) Kill() error { 117 if err := p.Process.Kill(); err == nil { 118 if p.Manager != nil { 119 p.Manager.processes.Remove(p.Pid()) 120 } 121 if runtime.GOOS != "windows" { 122 if err = p.Process.Release(); err != nil { 123 intlog.Error(context.TODO(), err) 124 } 125 } 126 _, err = p.Process.Wait() 127 intlog.Error(context.TODO(), err) 128 //return err 129 return nil 130 } else { 131 return err 132 } 133 } 134 135 // Signal sends a signal to the Process. 136 // Sending Interrupt on Windows is not implemented. 137 func (p *Process) Signal(sig os.Signal) error { 138 return p.Process.Signal(sig) 139 }