package config import ( "strings" "time" "git.yuntuo.hk/k2safe/go-omni/httpx" "git.yuntuo.hk/k2safe/go-omni/logx" ) const defaultRequestIDHeader = "X-Request-ID" // Config controls the default runtime behavior of an App. type Config struct { Address string RequestIDHeader string EnableLogger bool TrustedProxies []string ShutdownTimeout time.Duration Log logx.Config } func Default() Config { return Config{ Address: ":8080", RequestIDHeader: defaultRequestIDHeader, ShutdownTimeout: 10 * time.Second, Log: logx.Default(), } } // Validate checks configuration values before an application starts. func (c Config) Validate() error { if strings.TrimSpace(c.Address) == "" { return &ConfigError{Field: "address", Message: "is required"} } if strings.TrimSpace(c.RequestIDHeader) == "" { return &ConfigError{Field: "request_id_header", Message: "is required"} } if c.ShutdownTimeout <= 0 { return &ConfigError{Field: "shutdown_timeout", Message: "must be positive"} } if _, err := httpx.NewClientIPResolver(c.TrustedProxies...); err != nil { return &ConfigError{Field: "trusted_proxies", Message: err.Error()} } return nil } // ConfigError describes an invalid application configuration field. type ConfigError struct { Field string Message string } func (e *ConfigError) Error() string { return "config " + e.Field + " " + e.Message } // Option changes an App's configuration. type Option func(*Config) // WithRequestIDHeader changes the header used to read and return request IDs. func WithRequestIDHeader(header string) Option { return func(cfg *Config) { if value := strings.TrimSpace(header); value != "" { cfg.RequestIDHeader = value } } } // WithLogger enables GoOmni's structured access logger. func WithLogger(enabled bool) Option { return func(cfg *Config) { cfg.EnableLogger = enabled } } // WithTrustedProxies allows only these IPs/CIDRs to supply X-Forwarded-For. // An empty list disables forwarding-header trust. Invalid entries are rejected // by Config.Validate and panic when passed directly to App.New. func WithTrustedProxies(proxies ...string) Option { proxies = append([]string(nil), proxies...) return func(cfg *Config) { cfg.TrustedProxies = append([]string(nil), proxies...) } } // WithConfig applies a complete configuration loaded from a file or // environment. Later options can still override individual fields. func WithConfig(settings Config) Option { settings.TrustedProxies = append([]string(nil), settings.TrustedProxies...) return func(cfg *Config) { *cfg = settings cfg.TrustedProxies = append([]string(nil), settings.TrustedProxies...) } } // WithLogConfig configures the logger used by the application runtime. func WithLogConfig(settings logx.Config) Option { return func(cfg *Config) { cfg.Log = settings } } // WithShutdownTimeout controls how long RunContext waits for active requests. func WithShutdownTimeout(timeout time.Duration) Option { return func(cfg *Config) { if timeout > 0 { cfg.ShutdownTimeout = timeout } } }