package main import ( "context" "log" "os" "strings" "time" "frpc-console/internal/api" "frpc-console/internal/db" "frpc-console/internal/frp" "frpc-console/internal/process" ) func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) // ============================================================ // 1. 初始化数据目录 // ============================================================ if err := os.MkdirAll("./data", 0755); err != nil { log.Printf("⚠️ 创建 data 目录失败: %v", err) } // ============================================================ // 2. 显示版本信息 // ============================================================ if data, err := os.ReadFile("./data/version.ini"); err == nil { version := strings.TrimSpace(string(data)) log.Printf("📌 版本: %s", version) } else { log.Printf("📌 版本: (未记录)") } // ============================================================ // 3. 初始化数据库 // ============================================================ if err := db.InitDB(); err != nil { log.Fatal("❌ 数据库初始化失败:", err) } // ============================================================ // 4. 生成 frpc 配置文件 // ============================================================ if err := frp.GenerateConfig(); err != nil { log.Println("⚠️ 生成配置文件失败:", err) } // ============================================================ // 5. 创建进程管理器并启动 frpc // ============================================================ pm := process.NewManager("./data", "./data/frpc.toml") process.SetGlobalManager(pm) // 加载 admin_port 配置 if err := pm.LoadConfig(); err != nil { log.Printf("⚠️ 加载 admin_port 配置失败: %v (将使用 PID 文件模式)", err) } else { log.Printf("📌 admin_port: %d", pm.AdminPort()) } // 启动 frpc (幂等) ctx := context.Background() if err := pm.Start(ctx); err != nil { log.Printf("⚠️ 启动 frpc 失败: %v", err) } else { if status, err := pm.Status(); err == nil { log.Printf("✅ frpc 状态: %s", status.State) if status.PID > 0 { log.Printf(" PID: %d, 端口: %d", status.PID, status.Port) } } } // ============================================================ // 6. 启动看门狗 (自动恢复) // ============================================================ go startWatchdog(pm) // ============================================================ // 7. 启动 HTTP 服务 // ============================================================ router := api.SetupRouter() log.Println("🚀 frpc-console 启动成功!") log.Println("📍 访问地址: http://localhost:9300") log.Println("📍 API 地址: http://localhost:9300/api") if err := router.Run(":9300"); err != nil { log.Fatal("❌ 服务启动失败:", err) } } // ================================================================ // 看门狗 // ================================================================ func startWatchdog(pm *process.Manager) { ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() for range ticker.C { status, err := pm.Status() if err != nil { log.Printf("⚠️ 检查 frpc 状态失败: %v", err) continue } if status.State != "running" { log.Printf("⚠️ frpc 进程已停止 (状态: %s),自动重启...", status.State) ctx := context.Background() if err := pm.Start(ctx); err != nil { log.Printf("❌ 自动重启 frpc 失败: %v", err) } else { log.Println("✅ frpc 已自动重启") } } } }