package models import ( "errors" "fmt" "os" "os/exec" "path/filepath" "strings" ) type Service struct { Name string `json:"name"` Description string `json:"description"` ExecutablePath string `json:"executablePath,omitempty"` WorkingDirectory string `json:"workingDirectory,omitempty"` Arguments []string `json:"arguments,omitempty"` State string `json:"-"` Cmd *exec.Cmd `json:"-"` Stopping bool `json:"-"` } func (s *Service) Start(errFunc func(e string)) error { s.State = "Error" absolutePath, err := filepath.Abs(s.ExecutablePath) if err != nil { return err } var arguments []string for _, a := range s.Arguments { arguments = append(arguments, strings.Split(a, " ")...) } s.Cmd = exec.Command(absolutePath, arguments...) s.Cmd.Dir = s.WorkingDirectory s.Cmd.Stdout = os.Stdout s.Cmd.Stderr = os.Stderr err = s.Cmd.Start() if err != nil { return err } go func() { err := s.Cmd.Wait() if err != nil { // Process exited with error if exitErr, ok := err.(*exec.ExitError); ok { if !s.Stopping { errFunc(fmt.Sprintf("Command failed with exit code %d: %v", exitErr.ExitCode(), err)) } } else { errFunc(fmt.Sprintf("Command wait error: %v", err)) } } s.Stopping = false }() s.State = "Running" return nil } func (s *Service) Stop() error { s.State = "Error" if s.Cmd == nil { return errors.New("process nil pointer") } // Stop (kill) the process s.Stopping = true err := s.Cmd.Process.Kill() if err != nil { return err } s.State = "Stopped" return nil }