package config import ( "fmt" "os" "path/filepath" "gopkg.in/yaml.v3" ) // Config represents the application configuration type Config struct { Server ServerConfig `yaml:"server"` Proxy ProxyConfig `yaml:"proxy"` NAT NATConfig `yaml:"nat"` Logging LoggingConfig `yaml:"logging"` Monitor MonitorConfig `yaml:"monitor"` } // ServerConfig represents server configuration type ServerConfig struct { Port int `yaml:"port"` ReadTimeout int `yaml:"read_timeout"` WriteTimeout int `yaml:"write_timeout"` IdleTimeout int `yaml:"idle_timeout"` TLSCertFile string `yaml:"tls_cert_file,omitempty"` TLSKeyFile string `yaml:"tls_key_file,omitempty"` } // ProxyConfig represents reverse proxy configuration type ProxyConfig struct { Targets []TargetConfig `yaml:"targets"` LoadBalancer string `yaml:"load_balancer"` // "roundrobin", "leastconn", "random" HealthCheckPath string `yaml:"health_check_path"` HealthCheckInterval int `yaml:"health_check_interval"` } // TargetConfig represents a proxy target type TargetConfig struct { Name string `yaml:"name"` Address string `yaml:"address"` Protocol string `yaml:"protocol"` // "http", "https" Weight int `yaml:"weight"` // for weighted load balancing Healthy bool `yaml:"-"` // health status } // NATConfig represents NAT traversal configuration type NATConfig struct { Enabled bool `yaml:"enabled"` STUNServer string `yaml:"stun_server,omitempty"` TURNServer string `yaml:"turn_server,omitempty"` TURNUsername string `yaml:"turn_username,omitempty"` TURNPassword string `yaml:"turn_password,omitempty"` } // LoggingConfig represents logging configuration type LoggingConfig struct { Level string `yaml:"level"` // "debug", "info", "warn", "error" Format string `yaml:"format"` // "json", "text" Output string `yaml:"output"` // "stdout", "file" File string `yaml:"file,omitempty"` } // MonitorConfig represents monitoring configuration type MonitorConfig struct { Enabled bool `yaml:"enabled"` Port int `yaml:"port"` Path string `yaml:"path"` Auth bool `yaml:"auth"` Username string `yaml:"username,omitempty"` Password string `yaml:"password,omitempty"` } // Load loads configuration from file func Load(path string) (*Config, error) { // Check if file exists if _, err := os.Stat(path); os.IsNotExist(err) { return nil, fmt.Errorf("configuration file not found: %s", path) } // Read file data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("failed to read configuration file: %w", err) } // Parse YAML var config Config if err := yaml.Unmarshal(data, &config); err != nil { return nil, fmt.Errorf("failed to parse configuration: %w", err) } // Set defaults setDefaults(&config) return &config, nil } // setDefaults sets default values for configuration func setDefaults(c *Config) { // Server defaults if c.Server.Port == 0 { c.Server.Port = 8080 } if c.Server.ReadTimeout == 0 { c.Server.ReadTimeout = 30 } if c.Server.WriteTimeout == 0 { c.Server.WriteTimeout = 30 } if c.Server.IdleTimeout == 0 { c.Server.IdleTimeout = 60 } // Proxy defaults if c.Proxy.LoadBalancer == "" { c.Proxy.LoadBalancer = "roundrobin" } if c.Proxy.HealthCheckPath == "" { c.Proxy.HealthCheckPath = "/health" } if c.Proxy.HealthCheckInterval == 0 { c.Proxy.HealthCheckInterval = 30 } // NAT defaults if c.NAT.Enabled && c.NAT.STUNServer == "" { c.NAT.STUNServer = "stun:stun.l.google.com:19302" } // Logging defaults if c.Logging.Level == "" { c.Logging.Level = "info" } if c.Logging.Format == "" { c.Logging.Format = "json" } if c.Logging.Output == "" { c.Logging.Output = "stdout" } // Monitor defaults if c.Monitor.Enabled && c.Monitor.Port == 0 { c.Monitor.Port = 9090 } if c.Monitor.Enabled && c.Monitor.Path == "" { c.Monitor.Path = "/metrics" } } // CreateDefaultConfig creates a default configuration file func CreateDefaultConfig(path string) error { config := Config{ Server: ServerConfig{ Port: 8080, ReadTimeout: 30, WriteTimeout: 30, IdleTimeout: 60, }, Proxy: ProxyConfig{ LoadBalancer: "roundrobin", HealthCheckPath: "/health", HealthCheckInterval: 30, Targets: []TargetConfig{ { Name: "example", Address: "http://localhost:3000", Protocol: "http", Weight: 1, }, }, }, NAT: NATConfig{ Enabled: false, STUNServer: "stun:stun.l.google.com:19302", }, Logging: LoggingConfig{ Level: "info", Format: "json", Output: "stdout", }, Monitor: MonitorConfig{ Enabled: true, Port: 9090, Path: "/metrics", Auth: false, }, } data, err := yaml.Marshal(config) if err != nil { return fmt.Errorf("failed to marshal default configuration: %w", err) } // Create directory if it doesn't exist if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return fmt.Errorf("failed to create configuration directory: %w", err) } // Write configuration file if err := os.WriteFile(path, data, 0644); err != nil { return fmt.Errorf("failed to write configuration file: %w", err) } return nil }