package handler import ( "net/http" "os" "path/filepath" "proxy-platform/internal/config" "proxy-platform/internal/models" "proxy-platform/internal/repository" "github.com/gin-gonic/gin" "go.uber.org/zap" "golang.org/x/crypto/bcrypt" "gorm.io/driver/sqlite" "gorm.io/gorm" ) // CheckInstall 检查安装状态 func CheckInstall() gin.HandlerFunc { return func(c *gin.Context) { // 检查数据库是否存在安装记录 dbPath := "data/proxy.db" installed := false if _, err := os.Stat(dbPath); err == nil { // 数据库文件存在,检查安装状态 db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{}) if err == nil { var status models.InstallStatus if result := db.First(&status); result.Error == nil { installed = status.Installed } sqlDB, _ := db.DB() sqlDB.Close() } } c.JSON(http.StatusOK, gin.H{ "installed": installed, }) } } // InstallRequest 安装请求 type InstallRequest struct { DbType string `json:"db_type" binding:"required"` // sqlite, postgres AdminUser string `json:"admin_user" binding:"required"` AdminPass string `json:"admin_pass" binding:"required"` PlatformName string `json:"platform_name"` // SQLite 配置 SqlitePath string `json:"sqlite_path"` // PostgreSQL 配置(可选) PgHost string `json:"pg_host"` PgPort int `json:"pg_port"` PgUser string `json:"pg_user"` PgPassword string `json:"pg_password"` PgDatabase string `json:"pg_database"` // Redis 配置(可选) RedisEnabled bool `json:"redis_enabled"` RedisHost string `json:"redis_host"` RedisPort int `json:"redis_port"` RedisPassword string `json:"redis_password"` RedisDB int `json:"redis_db"` } // DoInstall 执行安装 func DoInstall(logger *zap.Logger) gin.HandlerFunc { return func(c *gin.Context) { var req InstallRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 验证必填项 if req.AdminUser == "" || req.AdminPass == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "用户名和密码不能为空"}) return } if req.DbType != "sqlite" && req.DbType != "postgres" { c.JSON(http.StatusBadRequest, gin.H{"error": "数据库类型只能是 sqlite 或 postgres"}) return } if req.DbType == "postgres" { if req.PgHost == "" || req.PgDatabase == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "PostgreSQL 配置不完整"}) return } } // 确定数据库路径 dbPath := req.SqlitePath if dbPath == "" { dbPath = "data/proxy.db" } // 创建数据目录 dbDir := filepath.Dir(dbPath) if err := os.MkdirAll(dbDir, 0755); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "创建数据目录失败: " + err.Error()}) return } // 初始化数据库 var db *gorm.DB var err error if req.DbType == "sqlite" { db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{}) } else { // PostgreSQL 支持(需要额外配置 postgres driver) c.JSON(http.StatusBadRequest, gin.H{"error": "PostgreSQL 支持需要额外配置,请使用 SQLite"}) return } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库连接失败: " + err.Error()}) return } // 自动迁移 if err := db.AutoMigrate( &models.User{}, &models.Node{}, &models.NodeGroup{}, &models.UnlockStatus{}, &models.IPChangeLog{}, &models.ConnectionLog{}, &models.IPRefreshRule{}, &models.InstallStatus{}, ); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库迁移失败: " + err.Error()}) return } // 创建管理员用户 hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.AdminPass), bcrypt.DefaultCost) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"}) return } adminUser := &models.User{ Username: req.AdminUser, PasswordHash: string(hashedPassword), Status: "active", TrafficQuota: 0, // 无限制 } userRepo := repository.NewUserRepository(db) if err := userRepo.Create(adminUser); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "创建管理员失败: " + err.Error()}) return } // 创建安装状态记录 platformName := req.PlatformName if platformName == "" { platformName = "代理管理平台" } installStatus := &models.InstallStatus{ Installed: true, DbType: req.DbType, RedisEnabled: req.RedisEnabled, AdminUser: req.AdminUser, PlatformName: platformName, } if err := db.Create(installStatus).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存安装状态失败: " + err.Error()}) return } // 生成配置文件 cfg := &config.Config{ Server: config.ServerConfig{ Host: "0.0.0.0", Port: 8080, Mode: "release", }, SOCKS5: config.SOCKS5Config{ Host: "0.0.0.0", Port: 1080, MaxConnections: 10000, Timeout: 30, }, Database: config.DatabaseConfig{ Type: req.DbType, Path: dbPath, }, Redis: config.RedisConfig{ Enabled: req.RedisEnabled, Host: req.RedisHost, Port: req.RedisPort, Password: req.RedisPassword, DB: req.RedisDB, }, Scheduler: config.SchedulerConfig{ Strategy: "least_latency", HealthCheckInterval: 60, UnlockCheckInterval: 300, NodeTimeout: 120, }, Logging: config.LoggingConfig{ Level: "info", Output: "stdout", }, Install: config.InstallConfig{ Installed: true, }, } // 保存配置文件 configPath := "configs/scheduler.yaml" if err := config.Save(configPath, cfg); err != nil { logger.Error("保存配置文件失败", zap.Error(err)) } // 关闭数据库连接 sqlDB, _ := db.DB() sqlDB.Close() logger.Info("安装完成", zap.String("db_type", req.DbType), zap.Bool("redis_enabled", req.RedisEnabled), zap.String("admin_user", req.AdminUser), ) c.JSON(http.StatusOK, gin.H{ "message": "安装成功", "db_type": req.DbType, "redis_enabled": req.RedisEnabled, "admin_user": req.AdminUser, }) } } // GetInstallStatus 获取安装状态(从数据库) func GetInstallStatus(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var status models.InstallStatus if result := db.First(&status); result.Error != nil { c.JSON(http.StatusOK, gin.H{ "installed": false, }) return } c.JSON(http.StatusOK, gin.H{ "installed": status.Installed, "db_type": status.DbType, "redis_enabled": status.RedisEnabled, "platform_name": status.PlatformName, "admin_user": status.AdminUser, }) } }