gproc_process.go 3.2 KB

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