feat(watchdog): add auto boot up for watchdog progress

This commit is contained in:
2026-05-09 15:30:03 +08:00
parent 898b67a24b
commit 21a4b03c57
5 changed files with 121 additions and 0 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
# #
# Binaries for programs and plugins # Binaries for programs and plugins
.gocache/
*.exe *.exe
*.exe~ *.exe~
*.dll *.dll

2
watchdog/keepalive.go Normal file
View File

@@ -0,0 +1,2 @@
package watchdog

View File

@@ -4,7 +4,14 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"net" "net"
"os"
"os/exec"
"path/filepath"
"strings" "strings"
"super-frpc/global"
"super-frpc/sys"
"super-frpc/utils"
"super-frpc/postLog"
"sync" "sync"
"time" "time"
) )
@@ -19,9 +26,20 @@ var (
) )
func Init() error { func Init() error {
if global.CurrentConfig.Watchdog.Enabled {
if err := ensureWatchdogProcess(); err != nil {
postLog.Error(fmt.Sprintf("Failed to boot watchdog program: %v", err))
return err
}
}
tcpConnMutex.Lock() tcpConnMutex.Lock()
defer tcpConnMutex.Unlock() defer tcpConnMutex.Unlock()
if recvChan != nil || stopRecvChan != nil {
return nil
}
if tcpConn != nil { if tcpConn != nil {
return fmt.Errorf("TCP client already initialized") return fmt.Errorf("TCP client already initialized")
} }
@@ -33,6 +51,86 @@ func Init() error {
return nil return nil
} }
func ensureWatchdogProcess() error {
watchdogName, err := getWatchdogBinaryName()
if err != nil {
return err
}
if isWatchdogProcessRunning(watchdogName) {
postLog.Info(fmt.Sprintf("Watchdog process %s is already running, skipping initialize...", watchdogName))
return nil
}
postLog.Info(fmt.Sprintf("Watchdog process %s is not running, starting it...", watchdogName))
watchdogPath := filepath.Join(".", "watchdog", watchdogName)
if !utils.IsFileExist(watchdogPath) {
return fmt.Errorf("watchdog binary not found: %s", watchdogPath)
}
cmd := exec.Command(watchdogPath)
devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0)
if err != nil {
return fmt.Errorf("failed to open null device: %w", err)
}
defer devNull.Close()
cmd.Stdin = devNull
cmd.Stdout = devNull
cmd.Stderr = devNull
configureWatchdogCommand(cmd)
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to start watchdog process %s: %w", watchdogPath, err)
}
return nil
}
func getWatchdogBinaryName() (string, error) {
switch sys.GetInitSystem() {
case "systemd":
return "watchdog_systemd", nil
case "init.d":
return "watchdog_initd", nil
case "windows":
if utils.IsFileExist(filepath.Join(".", "watchdog", "watchdog_windows.exe")) {
return "watchdog_windows.exe", nil
}
return "watchdog_windows", nil
default:
return "", fmt.Errorf("unsupported init system: %s", sys.GetInitSystem())
}
}
func isWatchdogProcessRunning(watchdogName string) bool {
switch sys.GetInitSystem() {
case "windows":
cmd := exec.Command("tasklist", "/FI", fmt.Sprintf("IMAGENAME eq %s", watchdogName))
output, err := cmd.CombinedOutput()
if err != nil {
return false
}
outputStr := strings.ToLower(string(output))
return strings.Contains(outputStr, strings.ToLower(watchdogName)) && !strings.Contains(outputStr, "no tasks are running")
case "systemd", "init.d":
cmd := exec.Command("ps", "-A", "-o", "comm=")
output, err := cmd.CombinedOutput()
if err != nil {
return false
}
for _, line := range strings.Split(string(output), "\n") {
if strings.TrimSpace(line) == watchdogName {
return true
}
}
return false
default:
return false
}
}
func tcpConnect(ipaddr string, port int) error { func tcpConnect(ipaddr string, port int) error {
tcpConnMutex.Lock() tcpConnMutex.Lock()
defer tcpConnMutex.Unlock() defer tcpConnMutex.Unlock()

View File

@@ -0,0 +1,8 @@
//go:build linux
package watchdog
import "os/exec"
func configureWatchdogCommand(cmd *exec.Cmd) {
}

View File

@@ -0,0 +1,12 @@
//go:build windows
package watchdog
import (
"os/exec"
"syscall"
)
func configureWatchdogCommand(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
}