gproc_process.go 3.3 KB

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