otpm/config/config.go
“xHuPo” bcd986e3f7 beta
2025-05-23 18:57:11 +08:00

128 lines
3.9 KiB
Go

package config
import (
"fmt"
"time"
"github.com/spf13/viper"
)
// Config holds all configuration for the application
type Config struct {
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
JWT JWTConfig `mapstructure:"jwt"`
WeChat WeChatConfig `mapstructure:"wechat"`
}
// 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
}
// 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"`
}
// 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"`
}
// WeChatConfig holds all 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()
// Read config file
if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
var config Config
if err := viper.Unmarshal(&config); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
// Validate config
if err := validateConfig(&config); err != nil {
return nil, fmt.Errorf("invalid configuration: %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", 25)
viper.SetDefault("database.max_idle_conns", 25)
viper.SetDefault("database.max_lifetime", "5m")
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
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.Database.Driver == "" {
return fmt.Errorf("database driver is required")
}
if config.Database.DSN == "" {
return fmt.Errorf("database DSN is required")
}
if config.JWT.Secret == "" {
return fmt.Errorf("JWT secret is required")
}
if config.WeChat.AppID == "" {
return fmt.Errorf("WeChat AppID is required")
}
if config.WeChat.AppSecret == "" {
return fmt.Errorf("WeChat AppSecret is required")
}
return nil
}