Files
frpc-console/frp.go
T

147 lines
3.0 KiB
Go

package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
"text/template"
)
// frpc.toml 模板 - 完全复制你的配置文件结构
const frpcTemplate = `serverAddr = "{{.ServerAddr}}"
serverPort = {{.ServerPort}}
[auth]
token = "{{.Token}}"
[log]
to = "./frpc.log"
level = "{{.LogLevel}}"
maxDays = {{.LogMaxDays}}
[transport]
tcpMux = {{.TcpMux}}
tcpMuxKeepaliveInterval = {{.TcpMuxKeepalive}}
heartbeatInterval = {{.HeartbeatInterval}}
heartbeatTimeout = {{.HeartbeatTimeout}}
poolCount = {{.PoolCount}}
{{range .Proxies}}
[[proxies]]
name = "{{.Name}}"
type = "{{.Type}}"
localIP = "{{.LocalIP}}"
localPort = {{.LocalPort}}
remotePort = {{.RemotePort}}
{{end}}`
// 生成 frpc.toml 文件
func GenerateFrpcConfig() error {
// 1. 读取全局配置
cfg, err := GetGlobalConfig()
if err != nil {
return fmt.Errorf("读取全局配置失败: %w", err)
}
// 2. 读取所有启用的隧道
proxies, err := GetProxies()
if err != nil {
return fmt.Errorf("读取隧道列表失败: %w", err)
}
var activeProxies []Proxy
for _, p := range proxies {
if p.Enabled {
activeProxies = append(activeProxies, p)
}
}
// 3. 组合数据
data := struct {
*GlobalConfig
Proxies []Proxy
}{
GlobalConfig: cfg,
Proxies: activeProxies,
}
// 4. 渲染模板
tmpl, err := template.New("frpc").Parse(frpcTemplate)
if err != nil {
return fmt.Errorf("解析模板失败: %w", err)
}
var buf bytes.Buffer
err = tmpl.Execute(&buf, data)
if err != nil {
return fmt.Errorf("渲染模板失败: %w", err)
}
// 5. 写入文件
err = os.WriteFile("./frpc.toml", buf.Bytes(), 0644)
if err != nil {
return fmt.Errorf("写入配置文件失败: %w", err)
}
return nil
}
// 热加载 frpc
func ReloadFrpc() error {
// 先检查 frpc 进程是否在运行
cmd := exec.Command("pgrep", "-f", "frpc")
output, err := cmd.Output()
if err != nil || len(output) == 0 {
// frpc 没在运行,尝试启动
return StartFrpc()
}
// 执行 reload
reloadCmd := exec.Command("frpc", "reload", "-c", "./frpc.toml")
output, err = reloadCmd.CombinedOutput()
if err != nil {
return fmt.Errorf("reload 失败: %s, %w", string(output), err)
}
return nil
}
// 启动 frpc
func StartFrpc() error {
// 先确保配置文件存在
if _, err := os.Stat("./frpc.toml"); os.IsNotExist(err) {
if err := GenerateFrpcConfig(); err != nil {
return fmt.Errorf("生成配置文件失败: %w", err)
}
}
cmd := exec.Command("frpc", "-c", "./frpc.toml")
// 后台运行,不阻塞
err := cmd.Start()
if err != nil {
return fmt.Errorf("启动 frpc 失败: %w", err)
}
return nil
}
// StopFrpc 停止 frpc
func StopFrpc() error {
cmd := exec.Command("pkill", "-f", "frpc")
err := cmd.Run()
if err != nil && !strings.Contains(err.Error(), "no process") {
return fmt.Errorf("停止 frpc 失败: %w", err)
}
return nil
}
// 检查 frpc 状态
func GetFrpcStatus() (bool, error) {
cmd := exec.Command("pgrep", "-f", "frpc")
output, err := cmd.Output()
if err != nil {
return false, nil
}
return len(output) > 0, nil
}