From 35cc5d360b4a74cdd193e429c93913ddd339f271 Mon Sep 17 00:00:00 2001 From: ZhuoQinghui <1302344380@qq.com> Date: Thu, 10 Oct 2024 17:05:11 +0800 Subject: [PATCH] daemon --- main.go | 265 ++++++++++++++++++++++++++++++++++++++++++++- src/acme-client.go | 4 +- 2 files changed, 264 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 8f30d5c..c615229 100644 --- a/main.go +++ b/main.go @@ -1,17 +1,274 @@ package main import ( - "acme-mana/src" "fmt" + "log" + "net" + "os" + "os/exec" + "path/filepath" + "strconv" + "syscall" ) func main() { - config := src.GetAppConfig() - fmt.Println(config) - src.Apply(config.Domains[0]) + //config := src.GetAppConfig() + //fmt.Println(config) + //src.Apply(config.Domains[0]) //fmt.Println(os.Getwd()) //err := os.MkdirAll("cert\\abc", 0777) //if err != nil { // fmt.Println(err) //} + fmt.Println("start()") + start() +} + +const pidFile = "acme-mana.pid" +const socketFile = "acme-mana.sock" + +func start() { + log.Println("Run Acme Mana...") + args := os.Args + if len(args) <= 1 { + daemonStart() + return + } + command := args[1] + switch command { + case "start": + daemonStart() + case "stop": + daemonStop() + case "status": + daemonStatus() + case "-s": + daemonCommand() + default: + log.Fatalf("Unknown command: %s", command) + } +} + +func daemonStart() { + isDaemon := os.Getenv("GO_DAEMON") + log.Println("Run Daemon, DAEMON Is " + isDaemon) + if isDaemon != "1" { + // 直接启动 + if isRunning() { + log.Println("Daemon is already running.") + return + } + + path, err := os.Executable() + if err != nil { + log.Fatalf("Failed to get executable path: %v", err) + } + cmd := exec.Cmd{ + Path: path, + Args: os.Args, + Dir: filepath.Dir(path), + Env: append(os.Environ(), "GO_DAEMON=1"), + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + SysProcAttr: &syscall.SysProcAttr{}, + } + + //cmd := exec.Command(os.Args[0]) + //cmd.Env = append(os.Environ(), "GO_DAEMON=1") + //cmd.Stdout = os.Stdout + //cmd.Stderr = os.Stderr + //cmd.SysProcAttr = &syscall.SysProcAttr{} + log.Println("Starting daemon...") + log.Println(cmd) + err = cmd.Start() + if err != nil { + log.Fatalf("Failed to start daemon: %v", err) + } + err = os.WriteFile(pidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0644) + if err != nil { + log.Fatalf("Failed to write PID file: %v", err) + } + log.Printf("Daemon started with PID: %d", cmd.Process.Pid) + os.Exit(0) + + } else { + // 子进程 + doTask() + } + +} + +func daemonStop() { + //pid, err := readPID() + //if err != nil { + // log.Fatalf("Failed to stop daemon: %v", err) + //} + // + //process, err := os.FindProcess(pid) + //if err != nil { + // log.Fatalf("Failed to find process: %v", err) + //} + // + //err = process.Signal(syscall.SIGTERM) + //if err != nil { + // log.Fatalf("Failed to stop process: %v", err) + //} + // + //os.Remove(pidFile) + //os.Remove(socketFile) + //log.Println("Daemon stopped.") + sendCommand("stop") +} + +func daemonStatus() { + if isRunning() { + log.Println("Daemon is running.") + } else { + log.Println("Daemon is not running.") + } +} + +func daemonCommand() { + log.Println("Sending command...") + //pid, err := readPID() + //if err != nil { + // log.Fatalf("Failed to send command: %v", err) + //} + // + //_, err = os.FindProcess(pid) + //if err != nil { + // log.Fatalf("Failed to find process: %v", err) + //} + //if len(os.Args) < 3 { + // log.Fatalf("No command specified") + //} + command := os.Args[2] + sendCommand(command) + +} + +func sendCommand(command string) { + conn, err := net.Dial("unix", socketFile) + if err != nil { + log.Fatalf("Failed to connect to daemon: %v", err) + } + defer func(conn net.Conn) { + err := conn.Close() + if err != nil { + log.Fatalf("Failed to close connection: %v", err) + } + }(conn) + + _, err = conn.Write([]byte(command)) + if err != nil { + log.Fatalf("Failed to send command: %v", err) + } + + log.Printf("Sending command '%s' to daemon with PID: %d", command, 0) +} + +func doTask() { + // 示例:每隔10秒打印一条日志 + //for { + // log.Println("Daemon is running...") + // time.Sleep(10 * time.Second) + //} + initSocket() +} + +func isRunning() bool { + log.Println("Checking if daemon is running...") + pid, err := readPID() + if err != nil { + return false + } + + process, err := os.FindProcess(pid) + log.Println("Found process:", process) + if err != nil { + log.Println("Failed to find process:", err) + return false + } + + err = process.Signal(syscall.Signal(0)) + log.Println("Signal result:", err) + return err == nil +} + +func readPID() (int, error) { + log.Println("Reading PID file...") + data, err := os.ReadFile(pidFile) + if err != nil { + log.Println("Failed to read PID file:", err) + return 0, err + } + log.Println("PID file content:", string(data)) + + pid, err := strconv.Atoi(string(data)) + if err != nil { + log.Println("Failed to parse PID:", err) + return 0, err + } + log.Println("PID:", pid) + + return pid, nil +} + +func initSocket() { + // 删除旧的 socket 文件 + if _, err := os.Stat(socketFile); err == nil { + os.Remove(socketFile) + } + + listener, err := net.Listen("unix", socketFile) + if err != nil { + log.Fatalf("Failed to listen on socket: %v", err) + } + defer listener.Close() + + for { + log.Println("Waiting for connections...") + conn, err := listener.Accept() + if err != nil { + log.Printf("Failed to accept connection: %v", err) + continue + } + + go handleConnection(conn) + } +} + +func handleConnection(conn net.Conn) { + defer conn.Close() + + buf := make([]byte, 1024) + n, err := conn.Read(buf) + if err != nil { + log.Printf("Failed to read command: %v", err) + return + } + + command := string(buf[:n]) + log.Printf("Received command: %s", command) + + // 在这里处理接收到的命令 + switch command { + case "stop": + onStop() + default: + onCommand(command) + } +} + +func onStop() { + log.Println("Stopping daemon...") + os.Remove(pidFile) + log.Println("Remove PID File...") + os.Remove(socketFile) + log.Println("Remove Socket File...") + os.Exit(0) +} +func onCommand(command string) { + } diff --git a/src/acme-client.go b/src/acme-client.go index 33e71fd..17355e4 100644 --- a/src/acme-client.go +++ b/src/acme-client.go @@ -15,6 +15,8 @@ import ( "path/filepath" ) +// Apply 申请证书 +// domain: 申请的域名 func Apply(domain Domain) { email, hosts, name := domain.Email, domain.Host, domain.Name privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -29,7 +31,6 @@ func Apply(domain Domain) { config := lego.NewConfig(&acmeUser) - // A client facilitates communication with the CA server. client, err := lego.NewClient(config) if err != nil { log.Fatal(err) @@ -80,6 +81,7 @@ func Apply(domain Domain) { saveCertFile(cert, name) } +// saveCertFile 保存证书文件 func saveCertFile(cert *certificate.Resource, name string) { dir := GetAppConfig().CertDir dir = filepath.Join(dir, name)