正在优化linux端的运行状态于逻辑
This commit is contained in:
@@ -4,13 +4,17 @@ import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
|
||||
"github.com/creack/pty"
|
||||
)
|
||||
|
||||
//go:embed bin/*
|
||||
@@ -24,7 +28,10 @@ var (
|
||||
frpcPathMutex sync.Mutex
|
||||
)
|
||||
|
||||
// getFrpcPath 获取当前平台对应的 frpc 路径(优先使用缓存)
|
||||
// getFrpcPath 获取 frpc 路径,优先级:
|
||||
// 1. 当前目录 ./bin/<platform> (便于用户手动管理 frpc 版本)
|
||||
// 2. embed 解压到 /tmp (便于开箱即用)
|
||||
// 3. 系统 PATH 中的 frpc (降级方案)
|
||||
func getFrpcPath() (string, error) {
|
||||
frpcPathMutex.Lock()
|
||||
defer frpcPathMutex.Unlock()
|
||||
@@ -34,21 +41,24 @@ func getFrpcPath() (string, error) {
|
||||
if _, err := os.Stat(cachedFrpcPath); err == nil {
|
||||
return cachedFrpcPath, nil
|
||||
}
|
||||
// 缓存失效,清空
|
||||
cachedFrpcPath = ""
|
||||
}
|
||||
|
||||
// 确定文件名
|
||||
// 确定当前平台的文件名
|
||||
var fileName string
|
||||
switch {
|
||||
case runtime.GOOS == "windows" && runtime.GOARCH == "amd64":
|
||||
fileName = "frpc_windows_amd64.exe"
|
||||
case runtime.GOOS == "windows" && runtime.GOARCH == "386":
|
||||
fileName = "frpc_windows_386.exe"
|
||||
case runtime.GOOS == "linux" && runtime.GOARCH == "amd64":
|
||||
fileName = "frpc_linux_amd64"
|
||||
case runtime.GOOS == "linux" && runtime.GOARCH == "arm64":
|
||||
fileName = "frpc_linux_arm64"
|
||||
case runtime.GOOS == "linux" && runtime.GOARCH == "arm":
|
||||
fileName = "frpc_linux_armv7"
|
||||
default:
|
||||
// 降级:尝试从系统 PATH 查找 frpc
|
||||
// 不支持的平台,尝试从 PATH 找
|
||||
path, err := exec.LookPath("frpc")
|
||||
if err == nil {
|
||||
cachedFrpcPath = path
|
||||
@@ -57,36 +67,39 @@ func getFrpcPath() (string, error) {
|
||||
return "", fmt.Errorf("不支持的平台: %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// 从 embed 读取
|
||||
// ===== 优先级 1:从当前目录 ./bin/ 查找 =====
|
||||
localPath := filepath.Join(".", "bin", fileName)
|
||||
if _, err := os.Stat(localPath); err == nil {
|
||||
cachedFrpcPath = localPath
|
||||
return localPath, nil
|
||||
}
|
||||
|
||||
// ===== 优先级 2:从 embed 读取并解压到临时目录 =====
|
||||
data, err := embeddedFrpc.ReadFile("bin/" + fileName)
|
||||
if err != nil {
|
||||
// 降级到 PATH
|
||||
path, lookErr := exec.LookPath("frpc")
|
||||
if lookErr == nil {
|
||||
cachedFrpcPath = path
|
||||
return path, nil
|
||||
if err == nil {
|
||||
tmpPath := filepath.Join(os.TempDir(), "frpc")
|
||||
if runtime.GOOS == "windows" {
|
||||
tmpPath += ".exe"
|
||||
}
|
||||
return "", fmt.Errorf("未找到 frpc 文件 (embed 和 PATH 均无): %w", err)
|
||||
}
|
||||
|
||||
// 写入临时目录
|
||||
tmpPath := os.TempDir() + "/frpc"
|
||||
if runtime.GOOS == "windows" {
|
||||
tmpPath += ".exe"
|
||||
}
|
||||
|
||||
// 尝试写入(如果文件已存在且正在使用,忽略错误,直接使用已有文件)
|
||||
if err := os.WriteFile(tmpPath, data, 0755); err != nil {
|
||||
// 如果写入失败,检查是否已有可用的 frpc
|
||||
if err := os.WriteFile(tmpPath, data, 0755); err == nil {
|
||||
cachedFrpcPath = tmpPath
|
||||
return tmpPath, nil
|
||||
}
|
||||
// 写入失败时,检查是否已有可用的临时文件
|
||||
if _, statErr := os.Stat(tmpPath); statErr == nil {
|
||||
cachedFrpcPath = tmpPath
|
||||
return tmpPath, nil
|
||||
}
|
||||
return "", fmt.Errorf("写入临时文件失败: %w", err)
|
||||
}
|
||||
|
||||
cachedFrpcPath = tmpPath
|
||||
return tmpPath, nil
|
||||
// ===== 优先级 3:降级到系统 PATH =====
|
||||
path, err := exec.LookPath("frpc")
|
||||
if err == nil {
|
||||
cachedFrpcPath = path
|
||||
return path, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("未找到 frpc 文件 (本地 bin/、embed、PATH 均无)")
|
||||
}
|
||||
|
||||
// GenerateFrpcConfig 生成 frpc.toml 配置文件
|
||||
@@ -116,23 +129,18 @@ func GenerateFrpcConfig() error {
|
||||
Proxies: activeProxies,
|
||||
}
|
||||
|
||||
// ===== 核心改动 =====
|
||||
// 优先使用外部模板文件 frpc.tmpl,如果不存在则使用 embed 中的模板
|
||||
// 优先使用外部模板文件,不存在则用 embed
|
||||
var tmplContent string
|
||||
if _, err := os.Stat("frpc.tmpl"); err == nil {
|
||||
// 外部文件存在,读取它
|
||||
content, readErr := os.ReadFile("frpc.tmpl")
|
||||
if readErr == nil {
|
||||
tmplContent = string(content)
|
||||
} else {
|
||||
// 读取失败时回退到 embed
|
||||
tmplContent = FrpcTemplateContent
|
||||
}
|
||||
} else {
|
||||
// 外部文件不存在,使用 embed 中的模板
|
||||
tmplContent = FrpcTemplateContent
|
||||
}
|
||||
// ===== 核心改动结束 =====
|
||||
|
||||
tmpl, err := template.New("frpc").Parse(tmplContent)
|
||||
if err != nil {
|
||||
@@ -151,38 +159,46 @@ func GenerateFrpcConfig() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartFrpc 启动 frpc(后台运行)
|
||||
// StartFrpc 启动 frpc
|
||||
|
||||
func StartFrpc() error {
|
||||
frpcPath, err := getFrpcPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取 frpc 路径失败: %w", err)
|
||||
}
|
||||
|
||||
// 确保配置文件存在
|
||||
if _, err := os.Stat("./frpc.toml"); os.IsNotExist(err) {
|
||||
if err := GenerateFrpcConfig(); err != nil {
|
||||
return fmt.Errorf("生成配置文件失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否已在运行
|
||||
running, _ := GetFrpcStatus()
|
||||
if running {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command(frpcPath, "-c", "./frpc.toml")
|
||||
if runtime.GOOS == "windows" {
|
||||
setWindowHide(cmd)
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("启动 frpc 失败: %w", err)
|
||||
setWindowHide(cmd)
|
||||
|
||||
// ✅ Linux 下分配伪终端,让 frpc 认为自己在真实终端中运行
|
||||
if runtime.GOOS != "windows" {
|
||||
f, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("启动伪终端失败: %w", err)
|
||||
}
|
||||
// 可选:丢弃 pty 输出,或写入日志文件
|
||||
go io.Copy(io.Discard, f)
|
||||
} else {
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("启动 frpc 失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReloadFrpc 热加载 frpc 配置(仅发信号,不重复写入二进制)
|
||||
// ReloadFrpc 热加载 frpc 配置,失败时自动降级为重启
|
||||
// ReloadFrpc 热加载,失败时自动降级为重启
|
||||
func ReloadFrpc() error {
|
||||
running, err := GetFrpcStatus()
|
||||
if err != nil {
|
||||
@@ -192,14 +208,13 @@ func ReloadFrpc() error {
|
||||
return StartFrpc()
|
||||
}
|
||||
|
||||
if cachedFrpcPath == "" {
|
||||
if _, err := getFrpcPath(); err != nil {
|
||||
return fmt.Errorf("获取 frpc 路径失败: %w", err)
|
||||
}
|
||||
frpcPath, err := getFrpcPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取 frpc 路径失败: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(cachedFrpcPath, "reload", "-c", "./frpc.toml")
|
||||
_, err = cmd.CombinedOutput() // ← 这里改了
|
||||
cmd := exec.Command(frpcPath, "reload", "-c", "./frpc.toml")
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("⚠️ 热加载失败 (%v),自动降级为重启 frpc", err)
|
||||
if stopErr := StopFrpc(); stopErr != nil {
|
||||
|
||||
Reference in New Issue
Block a user