package config import ( "fmt" "os" "time" "gopkg.in/yaml.v3" ) type Config struct { HTTP HTTPConfig `yaml:"http"` Server ServerConfig `yaml:"server"` SSL SSLConfig `yaml:"ssl"` Logging LoggingConfig `yaml:"logging"` Extensions []ExtensionConfig `yaml:"extensions"` } type HTTPConfig struct { StaticDir string `yaml:"static_dir"` TemplatesDir string `yaml:"templates_dir"` } type ServerConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` Backlog int `yaml:"backlog"` DefaultRoot bool `yaml:"default_root"` ProxyTimeout time.Duration `yaml:"proxy_timeout"` RedirectInstructions map[string]string `yaml:"redirect_instructions"` } type SSLConfig struct { Enabled bool `yaml:"enabled"` CertFile string `yaml:"cert_file"` KeyFile string `yaml:"key_file"` } type LoggingConfig struct { Level string `yaml:"level"` ConsoleOutput bool `yaml:"console_output"` Format LogFormatConfig `yaml:"format"` Console *ConsoleLogConfig `yaml:"console"` Files []FileLogConfig `yaml:"files"` } type LogFormatConfig struct { Type string `yaml:"type"` UseColors bool `yaml:"use_colors"` ShowModule bool `yaml:"show_module"` TimestampFormat string `yaml:"timestamp_format"` } type ConsoleLogConfig struct { Format LogFormatConfig `yaml:"format"` Level string `yaml:"level"` } type FileLogConfig struct { Path string `yaml:"path"` Level string `yaml:"level"` Loggers []string `yaml:"loggers"` Format LogFormatConfig `yaml:"format"` MaxBytes int64 `yaml:"max_bytes"` BackupCount int `yaml:"backup_count"` } type ExtensionConfig struct { Type string `yaml:"type"` Config map[string]interface{} `yaml:"config"` } func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } cfg := Default() if err := yaml.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("failed to parse config: %w", err) } return cfg, nil } func Default() *Config { return &Config{ HTTP: HTTPConfig{ StaticDir: "./static", TemplatesDir: "./templates", }, Server: ServerConfig{ Host: "0.0.0.0", Port: 8080, Backlog: 5, DefaultRoot: false, ProxyTimeout: 30 * time.Second, }, SSL: SSLConfig{ Enabled: false, CertFile: "./ssl/cert.pem", KeyFile: "./ssl/key.pem", }, Logging: LoggingConfig{ Level: "INFO", ConsoleOutput: true, Format: LogFormatConfig{ Type: "standard", UseColors: true, ShowModule: true, TimestampFormat: "2006-01-02 15:04:05", }, }, Extensions: []ExtensionConfig{}, } } func (c *Config) Validate() error { if c.Server.Port < 1 || c.Server.Port > 65535 { return fmt.Errorf("invalid port: %d", c.Server.Port) } if c.SSL.Enabled { if c.SSL.CertFile == "" { return fmt.Errorf("SSL enabled but cert_file not specified") } if c.SSL.KeyFile == "" { return fmt.Errorf("SSL enabled but key_file not specified") } } return nil }