frps端同步frpc2.4-LTS的全套代码库的设计逻辑
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user