add branch v1
This commit is contained in:
parent
5d370e1077
commit
01b8951dd5
53 changed files with 1079 additions and 6481 deletions
178
config/config.go
178
config/config.go
|
@ -7,122 +7,156 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Config holds all configuration for the application
|
||||
// Config holds all configuration for our application
|
||||
type Config struct {
|
||||
Server ServerConfig `mapstructure:"server"`
|
||||
Database DatabaseConfig `mapstructure:"database"`
|
||||
JWT JWTConfig `mapstructure:"jwt"`
|
||||
WeChat WeChatConfig `mapstructure:"wechat"`
|
||||
Server ServerConfig
|
||||
Database DatabaseConfig
|
||||
Security SecurityConfig
|
||||
CORS CORSConfig
|
||||
Wechat WechatConfig
|
||||
}
|
||||
|
||||
// ServerConfig holds all server related configuration
|
||||
type ServerConfig struct {
|
||||
Host string `mapstructure:"host"`
|
||||
Port int `mapstructure:"port"`
|
||||
ReadTimeout time.Duration `mapstructure:"read_timeout"`
|
||||
WriteTimeout time.Duration `mapstructure:"write_timeout"`
|
||||
ShutdownTimeout time.Duration `mapstructure:"shutdown_timeout"`
|
||||
Timeout time.Duration `mapstructure:"timeout"` // Request processing timeout
|
||||
Port int
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// DatabaseConfig holds all database related configuration
|
||||
type DatabaseConfig struct {
|
||||
Driver string `mapstructure:"driver"`
|
||||
DSN string `mapstructure:"dsn"`
|
||||
MaxOpenConns int `mapstructure:"max_open_conns"`
|
||||
MaxIdleConns int `mapstructure:"max_idle_conns"`
|
||||
MaxLifetime time.Duration `mapstructure:"max_lifetime"`
|
||||
SkipMigration bool `mapstructure:"skip_migration"`
|
||||
Driver string
|
||||
SQLite SQLiteConfig
|
||||
Postgres PostgresConfig
|
||||
}
|
||||
|
||||
// JWTConfig holds all JWT related configuration
|
||||
type JWTConfig struct {
|
||||
Secret string `mapstructure:"secret"`
|
||||
ExpireDelta time.Duration `mapstructure:"expire_delta"`
|
||||
RefreshDelta time.Duration `mapstructure:"refresh_delta"`
|
||||
SigningMethod string `mapstructure:"signing_method"`
|
||||
Issuer string `mapstructure:"issuer"`
|
||||
Audience string `mapstructure:"audience"`
|
||||
// SQLiteConfig holds SQLite specific configuration
|
||||
type SQLiteConfig struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
// WeChatConfig holds all WeChat related configuration
|
||||
type WeChatConfig struct {
|
||||
// PostgresConfig holds PostgreSQL specific configuration
|
||||
type PostgresConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
User string
|
||||
Password string
|
||||
DBName string
|
||||
SSLMode string
|
||||
}
|
||||
|
||||
// SecurityConfig holds all security related configuration
|
||||
type SecurityConfig struct {
|
||||
EncryptionKey string
|
||||
JWTSigningKey string
|
||||
TokenExpiry time.Duration
|
||||
RefreshTokenExpiry time.Duration
|
||||
}
|
||||
|
||||
// CORSConfig holds CORS related configuration
|
||||
type CORSConfig struct {
|
||||
AllowedOrigins []string
|
||||
AllowedMethods []string
|
||||
AllowedHeaders []string
|
||||
}
|
||||
|
||||
// WechatConfig holds WeChat related configuration
|
||||
type WechatConfig struct {
|
||||
AppID string `mapstructure:"app_id"`
|
||||
AppSecret string `mapstructure:"app_secret"`
|
||||
}
|
||||
|
||||
// LoadConfig loads the configuration from file and environment variables
|
||||
func LoadConfig() (*Config, error) {
|
||||
// Set default values
|
||||
setDefaults()
|
||||
// LoadConfig reads configuration from file or environment variables
|
||||
func LoadConfig(configPath string) (*Config, error) {
|
||||
v := viper.New()
|
||||
|
||||
// Read config file
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
v.SetConfigName("config")
|
||||
v.SetConfigType("yaml")
|
||||
v.AddConfigPath(configPath)
|
||||
v.AddConfigPath(".")
|
||||
|
||||
// Read environment variables
|
||||
v.AutomaticEnv()
|
||||
|
||||
// Allow environment variables to override config file
|
||||
v.SetEnvPrefix("OTP")
|
||||
v.BindEnv("security.encryption_key", "OTP_ENCRYPTION_KEY")
|
||||
v.BindEnv("security.jwt_signing_key", "OTP_JWT_SIGNING_KEY")
|
||||
v.BindEnv("database.postgres.password", "OTP_DB_PASSWORD")
|
||||
v.BindEnv("wechat.app_id", "OTP_WECHAT_APPID")
|
||||
v.BindEnv("wechat.app_secret", "OTP_WECHAT_SECRET")
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := viper.Unmarshal(&config); err != nil {
|
||||
if err := v.Unmarshal(&config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||
}
|
||||
|
||||
// Validate config
|
||||
// Validate required configurations
|
||||
if err := validateConfig(&config); err != nil {
|
||||
return nil, fmt.Errorf("invalid configuration: %w", err)
|
||||
return nil, fmt.Errorf("config validation failed: %w", err)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// setDefaults sets default values for configuration
|
||||
func setDefaults() {
|
||||
// Server defaults
|
||||
viper.SetDefault("server.port", 8080)
|
||||
viper.SetDefault("server.read_timeout", "15s")
|
||||
viper.SetDefault("server.write_timeout", "15s")
|
||||
viper.SetDefault("server.shutdown_timeout", "5s")
|
||||
viper.SetDefault("server.timeout", "30s") // Default request processing timeout
|
||||
|
||||
// Database defaults
|
||||
viper.SetDefault("database.driver", "sqlite3")
|
||||
viper.SetDefault("database.max_open_conns", 1) // SQLite only needs 1 connection
|
||||
viper.SetDefault("database.max_idle_conns", 1) // SQLite only needs 1 connection
|
||||
viper.SetDefault("database.max_lifetime", "0") // SQLite doesn't benefit from connection recycling
|
||||
viper.SetDefault("database.skip_migration", false)
|
||||
|
||||
// JWT defaults
|
||||
viper.SetDefault("jwt.expire_delta", "24h")
|
||||
viper.SetDefault("jwt.refresh_delta", "168h") // 7 days
|
||||
viper.SetDefault("jwt.signing_method", "HS256")
|
||||
viper.SetDefault("jwt.issuer", "otpm")
|
||||
viper.SetDefault("jwt.audience", "otpm-client")
|
||||
}
|
||||
|
||||
// validateConfig validates the configuration
|
||||
// validateConfig ensures all required configuration values are provided
|
||||
func validateConfig(config *Config) error {
|
||||
if config.Server.Port < 1 || config.Server.Port > 65535 {
|
||||
return fmt.Errorf("invalid port number: %d", config.Server.Port)
|
||||
if config.Security.EncryptionKey == "" {
|
||||
return fmt.Errorf("encryption key is required")
|
||||
}
|
||||
|
||||
if config.Security.JWTSigningKey == "" {
|
||||
return fmt.Errorf("JWT signing key is required")
|
||||
}
|
||||
|
||||
if config.Database.Driver == "" {
|
||||
return fmt.Errorf("database driver is required")
|
||||
}
|
||||
|
||||
if config.Database.DSN == "" {
|
||||
return fmt.Errorf("database DSN is required")
|
||||
switch config.Database.Driver {
|
||||
case "sqlite3":
|
||||
if config.Database.SQLite.Path == "" {
|
||||
return fmt.Errorf("SQLite database path is required")
|
||||
}
|
||||
case "postgres":
|
||||
if config.Database.Postgres.Host == "" ||
|
||||
config.Database.Postgres.User == "" ||
|
||||
config.Database.Postgres.Password == "" ||
|
||||
config.Database.Postgres.DBName == "" {
|
||||
return fmt.Errorf("incomplete PostgreSQL configuration")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported database driver: %s", config.Database.Driver)
|
||||
}
|
||||
|
||||
if config.JWT.Secret == "" {
|
||||
return fmt.Errorf("JWT secret is required")
|
||||
}
|
||||
|
||||
if config.WeChat.AppID == "" {
|
||||
// Validate WeChat configuration
|
||||
if config.Wechat.AppID == "" {
|
||||
return fmt.Errorf("WeChat AppID is required")
|
||||
}
|
||||
|
||||
if config.WeChat.AppSecret == "" {
|
||||
if config.Wechat.AppSecret == "" {
|
||||
return fmt.Errorf("WeChat AppSecret is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDSN returns the appropriate database connection string based on the driver
|
||||
func (c *DatabaseConfig) GetDSN() string {
|
||||
switch c.Driver {
|
||||
case "sqlite3":
|
||||
return c.SQLite.Path
|
||||
case "postgres":
|
||||
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
|
||||
c.Postgres.Host,
|
||||
c.Postgres.Port,
|
||||
c.Postgres.User,
|
||||
c.Postgres.Password,
|
||||
c.Postgres.DBName,
|
||||
c.Postgres.SSLMode)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue