Akron | 90f6521 | 2025-06-12 14:32:55 +0200 | [diff] [blame] | 1 | package config |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "os" |
| 6 | ) |
| 7 | |
| 8 | // Config represents the complete configuration for KorAP MCP server |
| 9 | type Config struct { |
| 10 | // Server configuration |
| 11 | Server ServerConfig `yaml:"server" embed:""` |
| 12 | |
| 13 | // OAuth2 authentication configuration |
| 14 | OAuth OAuthConfig `yaml:"oauth"` |
| 15 | |
| 16 | // KorAP API configuration |
| 17 | KorAP KorAPConfig `yaml:"korap"` |
| 18 | |
Akron | e73bc91 | 2025-06-17 16:36:45 +0200 | [diff] [blame] | 19 | // Cache configuration |
| 20 | Cache CacheConfig `yaml:"cache"` |
| 21 | |
Akron | 90f6521 | 2025-06-12 14:32:55 +0200 | [diff] [blame] | 22 | // Logging configuration |
| 23 | Logging LoggingConfig `yaml:"logging"` |
| 24 | } |
| 25 | |
| 26 | // ServerConfig represents server-specific configuration |
| 27 | type ServerConfig struct { |
| 28 | // Name is the server name (constant, not configurable) |
| 29 | Name string `yaml:"-"` |
| 30 | |
| 31 | // Version is the server version (constant, not configurable) |
| 32 | Version string `yaml:"-"` |
| 33 | |
| 34 | // ConfigFile is the path to the configuration file (handled by CLI layer) |
| 35 | ConfigFile string `yaml:"-"` |
| 36 | } |
| 37 | |
| 38 | // KorAPConfig represents KorAP API configuration |
| 39 | type KorAPConfig struct { |
| 40 | // BaseURL is the KorAP server base URL |
| 41 | BaseURL string `yaml:"base_url" default:"https://korap.ids-mannheim.de" help:"KorAP server base URL"` |
| 42 | |
| 43 | // APIVersion is the API version to use |
| 44 | APIVersion string `yaml:"api_version" default:"v1.0" help:"KorAP API version"` |
| 45 | |
| 46 | // Timeout is the HTTP request timeout in seconds |
| 47 | Timeout int `yaml:"timeout" default:"30" help:"HTTP request timeout in seconds"` |
| 48 | |
| 49 | // MaxRetries is the maximum number of retry attempts |
| 50 | MaxRetries int `yaml:"max_retries" default:"3" help:"Maximum number of retry attempts"` |
| 51 | } |
| 52 | |
| 53 | // LoggingConfig represents logging configuration |
| 54 | type LoggingConfig struct { |
| 55 | // Level is the logging level (trace, debug, info, warn, error) |
| 56 | Level string `yaml:"level" default:"info" enum:"trace,debug,info,warn,error" help:"Logging level"` |
| 57 | |
| 58 | // Format is the log format (json, text) |
| 59 | Format string `yaml:"format" default:"text" enum:"json,text" help:"Log output format"` |
| 60 | |
| 61 | // File is the log file path (empty for stdout) |
| 62 | File string `yaml:"file" help:"Log file path (empty for stdout)"` |
| 63 | } |
| 64 | |
| 65 | // DefaultConfig returns a default configuration |
| 66 | func DefaultConfig() *Config { |
| 67 | return &Config{ |
| 68 | Server: ServerConfig{ |
| 69 | // Name and Version are set by the CLI layer as constants |
| 70 | }, |
| 71 | OAuth: *DefaultOAuthConfig(), |
| 72 | KorAP: KorAPConfig{ |
| 73 | BaseURL: "https://korap.ids-mannheim.de", |
| 74 | APIVersion: "v1.0", |
| 75 | Timeout: 30, |
| 76 | MaxRetries: 3, |
| 77 | }, |
Akron | e73bc91 | 2025-06-17 16:36:45 +0200 | [diff] [blame] | 78 | Cache: *DefaultCacheConfig(), |
Akron | 90f6521 | 2025-06-12 14:32:55 +0200 | [diff] [blame] | 79 | Logging: LoggingConfig{ |
| 80 | Level: "info", |
| 81 | Format: "text", |
| 82 | }, |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | // Validate validates the complete configuration |
| 87 | func (c *Config) Validate() error { |
| 88 | if err := c.OAuth.Validate(); err != nil { |
| 89 | return fmt.Errorf("oauth config validation failed: %w", err) |
| 90 | } |
| 91 | |
| 92 | if err := c.KorAP.Validate(); err != nil { |
| 93 | return fmt.Errorf("korap config validation failed: %w", err) |
| 94 | } |
| 95 | |
Akron | e73bc91 | 2025-06-17 16:36:45 +0200 | [diff] [blame] | 96 | if err := c.Cache.Validate(); err != nil { |
| 97 | return fmt.Errorf("cache config validation failed: %w", err) |
| 98 | } |
| 99 | |
Akron | 90f6521 | 2025-06-12 14:32:55 +0200 | [diff] [blame] | 100 | if err := c.Logging.Validate(); err != nil { |
| 101 | return fmt.Errorf("logging config validation failed: %w", err) |
| 102 | } |
| 103 | |
| 104 | return nil |
| 105 | } |
| 106 | |
| 107 | // Validate validates KorAP configuration |
| 108 | func (k *KorAPConfig) Validate() error { |
| 109 | if k.BaseURL == "" { |
| 110 | return fmt.Errorf("base_url cannot be empty") |
| 111 | } |
| 112 | |
| 113 | if k.APIVersion == "" { |
| 114 | return fmt.Errorf("api_version cannot be empty") |
| 115 | } |
| 116 | |
| 117 | if k.Timeout <= 0 { |
| 118 | return fmt.Errorf("timeout must be positive") |
| 119 | } |
| 120 | |
| 121 | if k.MaxRetries < 0 { |
| 122 | return fmt.Errorf("max_retries cannot be negative") |
| 123 | } |
| 124 | |
| 125 | return nil |
| 126 | } |
| 127 | |
| 128 | // Validate validates logging configuration |
| 129 | func (l *LoggingConfig) Validate() error { |
| 130 | validLevels := map[string]bool{ |
| 131 | "trace": true, |
| 132 | "debug": true, |
| 133 | "info": true, |
| 134 | "warn": true, |
| 135 | "error": true, |
| 136 | } |
| 137 | |
| 138 | if !validLevels[l.Level] { |
| 139 | return fmt.Errorf("invalid log level: %s", l.Level) |
| 140 | } |
| 141 | |
| 142 | validFormats := map[string]bool{ |
| 143 | "json": true, |
| 144 | "text": true, |
| 145 | } |
| 146 | |
| 147 | if !validFormats[l.Format] { |
| 148 | return fmt.Errorf("invalid log format: %s", l.Format) |
| 149 | } |
| 150 | |
| 151 | // Check if log file is writable if specified |
| 152 | if l.File != "" { |
| 153 | file, err := os.OpenFile(l.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) |
| 154 | if err != nil { |
| 155 | return fmt.Errorf("cannot write to log file %s: %w", l.File, err) |
| 156 | } |
| 157 | file.Close() |
| 158 | } |
| 159 | |
| 160 | return nil |
| 161 | } |
| 162 | |
| 163 | // GetKorAPEndpoint returns the full KorAP API endpoint URL |
| 164 | func (k *KorAPConfig) GetKorAPEndpoint() string { |
| 165 | return fmt.Sprintf("%s/api/%s", k.BaseURL, k.APIVersion) |
| 166 | } |