package config import ( "fmt" "os" "github.com/spf13/viper" ) type Config struct { Server ServerConfig Database DatabaseConfig Redis RedisConfig JWT JWTConfig Captcha CaptchaConfig } type ServerConfig struct { Host string Port int Mode string } type DatabaseConfig struct { Type string // sqlite or mysql Host string Port int User string Password string Database string SQLite SQLiteConfig } type SQLiteConfig struct { Path string } type RedisConfig struct { Enabled bool Host string Port int Password string DB int } type JWTConfig struct { Secret string ExpireTime int // hours } type CaptchaConfig struct { ModelPath string } var Cfg *Config func Load(configPath string) error { viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AddConfigPath(".") viper.AddConfigPath("./data") viper.AddConfigPath(configPath) // 默认值 viper.SetDefault("server.host", "0.0.0.0") viper.SetDefault("server.port", 6688) viper.SetDefault("server.mode", "release") viper.SetDefault("database.type", "sqlite") viper.SetDefault("database.sqlite.path", "./data/app.db") viper.SetDefault("database.host", "localhost") viper.SetDefault("database.port", 3306) viper.SetDefault("redis.enabled", false) viper.SetDefault("redis.host", "localhost") viper.SetDefault("redis.port", 6379) viper.SetDefault("redis.db", 0) viper.SetDefault("jwt.expire_time", 1440) // 60 days viper.SetDefault("captcha.model_path", "./models") if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { return fmt.Errorf("配置文件未找到,请先运行安装向导") } return err } Cfg = &Config{} if err := viper.Unmarshal(Cfg); err != nil { return err } // 从环境变量读取 JWT Secret if secret := os.Getenv("JWT_SECRET"); secret != "" { Cfg.JWT.Secret = secret } return nil } func Save(cfg *Config) error { // 确保 data 目录存在 if err := os.MkdirAll("./data", 0755); err != nil { return fmt.Errorf("创建数据目录失败: %w", err) } viper.Set("server", cfg.Server) viper.Set("database", cfg.Database) viper.Set("redis", cfg.Redis) viper.Set("jwt", cfg.JWT) viper.Set("captcha", cfg.Captcha) // 使用 SafeWriteConfig,如果文件不存在会自动创建 configPath := "./data/config.yaml" viper.SetConfigFile(configPath) // 检查文件是否存在,不存在则创建 if _, err := os.Stat(configPath); os.IsNotExist(err) { if err := viper.SafeWriteConfig(); err != nil { return fmt.Errorf("创建配置文件失败: %w", err) } return nil } // 文件已存在,直接写入 return viper.WriteConfig() } func IsInstalled() bool { _, err := os.Stat("./data/config.yaml") return err == nil }