2.6-Preview最后一批代码上线

This commit is contained in:
2026-08-07 21:18:28 +08:00
parent 41eb21f512
commit d7c27c513c
12 changed files with 322 additions and 122 deletions
+57 -27
View File
@@ -1,4 +1,4 @@
// process/manager.go
// internal/process/manager.go
// frpc-console 进程管理模块
// 2.6-preview: 端口检测 + 单实例锁定 + 状态自述
@@ -11,6 +11,7 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
"os"
@@ -41,7 +42,6 @@ const (
// 数据结构
// ================================================================
// PortStatus 端口检测结果
type PortStatus struct {
Port int `json:"port"`
Occupied bool `json:"occupied"`
@@ -50,17 +50,15 @@ type PortStatus struct {
ProcessCmd string `json:"process_cmd,omitempty"`
}
// ProcessStatus frpc 进程状态
type ProcessStatus struct {
State string `json:"state"` // "running" | "stopped" | "unknown" | "conflict"
PID int `json:"pid"` // 进程 PID (如果运行中)
Port int `json:"port"` // 监听的端口
State string `json:"state"`
PID int `json:"pid"`
Port int `json:"port"`
Uptime string `json:"uptime,omitempty"`
Version string `json:"version,omitempty"`
Error string `json:"error,omitempty"`
}
// FRPCStatus 来自 frpc admin API 的状态响应
type FRPCStatus struct {
Version string `json:"version"`
RunID string `json:"run_id"`
@@ -91,7 +89,6 @@ var (
globalMu sync.Mutex
)
// NewManager 创建进程管理器
func NewManager(dataDir, configPath, frpcBinPath string) *ProcessManager {
return &ProcessManager{
dataDir: dataDir,
@@ -101,48 +98,62 @@ func NewManager(dataDir, configPath, frpcBinPath string) *ProcessManager {
}
}
// SetGlobalManager 设置全局管理器
func SetGlobalManager(pm *ProcessManager) {
globalMu.Lock()
defer globalMu.Unlock()
globalManager = pm
}
// GetGlobalManager 获取全局管理器
func GetGlobalManager() *ProcessManager {
globalMu.Lock()
defer globalMu.Unlock()
return globalManager
}
// AdminPort 获取 admin_port
func (pm *ProcessManager) AdminPort() int {
return pm.adminPort
}
// ================================================================
// 配置读取
// 配置读取 (带调试日志)
// ================================================================
// LoadConfig 从 frpc.toml 读取 admin_port 配置
// 兼容 frp 0.52.0 前后的配置格式
func (pm *ProcessManager) LoadConfig() error {
content, err := os.ReadFile(pm.configPath)
if err != nil {
return fmt.Errorf("读取配置文件失败: %w", err)
}
log.Printf("[DEBUG] LoadConfig 读取到文件,长度: %d 字节", len(content))
preview := string(content)
if len(preview) > 600 {
preview = preview[:600] + "\n... (截断)"
}
log.Printf("[DEBUG] 文件内容预览:\n%s", preview)
if port := extractIntValue(string(content), "admin_port"); port > 0 {
pm.adminPort = port
log.Printf("[DEBUG] ✅ 从 admin_port 解析到端口: %d", port)
return nil
}
log.Printf("[DEBUG] ❌ admin_port 未找到")
if port := extractIntValueFromSection(string(content), "webServer", "port"); port > 0 {
pm.adminPort = port
log.Printf("[DEBUG] ✅ 从 webServer.port 解析到端口: %d", port)
return nil
}
log.Printf("[DEBUG] ❌ webServer.port 未找到")
return fmt.Errorf("未找到 admin_port 或 webServer.port 配置")
if port := extractPortFromAddrSection(string(content), "webServer", "addr"); port > 0 {
pm.adminPort = port
log.Printf("[DEBUG] ✅ 从 webServer.addr 解析到端口: %d", port)
return nil
}
log.Printf("[DEBUG] ❌ webServer.addr 未找到或解析失败")
return fmt.Errorf("未找到 admin_port 或 webServer.port/addr 配置")
}
func extractIntValue(content, key string) int {
@@ -169,7 +180,8 @@ func extractIntValueFromSection(content, section, key string) int {
for _, line := range lines {
trimmed := strings.TrimSpace(line)
if strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]") {
inSection = strings.Trim(trimmed, "[]") == section
sectionName := strings.TrimSpace(strings.Trim(trimmed, "[]"))
inSection = strings.EqualFold(sectionName, section)
continue
}
if inSection && strings.HasPrefix(trimmed, key) {
@@ -186,14 +198,40 @@ func extractIntValueFromSection(content, section, key string) int {
return 0
}
func extractPortFromAddrSection(content, section, key string) int {
lines := strings.Split(content, "\n")
inSection := false
for _, line := range lines {
trimmed := strings.TrimSpace(line)
if strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]") {
sectionName := strings.TrimSpace(strings.Trim(trimmed, "[]"))
inSection = strings.EqualFold(sectionName, section)
continue
}
if inSection && strings.HasPrefix(trimmed, key) {
parts := strings.SplitN(trimmed, "=", 2)
if len(parts) == 2 {
val := strings.TrimSpace(parts[1])
val = strings.Trim(val, `"`)
if idx := strings.LastIndex(val, ":"); idx != -1 {
portStr := val[idx+1:]
if port, err := strconv.Atoi(portStr); err == nil && port > 0 {
return port
}
}
}
}
}
return 0
}
// ================================================================
// 端口检测
// ================================================================
// CheckPort 检测端口是否被占用
func (pm *ProcessManager) CheckPort() (bool, error) {
if pm.adminPort <= 0 {
return false, fmt.Errorf("admin_port 未配置")
return false, fmt.Errorf("admin_port 未配置 (当前值: %d)", pm.adminPort)
}
conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", pm.adminPort), PortCheckTimeout)
if err != nil {
@@ -203,7 +241,6 @@ func (pm *ProcessManager) CheckPort() (bool, error) {
return true, nil
}
// GetPortStatus 获取端口完整状态 (占用 + PID + 进程类型)
func (pm *ProcessManager) GetPortStatus() (*PortStatus, error) {
status := &PortStatus{Port: pm.adminPort, Occupied: false, PID: 0, IsFRPC: false}
occupied, err := pm.CheckPort()
@@ -389,11 +426,10 @@ func (pm *ProcessManager) deletePIDFile() error {
// 状态查询
// ================================================================
// Status 获取 frpc 进程实时状态
func (pm *ProcessManager) Status() (*ProcessStatus, error) {
status := &ProcessStatus{State: "unknown", PID: 0, Port: pm.adminPort}
if pm.adminPort <= 0 {
status.Error = "admin_port 未配置"
status.Error = fmt.Sprintf("admin_port 未配置 (当前值: %d)", pm.adminPort)
return status, nil
}
portStatus, err := pm.GetPortStatus()
@@ -460,7 +496,6 @@ func (pm *ProcessManager) getFRPCStatus(pid int) *FRPCStatus {
// 操作执行 (Start / Stop / Restart)
// ================================================================
// Start 启动 frpc (幂等)
func (pm *ProcessManager) Start(ctx context.Context) error {
if err := pm.Lock(); err != nil {
return fmt.Errorf("获取锁失败: %w", err)
@@ -483,10 +518,7 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
}
cmd := exec.CommandContext(ctx, pm.frpcBinPath, "-c", pm.configPath)
// 设置进程属性 (平台相关)
setProcessAttributes(cmd)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -508,7 +540,6 @@ func (pm *ProcessManager) startLocked(ctx context.Context) error {
return nil
}
// Stop 停止 frpc (幂等)
func (pm *ProcessManager) Stop(ctx context.Context) error {
if err := pm.Lock(); err != nil {
return fmt.Errorf("获取锁失败: %w", err)
@@ -565,7 +596,6 @@ func (pm *ProcessManager) stopLocked(ctx context.Context) error {
return nil
}
// Restart 重启 frpc (原子操作)
func (pm *ProcessManager) Restart(ctx context.Context) error {
if err := pm.Lock(); err != nil {
return fmt.Errorf("获取锁失败: %w", err)