mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-13 17:10:36 +00:00
204 lines
5.9 KiB
Go
204 lines
5.9 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// Manager handles configuration loading from multiple sources
|
|
type Manager struct {
|
|
v *viper.Viper
|
|
}
|
|
|
|
// NewManager creates a new configuration manager with defaults
|
|
func NewManager() *Manager {
|
|
v := viper.New()
|
|
|
|
// Set configuration file settings
|
|
v.SetConfigName("config")
|
|
v.SetConfigType("yaml")
|
|
v.AddConfigPath(".")
|
|
v.AddConfigPath("./config")
|
|
v.AddConfigPath("/etc/resolvespec")
|
|
v.AddConfigPath("$HOME/.resolvespec")
|
|
|
|
// Enable environment variable support
|
|
v.SetEnvPrefix("RESOLVESPEC")
|
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
v.AutomaticEnv()
|
|
|
|
// Set default values
|
|
setDefaults(v)
|
|
|
|
return &Manager{v: v}
|
|
}
|
|
|
|
// NewManagerWithOptions creates a new configuration manager with custom options
|
|
func NewManagerWithOptions(opts ...Option) *Manager {
|
|
m := NewManager()
|
|
for _, opt := range opts {
|
|
opt(m)
|
|
}
|
|
return m
|
|
}
|
|
|
|
// Option is a functional option for configuring the Manager
|
|
type Option func(*Manager)
|
|
|
|
// WithConfigFile sets a specific config file path
|
|
func WithConfigFile(path string) Option {
|
|
return func(m *Manager) {
|
|
m.v.SetConfigFile(path)
|
|
}
|
|
}
|
|
|
|
// WithConfigName sets the config file name (without extension)
|
|
func WithConfigName(name string) Option {
|
|
return func(m *Manager) {
|
|
m.v.SetConfigName(name)
|
|
}
|
|
}
|
|
|
|
// WithConfigPath adds a path to search for config files
|
|
func WithConfigPath(path string) Option {
|
|
return func(m *Manager) {
|
|
m.v.AddConfigPath(path)
|
|
}
|
|
}
|
|
|
|
// WithEnvPrefix sets the environment variable prefix
|
|
func WithEnvPrefix(prefix string) Option {
|
|
return func(m *Manager) {
|
|
m.v.SetEnvPrefix(prefix)
|
|
}
|
|
}
|
|
|
|
// Load attempts to load configuration from file and environment
|
|
func (m *Manager) Load() error {
|
|
// Try to read config file (not an error if it doesn't exist)
|
|
if err := m.v.ReadInConfig(); err != nil {
|
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
|
return fmt.Errorf("error reading config file: %w", err)
|
|
}
|
|
// Config file not found; will rely on defaults and env vars
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetConfig returns the complete configuration
|
|
func (m *Manager) GetConfig() (*Config, error) {
|
|
var cfg Config
|
|
if err := m.v.Unmarshal(&cfg); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
|
}
|
|
return &cfg, nil
|
|
}
|
|
|
|
// Get returns a configuration value by key
|
|
func (m *Manager) Get(key string) interface{} {
|
|
return m.v.Get(key)
|
|
}
|
|
|
|
// GetString returns a string configuration value
|
|
func (m *Manager) GetString(key string) string {
|
|
return m.v.GetString(key)
|
|
}
|
|
|
|
// GetInt returns an int configuration value
|
|
func (m *Manager) GetInt(key string) int {
|
|
return m.v.GetInt(key)
|
|
}
|
|
|
|
// GetBool returns a bool configuration value
|
|
func (m *Manager) GetBool(key string) bool {
|
|
return m.v.GetBool(key)
|
|
}
|
|
|
|
// Set sets a configuration value
|
|
func (m *Manager) Set(key string, value interface{}) {
|
|
m.v.Set(key, value)
|
|
}
|
|
|
|
// setDefaults sets default configuration values
|
|
func setDefaults(v *viper.Viper) {
|
|
// Server defaults
|
|
v.SetDefault("server.addr", ":8080")
|
|
v.SetDefault("server.shutdown_timeout", "30s")
|
|
v.SetDefault("server.drain_timeout", "25s")
|
|
v.SetDefault("server.read_timeout", "10s")
|
|
v.SetDefault("server.write_timeout", "10s")
|
|
v.SetDefault("server.idle_timeout", "120s")
|
|
|
|
// Tracing defaults
|
|
v.SetDefault("tracing.enabled", false)
|
|
v.SetDefault("tracing.service_name", "resolvespec")
|
|
v.SetDefault("tracing.service_version", "1.0.0")
|
|
v.SetDefault("tracing.endpoint", "")
|
|
|
|
// Cache defaults
|
|
v.SetDefault("cache.provider", "memory")
|
|
v.SetDefault("cache.redis.host", "localhost")
|
|
v.SetDefault("cache.redis.port", 6379)
|
|
v.SetDefault("cache.redis.password", "")
|
|
v.SetDefault("cache.redis.db", 0)
|
|
v.SetDefault("cache.memcache.servers", []string{"localhost:11211"})
|
|
v.SetDefault("cache.memcache.max_idle_conns", 10)
|
|
v.SetDefault("cache.memcache.timeout", "100ms")
|
|
|
|
// Logger defaults
|
|
v.SetDefault("logger.dev", false)
|
|
v.SetDefault("logger.path", "")
|
|
|
|
// Middleware defaults
|
|
v.SetDefault("middleware.rate_limit_rps", 100.0)
|
|
v.SetDefault("middleware.rate_limit_burst", 200)
|
|
v.SetDefault("middleware.max_request_size", 10485760) // 10MB
|
|
|
|
// CORS defaults
|
|
v.SetDefault("cors.allowed_origins", []string{"*"})
|
|
v.SetDefault("cors.allowed_methods", []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"})
|
|
v.SetDefault("cors.allowed_headers", []string{"*"})
|
|
v.SetDefault("cors.max_age", 3600)
|
|
|
|
// Database defaults
|
|
v.SetDefault("database.url", "")
|
|
|
|
// Event Broker defaults
|
|
v.SetDefault("event_broker.enabled", false)
|
|
v.SetDefault("event_broker.provider", "memory")
|
|
v.SetDefault("event_broker.mode", "async")
|
|
v.SetDefault("event_broker.worker_count", 10)
|
|
v.SetDefault("event_broker.buffer_size", 1000)
|
|
v.SetDefault("event_broker.instance_id", "")
|
|
|
|
// Event Broker - Redis defaults
|
|
v.SetDefault("event_broker.redis.stream_name", "resolvespec:events")
|
|
v.SetDefault("event_broker.redis.consumer_group", "resolvespec-workers")
|
|
v.SetDefault("event_broker.redis.max_len", 10000)
|
|
v.SetDefault("event_broker.redis.host", "localhost")
|
|
v.SetDefault("event_broker.redis.port", 6379)
|
|
v.SetDefault("event_broker.redis.password", "")
|
|
v.SetDefault("event_broker.redis.db", 0)
|
|
|
|
// Event Broker - NATS defaults
|
|
v.SetDefault("event_broker.nats.url", "nats://localhost:4222")
|
|
v.SetDefault("event_broker.nats.stream_name", "RESOLVESPEC_EVENTS")
|
|
v.SetDefault("event_broker.nats.subjects", []string{"events.>"})
|
|
v.SetDefault("event_broker.nats.storage", "file")
|
|
v.SetDefault("event_broker.nats.max_age", "24h")
|
|
|
|
// Event Broker - Database defaults
|
|
v.SetDefault("event_broker.database.table_name", "events")
|
|
v.SetDefault("event_broker.database.channel", "resolvespec_events")
|
|
v.SetDefault("event_broker.database.poll_interval", "1s")
|
|
|
|
// Event Broker - Retry Policy defaults
|
|
v.SetDefault("event_broker.retry_policy.max_retries", 3)
|
|
v.SetDefault("event_broker.retry_policy.initial_delay", "1s")
|
|
v.SetDefault("event_broker.retry_policy.max_delay", "30s")
|
|
v.SetDefault("event_broker.retry_policy.backoff_factor", 2.0)
|
|
}
|