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  }