frps端同步frpc2.4-LTS的全套代码库的设计逻辑

This commit is contained in:
2026-08-01 19:31:03 +08:00
parent ccdd5b0725
commit 3214215032
10 changed files with 988 additions and 455 deletions
+95 -25
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"embed"
"fmt"
"io"
"log"
"os"
"os/exec"
@@ -27,10 +28,6 @@ var (
frpsPathMutex sync.Mutex
)
// ============================================================
// 获取 frps 路径
// ============================================================
func getFrpsPath() (string, error) {
frpsPathMutex.Lock()
defer frpsPathMutex.Unlock()
@@ -92,17 +89,13 @@ func getFrpsPath() (string, error) {
return "", fmt.Errorf("未找到 frps 文件")
}
// ============================================================
// 生成 frps.toml
// ============================================================
func GenerateFrpsConfig() error {
cfg, err := GetGlobalConfig()
if err != nil {
return fmt.Errorf("读取全局配置失败: %w", err)
}
// 直接传递 cfg 即可,模板里能读到 .WireProtocolV2
// 直接使用 cfg,模板使用 frps.tmpl
var tmplContent string
if _, err := os.Stat("frps.tmpl"); err == nil {
content, readErr := os.ReadFile("frps.tmpl")
@@ -125,19 +118,18 @@ func GenerateFrpsConfig() error {
return fmt.Errorf("渲染模板失败: %w", err)
}
if err := os.WriteFile("./frps.toml", buf.Bytes(), 0644); err != nil {
if err := os.MkdirAll("./data", 0755); err != nil {
return fmt.Errorf("创建 data 目录失败: %w", err)
}
if err := os.WriteFile("./data/frps.toml", buf.Bytes(), 0644); err != nil {
return fmt.Errorf("写入配置文件失败: %w", err)
}
return nil
}
// ============================================================
// frps 进程管理
// ============================================================
func isFrpsRunning() bool {
pidData, err := os.ReadFile("./frps.pid")
pidData, err := os.ReadFile("./data/frps.pid")
if err != nil {
return false
}
@@ -168,7 +160,11 @@ func StartFrps() error {
return fmt.Errorf("获取 frps 路径失败: %w", err)
}
if _, err := os.Stat("./frps.toml"); os.IsNotExist(err) {
if err := os.MkdirAll("./data", 0755); err != nil {
return fmt.Errorf("创建 data 目录失败: %w", err)
}
if _, err := os.Stat("./data/frps.toml"); os.IsNotExist(err) {
if err := GenerateFrpsConfig(); err != nil {
return fmt.Errorf("生成配置文件失败: %w", err)
}
@@ -178,13 +174,13 @@ func StartFrps() error {
return nil
}
os.Remove("./frps.pid")
os.Remove("./data/frps.pid")
cmd := exec.Command(frpsPath, "-c", "./frps.toml")
cmd := exec.Command(frpsPath, "-c", "./data/frps.toml")
setWindowHide(cmd)
setSysProcAttr(cmd)
logFile, err := os.OpenFile("./frps.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
logFile, err := os.OpenFile("./data/frps.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return fmt.Errorf("打开日志文件失败: %w", err)
}
@@ -195,7 +191,7 @@ func StartFrps() error {
return fmt.Errorf("启动 frps 失败: %w", err)
}
if err := os.WriteFile("./frps.pid", []byte(fmt.Sprintf("%d", cmd.Process.Pid)), 0644); err != nil {
if err := os.WriteFile("./data/frps.pid", []byte(fmt.Sprintf("%d", cmd.Process.Pid)), 0644); err != nil {
return fmt.Errorf("保存 PID 失败: %w", err)
}
@@ -208,11 +204,11 @@ func StopFrps() error {
if err := cmd.Run(); err != nil && !strings.Contains(err.Error(), "not found") {
return fmt.Errorf("停止 frps 失败: %w", err)
}
os.Remove("./frps.pid")
os.Remove("./data/frps.pid")
return nil
}
pidData, err := os.ReadFile("./frps.pid")
pidData, err := os.ReadFile("./data/frps.pid")
if err != nil {
cmd := exec.Command("pkill", "-f", "frps")
if err := cmd.Run(); err != nil && !strings.Contains(err.Error(), "no process") {
@@ -224,7 +220,7 @@ func StopFrps() error {
pid, _ := strconv.Atoi(strings.TrimSpace(string(pidData)))
process, err := os.FindProcess(pid)
if err != nil {
os.Remove("./frps.pid")
os.Remove("./data/frps.pid")
return nil
}
@@ -232,7 +228,7 @@ func StopFrps() error {
return fmt.Errorf("杀死进程失败: %w", err)
}
os.Remove("./frps.pid")
os.Remove("./data/frps.pid")
return nil
}
@@ -251,7 +247,7 @@ func ReloadFrps() error {
return fmt.Errorf("获取 frps 路径失败: %w", err)
}
cmd := exec.Command(frpsPath, "reload", "-c", "./frps.toml")
cmd := exec.Command(frpsPath, "reload", "-c", "./data/frps.toml")
_, err = cmd.CombinedOutput()
if err != nil {
log.Printf("⚠️ 热加载失败 (%v),自动降级为重启 frps", err)
@@ -265,3 +261,77 @@ func ReloadFrps() error {
}
return nil
}
// readTailLog 通用
func readTailLog(filePath string, n int) ([]string, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
info, err := file.Stat()
if err != nil {
return nil, err
}
fileSize := info.Size()
if fileSize == 0 {
return []string{}, nil
}
const chunkSize = 4096
var lines []string
var leftover []byte
offset := fileSize
for len(lines) < n && offset > 0 {
readSize := chunkSize
if offset < int64(chunkSize) {
readSize = int(offset)
}
offset -= int64(readSize)
buf := make([]byte, readSize)
_, err := file.ReadAt(buf, offset)
if err != nil && err != io.EOF {
return nil, err
}
data := append(buf, leftover...)
leftover = nil
start := 0
for i := len(data) - 1; i >= 0; i-- {
if data[i] == '\n' {
if i+1 < len(data) {
line := string(data[i+1:])
if line != "" {
lines = append([]string{line}, lines...)
if len(lines) >= n {
break
}
}
}
start = i
}
}
if len(lines) < n && start > 0 {
leftover = data[:start]
}
}
if len(lines) < n && len(leftover) > 0 {
parts := strings.Split(string(leftover), "\n")
for i := len(parts) - 1; i >= 0; i-- {
if parts[i] != "" {
lines = append([]string{parts[i]}, lines...)
if len(lines) >= n {
break
}
}
}
}
return lines, nil
}