162 lines
3.9 KiB
Go
162 lines
3.9 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// Config holds all configuration for our application
|
|
type Config struct {
|
|
Server ServerConfig
|
|
Database DatabaseConfig
|
|
Security SecurityConfig
|
|
CORS CORSConfig
|
|
Wechat WechatConfig
|
|
}
|
|
|
|
// ServerConfig holds all server related configuration
|
|
type ServerConfig struct {
|
|
Port int
|
|
Timeout time.Duration
|
|
}
|
|
|
|
// DatabaseConfig holds all database related configuration
|
|
type DatabaseConfig struct {
|
|
Driver string
|
|
SQLite SQLiteConfig
|
|
Postgres PostgresConfig
|
|
}
|
|
|
|
// SQLiteConfig holds SQLite specific configuration
|
|
type SQLiteConfig struct {
|
|
Path string
|
|
}
|
|
|
|
// 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 reads configuration from file or environment variables
|
|
func LoadConfig(configPath string) (*Config, error) {
|
|
v := viper.New()
|
|
|
|
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 := v.Unmarshal(&config); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
|
}
|
|
|
|
// Validate required configurations
|
|
if err := validateConfig(&config); err != nil {
|
|
return nil, fmt.Errorf("config validation failed: %w", err)
|
|
}
|
|
|
|
return &config, nil
|
|
}
|
|
|
|
// validateConfig ensures all required configuration values are provided
|
|
func validateConfig(config *Config) error {
|
|
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")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
// Validate WeChat configuration
|
|
if config.Wechat.AppID == "" {
|
|
return fmt.Errorf("WeChat AppID is required")
|
|
}
|
|
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 ""
|
|
}
|
|
}
|