Files
2026-08-30 21:25:22 +08:00

107 lines
3.0 KiB
Go

package configs
import (
"fmt"
"os"
"strings"
"time"
"github.com/spf13/viper"
)
type Config struct {
Server ServerConfig `mapstructure:"server"`
Redis RedisConfig `mapstructure:"redis"`
RateLimit RateLimitConfig `mapstructure:"rate_limit"`
Session SessionConfig `mapstructure:"session"`
Log LogConfig `mapstructure:"log"`
CORS CORSConfig `mapstructure:"cors"`
}
type ServerConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
ReadTimeout time.Duration `mapstructure:"read_timeout"`
WriteTimeout time.Duration `mapstructure:"write_timeout"`
IdleTimeout time.Duration `mapstructure:"idle_timeout"`
}
type RedisConfig struct {
Addr string `mapstructure:"addr"`
Password string `mapstructure:"password"`
DB int `mapstructure:"db"`
PoolSize int `mapstructure:"pool_size"`
}
type RateLimitConfig struct {
GlobalRPS float64 `mapstructure:"global_rps"`
PerIPRPS float64 `mapstructure:"per_ip_rps"`
PerIPBurst int `mapstructure:"burst"`
}
type SessionConfig struct {
TTL int `mapstructure:"ttl"`
MaxTextLength int `mapstructure:"max_text_length"`
}
type LogConfig struct {
Level string `mapstructure:"level"`
Format string `mapstructure:"format"`
}
type CORSConfig struct {
AllowedOrigins []string `mapstructure:"allowed_origins"`
}
func Load(configPath ...string) (*Config, error) {
v := viper.New()
if len(configPath) > 0 && configPath[0] != "" {
v.SetConfigFile(configPath[0])
} else {
v.SetConfigName("config")
v.SetConfigType("yaml")
v.AddConfigPath("configs/")
v.AddConfigPath("./configs/")
v.AddConfigPath(".")
}
v.SetDefault("server.host", "0.0.0.0")
v.SetDefault("server.port", 8080)
v.SetDefault("server.read_timeout", "15s")
v.SetDefault("server.write_timeout", "15s")
v.SetDefault("server.idle_timeout", "60s")
v.SetDefault("redis.addr", "localhost:6379")
v.SetDefault("redis.db", 0)
v.SetDefault("redis.pool_size", 100)
v.SetDefault("rate_limit.global_rps", 1000)
v.SetDefault("rate_limit.per_ip_rps", 50)
v.SetDefault("rate_limit.burst", 100)
v.SetDefault("session.ttl", 604800)
v.SetDefault("session.max_text_length", 10000)
v.SetDefault("log.level", "info")
v.SetDefault("log.format", "json")
// 环境变量覆盖(前缀 DUALCHECK_)
// mapstructure 的 "." 和 "_" 都需要替换成 "_",并转大写
v.SetEnvPrefix("DUALCHECK")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
v.AutomaticEnv()
// 尝试读取配置文件(文件不存在不报错,用默认值+环境变量)
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
fmt.Fprintf(os.Stderr, "[config] warning: config file error: %v\n", err)
} else {
fmt.Fprintf(os.Stderr, "[config] config file not found, using defaults + env vars\n")
}
}
var cfg Config
if err := v.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("unmarshal config: %w", err)
}
return &cfg, nil
}