From 9dadc39725887215f9ab34982379b667743e07c2 Mon Sep 17 00:00:00 2001 From: pcong Date: Sat, 11 Jan 2025 18:31:42 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E6=8E=A7=E5=88=B6frpc=E8=BF=9B=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- godo/cmd/main.go | 9 ++++-- godo/progress/progress.go | 55 ++++++++++++++++++++++++++++++++++- godo/proxy/frpc_service.go | 59 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 godo/proxy/frpc_service.go diff --git a/godo/cmd/main.go b/godo/cmd/main.go index 0610eae..97b0379 100644 --- a/godo/cmd/main.go +++ b/godo/cmd/main.go @@ -171,10 +171,13 @@ func OsStart() { // 注册frpc路由 frpcRouter := router.PathPrefix("/frpc").Subrouter() frpcRouter.HandleFunc("/create", proxy.CreateFrpcHandler).Methods(http.MethodPost) - frpcRouter.HandleFunc("/delete", proxy.DeleteFrpcConfigHandler).Methods(http.MethodGet) // 删除frpc配置 - frpcRouter.HandleFunc("/get", proxy.GetFrpcConfigHandler).Methods(http.MethodGet) // 获取frpc配置 - frpcRouter.HandleFunc("/list", proxy.GetFrpcProxiesHandler).Methods(http.MethodGet) // 获取frpc代理列表 + frpcRouter.HandleFunc("/delete", proxy.DeleteFrpcConfigHandler).Methods(http.MethodGet) // 删除frpc配置 + frpcRouter.HandleFunc("/get", proxy.GetFrpcConfigHandler).Methods(http.MethodGet) // 获取frpc配置 + frpcRouter.HandleFunc("/list", proxy.GetFrpcProxiesHandler).Methods(http.MethodGet) // 获取frpc代理列表 frpcRouter.HandleFunc("/update", proxy.UpdateFrpcConfigHandler).Methods(http.MethodPost) // 更新frpc配置 + frpcRouter.HandleFunc("/start", proxy.StartFrpcHandler).Methods(http.MethodPost) // 启动frpc服务 + frpcRouter.HandleFunc("/stop", proxy.StopFrpcHandler).Methods(http.MethodPost) // 停止frpc服务 + frpcRouter.HandleFunc("/restart", proxy.RestartFrpcHandler).Methods(http.MethodPost) // 重启frpc服务 // 注册根路径的处理函数 distFS, _ := fs.Sub(deps.Frontendassets, "dist") diff --git a/godo/progress/progress.go b/godo/progress/progress.go index 1c98a9e..11918d1 100644 --- a/godo/progress/progress.go +++ b/godo/progress/progress.go @@ -10,13 +10,18 @@ import ( "os/exec" "path/filepath" "runtime" + "strconv" + "strings" "sync" + + "github.com/shirou/gopsutil/process" ) type Process struct { Name string Running bool ExitCode int + Pid int Cmd *exec.Cmd } @@ -31,6 +36,7 @@ func RegisterProcess(name string, cmdstr *exec.Cmd) { processes[name] = &Process{ Name: name, Running: true, + Pid: cmdstr.Process.Pid, Cmd: cmdstr, } } @@ -121,15 +127,24 @@ func StopCmd(name string) error { if !ok { return fmt.Errorf("process information for '%s' not found", name) } + if cmd.Running == false { + return nil + } // 停止进程并更新status - if err := cmd.Cmd.Process.Kill(); err != nil { + // 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 { return err @@ -147,3 +162,41 @@ func StopAllCmd() error { } 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 +} diff --git a/godo/proxy/frpc_service.go b/godo/proxy/frpc_service.go new file mode 100644 index 0000000..3b391ce --- /dev/null +++ b/godo/proxy/frpc_service.go @@ -0,0 +1,59 @@ +package proxy + +import ( + "encoding/json" + "godo/progress" + "log" + "net/http" +) + +func StartFrpcHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + if err := progress.StartCmd("frpc"); err != nil { + log.Printf("Failed to start frpc service: %v", err) + http.Error(w, "Failed to start frpc service", http.StatusInternalServerError) + return + } + + response := NewResponse("0", "frpc service started", nil) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +func StopFrpcHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + if err := progress.StopCmd("frpc"); err != nil { + log.Printf("Failed to stop frpc service: %v", err) + http.Error(w, "Failed to stop frpc service", http.StatusInternalServerError) + return + } + + response := NewResponse("0", "frpc service stoped", nil) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +func RestartFrpcHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + if err := progress.RestartCmd("frpc"); err != nil { + log.Printf("Failed to restarted frpc service: %v", err) + http.Error(w, "Failed to restarted frpc service", http.StatusInternalServerError) + return + } + + response := NewResponse("0", "frpc service restarted", nil) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +}