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 } const dataDir = "/app/data" func Save(cfg *Config) error { // 确保 data 目录存在 if err := os.MkdirAll(dataDir, 0755); err != nil { return fmt.Errorf("创建数据目录失败: %w", err) } // 直接写入配置文件 configPath := dataDir + "/config.yaml" // 构建 YAML 内容 content := fmt.Sprintf(`server: host: %s port: %d mode: %s database: type: %s host: %s port: %d user: %s password: %s database: %s sqlite: path: %s redis: enabled: %v host: %s port: %d password: %s db: %d jwt: secret: %s expire_time: %d captcha: model_path: %s `, cfg.Server.Host, cfg.Server.Port, cfg.Server.Mode, cfg.Database.Type, cfg.Database.Host, cfg.Database.Port, cfg.Database.User, cfg.Database.Password, cfg.Database.Database, cfg.Database.SQLite.Path, cfg.Redis.Enabled, cfg.Redis.Host, cfg.Redis.Port, cfg.Redis.Password, cfg.Redis.DB, cfg.JWT.Secret, cfg.JWT.ExpireTime, cfg.Captcha.ModelPath, ) if err := os.WriteFile(configPath, []byte(content), 0644); err != nil { return fmt.Errorf("写入配置文件失败: %w", err) } return nil } func IsInstalled() bool { _, err := os.Stat(dataDir + "/config.yaml") return err == nil }