package config import ( "errors" "fmt" "os" "strings" "github.com/spf13/viper" ) type AMapConfig struct { Key string `mapstructure:"key"` } type Config struct { AMap AMapConfig `mapstructure:"amap"` Server ServerConfig `mapstructure:"server"` Postgres PostgresConfig `mapstructure:"postgres"` MinIO MinIOConfig `mapstructure:"minio"` JWT JWTConfig `mapstructure:"jwt"` WeChat WeChatConfig `mapstructure:"wechat"` Auth AuthConfig `mapstructure:"auth"` Admin AdminConfig `mapstructure:"admin"` } type ServerConfig struct { Port int `mapstructure:"port"` Mode string `mapstructure:"mode"` } type PostgresConfig struct { Host string `mapstructure:"host"` Port int `mapstructure:"port"` User string `mapstructure:"user"` Password string `mapstructure:"password"` Database string `mapstructure:"database"` SSLMode string `mapstructure:"ssl_mode"` } func (p PostgresConfig) DSN() string { return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s TimeZone=Asia/Shanghai", p.Host, p.Port, p.User, p.Password, p.Database, p.SSLMode) } type MinIOConfig struct { Endpoint string `mapstructure:"endpoint"` AccessKey string `mapstructure:"access_key"` SecretKey string `mapstructure:"secret_key"` Bucket string `mapstructure:"bucket"` UseSSL bool `mapstructure:"use_ssl"` } type JWTConfig struct { Secret string `mapstructure:"secret"` ExpireHours int `mapstructure:"expire_hours"` RefreshHours int `mapstructure:"refresh_hours"` } type WeChatConfig struct { AppID string `mapstructure:"app_id"` AppSecret string `mapstructure:"app_secret"` } type AuthConfig struct { DevLogin bool `mapstructure:"dev_login"` } type AdminConfig struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` } func Load() (*Config, error) { v := viper.New() v.SetDefault("amap.key", "") v.SetDefault("server.port", 9090) v.SetDefault("server.mode", "debug") v.SetDefault("postgres.host", "192.168.100.127") v.SetDefault("postgres.port", 5432) v.SetDefault("postgres.user", "root") v.SetDefault("postgres.password", "") v.SetDefault("postgres.database", "sundynix-pets") v.SetDefault("postgres.ssl_mode", "disable") v.SetDefault("minio.endpoint", "https://s3.sundynix.cn") v.SetDefault("minio.access_key", "") v.SetDefault("minio.secret_key", "") v.SetDefault("minio.bucket", "sundynix-pet") v.SetDefault("minio.use_ssl", true) v.SetDefault("jwt.secret", "") v.SetDefault("jwt.expire_hours", 2) v.SetDefault("jwt.refresh_hours", 2) v.SetDefault("wechat.app_id", "") v.SetDefault("wechat.app_secret", "") v.SetDefault("auth.dev_login", false) v.SetDefault("admin.username", "sundynix") v.SetDefault("admin.password", "") v.SetConfigName("config") v.SetConfigType("yaml") v.AddConfigPath("./configs") v.AddConfigPath("../../configs") v.SetEnvPrefix("PETS") v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() if err := v.ReadInConfig(); err != nil { var missing viper.ConfigFileNotFoundError if !errors.As(err, &missing) && !os.IsNotExist(err) { return nil, fmt.Errorf("read config: %w", err) } } var cfg Config if err := v.Unmarshal(&cfg); err != nil { return nil, fmt.Errorf("decode config: %w", err) } if cfg.Postgres.Password == "" || cfg.JWT.Secret == "" { return nil, errors.New("postgres.password and jwt.secret are required") } if cfg.MinIO.AccessKey == "" || cfg.MinIO.SecretKey == "" { return nil, errors.New("minio access_key and secret_key are required") } if cfg.Server.Mode == "release" && cfg.Auth.DevLogin { return nil, errors.New("dev login must be disabled in release mode") } // Access tokens have the same fixed two-hour lifetime for both clients. cfg.JWT.ExpireHours = 2 cfg.JWT.RefreshHours = 2 return &cfg, nil }