Files
admin e6956aa001 Initial commit: TaskPool React panel
- React frontend with route-level code splitting
- Backend rebranded from Baihu to TaskPool
- DB brand migration script and local compatibility
2026-07-26 08:43:52 +08:00

242 lines
4.9 KiB
Go

package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"syscall"
"github.com/gofrs/flock"
)
// ========== PID 文件管理 ==========
var fileLock *flock.Flock
func getPidFile() string {
return filepath.Join(dataDir, "agent.pid")
}
func getLockFile() string {
return filepath.Join(dataDir, "agent.lock")
}
// tryLock 尝试获取文件锁,确保只有一个实例运行
func tryLock() bool {
os.MkdirAll(dataDir, 0755)
fileLock = flock.New(getLockFile())
locked, err := fileLock.TryLock()
if err != nil || !locked {
fileLock = nil
return false
}
return true
}
// unlock 释放文件锁
func unlock() {
if fileLock != nil {
fileLock.Unlock()
fileLock = nil
os.Remove(getLockFile())
}
}
func writePidFile() {
os.MkdirAll(dataDir, 0755)
pidFile := getPidFile()
os.WriteFile(pidFile, []byte(strconv.Itoa(os.Getpid())), 0644)
}
func readPidFile() int {
pidFile := getPidFile()
data, err := os.ReadFile(pidFile)
if err != nil {
return 0
}
pid, _ := strconv.Atoi(string(data))
return pid
}
func removePidFile() {
os.Remove(getPidFile())
}
// ========== 命令实现 ==========
func cmdStop() {
pid := readPidFile()
if pid == 0 {
fmt.Println("Agent 未运行")
return
}
process, err := os.FindProcess(pid)
if err != nil {
fmt.Printf("找不到进程 %d\n", pid)
removePidFile()
return
}
if runtime.GOOS == "windows" {
err = process.Kill()
} else {
err = process.Signal(syscall.SIGTERM)
}
if err != nil {
fmt.Printf("停止失败: %v\n", err)
return
}
fmt.Println("Agent 已停止")
removePidFile()
}
func cmdStatus() {
pid := readPidFile()
if pid == 0 {
fmt.Println("状态: 未运行")
return
}
if !isProcessRunning(pid) {
fmt.Println("状态: 未运行")
removePidFile()
return
}
fmt.Printf("状态: 运行中 (PID: %d)\n", pid)
}
func isProcessRunning(pid int) bool {
process, err := os.FindProcess(pid)
if err != nil {
return false
}
// Unix 系统发送信号 0 检查进程
if runtime.GOOS != "windows" {
err = process.Signal(syscall.Signal(0))
return err == nil
}
// Windows 下 FindProcess 成功即表示进程存在
return true
}
func cmdInstall() {
exePath, _ := os.Executable()
exeDir := filepath.Dir(exePath)
if runtime.GOOS == "windows" {
installWindows(exePath, exeDir)
} else {
installLinux(exePath, exeDir)
}
}
func cmdUninstall() {
if runtime.GOOS == "windows" {
uninstallWindows()
} else {
uninstallLinux()
}
}
// ========== Linux systemd ==========
func installLinux(exePath, exeDir string) {
serviceContent := fmt.Sprintf(`[Unit]
Description=%s
After=network.target
[Service]
Type=simple
WorkingDirectory=%s
ExecStart=%s run
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
`, ServiceDesc, exeDir, exePath)
servicePath := fmt.Sprintf("/etc/systemd/system/%s.service", ServiceName)
if err := os.WriteFile(servicePath, []byte(serviceContent), 0644); err != nil {
fmt.Printf("创建服务文件失败: %v\n", err)
fmt.Println("请使用 sudo 运行")
return
}
// 重载 systemd
exec.Command("systemctl", "daemon-reload").Run()
exec.Command("systemctl", "enable", ServiceName).Run()
fmt.Printf("服务已安装: %s\n", servicePath)
fmt.Println("使用以下命令管理服务:")
fmt.Printf(" 启动: sudo systemctl start %s\n", ServiceName)
fmt.Printf(" 停止: sudo systemctl stop %s\n", ServiceName)
fmt.Printf(" 状态: sudo systemctl status %s\n", ServiceName)
}
func uninstallLinux() {
// 停止服务
exec.Command("systemctl", "stop", ServiceName).Run()
exec.Command("systemctl", "disable", ServiceName).Run()
servicePath := fmt.Sprintf("/etc/systemd/system/%s.service", ServiceName)
if err := os.Remove(servicePath); err != nil {
fmt.Printf("删除服务文件失败: %v\n", err)
fmt.Println("请使用 sudo 运行")
return
}
exec.Command("systemctl", "daemon-reload").Run()
fmt.Println("服务已卸载")
}
// ========== Windows 服务 ==========
func installWindows(exePath, exeDir string) {
// 使用 sc.exe 创建服务
cmd := exec.Command("sc", "create", ServiceName,
"binPath=", fmt.Sprintf(`"%s" run`, exePath),
"start=", "auto",
"DisplayName=", ServiceDesc)
if err := cmd.Run(); err != nil {
fmt.Printf("创建服务失败: %v\n", err)
fmt.Println("请以管理员身份运行")
return
}
// 设置服务描述
exec.Command("sc", "description", ServiceName, ServiceDesc).Run()
fmt.Println("服务已安装")
fmt.Println("使用以下命令管理服务:")
fmt.Printf(" 启动: sc start %s\n", ServiceName)
fmt.Printf(" 停止: sc stop %s\n", ServiceName)
fmt.Printf(" 状态: sc query %s\n", ServiceName)
}
func uninstallWindows() {
// 停止服务
exec.Command("sc", "stop", ServiceName).Run()
// 删除服务
cmd := exec.Command("sc", "delete", ServiceName)
if err := cmd.Run(); err != nil {
fmt.Printf("删除服务失败: %v\n", err)
fmt.Println("请以管理员身份运行")
return
}
fmt.Println("服务已卸载")
}