You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

196 lines
4.6 KiB

package progress
import (
"fmt"
"godo/libs"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"sync"
"github.com/shirou/gopsutil/process"
)
type Process struct {
Name string
Running bool
ExitCode int
Pid int
Cmd *exec.Cmd
}
var (
processesMu sync.RWMutex
processes = make(map[string]*Process)
)
func RegisterProcess(name string, cmdstr *exec.Cmd) {
processesMu.Lock()
defer processesMu.Unlock()
processes[name] = &Process{
Name: name,
Running: true,
Pid: cmdstr.Process.Pid,
Cmd: cmdstr,
}
}
func GetCmd(name string) *Process {
// processesMu.Lock()
// defer processesMu.Unlock()
info, ok := processes[name]
if !ok {
return &Process{
Name: name,
Running: false,
}
}
return info
}
// StartCmd 执行指定名称的脚本。
// 参数:
// name - 脚本的名称。
// 返回值:
// 返回可能遇到的错误,如果执行成功,则返回nil。
func StartCmd(name string) error {
info, ok := processes[name]
if ok && info.Running {
return fmt.Errorf("process information for '%s' is runing", name)
}
//appName := name
scriptPath, err := libs.GetCmdPath(name)
if err != nil {
return fmt.Errorf("failed to extract zip file: %v", err)
}
// 设置并启动脚本执行命令
var cmd *exec.Cmd
switch name {
case "frpc":
// 检查配置文件
configPath := filepath.Join(filepath.Dir(scriptPath), "frpc.ini")
log.Printf("Config file not found at %s, creating new file", configPath)
if !libs.PathExists(configPath) {
return fmt.Errorf("frpc config file not found")
}
params := []string{
"-c",
configPath,
}
cmd = exec.Command(scriptPath, params...)
default:
cmd = exec.Command(scriptPath)
}
log.Printf("Starting %s", scriptPath)
//cmd = exec.Command(scriptPath)
if runtime.GOOS == "windows" {
// 在Windows上,通过设置CreationFlags来隐藏窗口
cmd = SetHideConsoleCursor(cmd)
}
go func() {
// 启动脚本命令并返回可能的错误
if err := cmd.Start(); err != nil {
//log.Printf("failed to start process %s: %v", name, err)
return
}
RegisterProcess(name, cmd)
// 等待命令完成
if err := cmd.Wait(); err != nil {
log.Printf("command failed for %s: %v", name, err)
//return
} else {
log.Printf("%s command completed successfully", name)
}
// 命令完成后,更新进程信息
processesMu.Lock()
defer processesMu.Unlock()
if p, ok := processes[name]; ok {
p.Running = false
p.ExitCode = cmd.ProcessState.ExitCode()
}
}()
return nil
}
func StopCmd(name string) error {
cmd, ok := processes[name]
if !ok {
return fmt.Errorf("process information for '%s' not found", name)
}
if !cmd.Running {
return nil
}
// 停止进程并更新status
// TODO: 如果有多个pid 的情况,需要处理
if err := KillByPid(cmd.Pid); err != nil {
return fmt.Errorf("failed to kill process %s: %v", name, err)
}
// if err := cmd.Cmd.Process.Kill(); err != nil {
// return fmt.Errorf("failed to kill process %s: %v", name, err)
// }
//delete(processes, name) // 更新status,表示进程已停止
cmd.Running = false
return nil
}
func RestartCmd(name string) error {
if err := StopCmd(name); err != nil {
log.Printf("stopping the app encountered an error: %s", err)
return err
}
return StartCmd(name)
}
func StopAllCmd() error {
processesMu.Lock()
defer processesMu.Unlock()
for name, cmd := range processes {
if err := cmd.Cmd.Process.Signal(os.Interrupt); err != nil {
return fmt.Errorf("failed to stop process %s: %v", name, err)
}
}
return nil
}
func KillByPid(pid int) error {
log.Println("Killing process with PID:", pid)
p, err := process.NewProcess(int32(pid))
if err != nil {
return fmt.Errorf("failed to create process object: %w", err)
}
// 杀死进程及其子进程
if err := p.Kill(); err != nil {
return fmt.Errorf("failed to kill process: %w", err)
}
return nil
}
// // findPidsWindows 在 Windows 系统下查找具有指定名称的进程的 PID
// func findPidsWindows(name string) ([]int, error) {
// cmd := exec.Command("tasklist")
// output, err := cmd.Output()
// if err != nil {
// return nil, fmt.Errorf("failed to execute tasklist: %w", err)
// }
// lines := strings.Split(string(output), "\r\n")
// var pids []int
// for _, line := range lines {
// fields := strings.Fields(line)
// if len(fields) >= 3 {
// if strings.Contains(strings.ToLower(fields[0]), strings.ToLower(name)) {
// pid, err := strconv.Atoi(fields[1])
// if err != nil {
// return nil, fmt.Errorf("failed to convert PID to integer: %w", err)
// }
// pids = append(pids, pid)
// }
// }
// }
// return pids, nil
// }