| package config |
|
|
| import ( |
| "fmt" |
| "strings" |
| ) |
|
|
| func ValidateConfig(c Config) error { |
| if err := ValidateProxyConfig(c.Proxies); err != nil { |
| return err |
| } |
| if err := ValidateAdminConfig(c.Admin); err != nil { |
| return err |
| } |
| if err := ValidateRuntimeConfig(c.Runtime); err != nil { |
| return err |
| } |
| if err := ValidateResponsesConfig(c.Responses); err != nil { |
| return err |
| } |
| if err := ValidateEmbeddingsConfig(c.Embeddings); err != nil { |
| return err |
| } |
| if err := ValidateAutoDeleteConfig(c.AutoDelete); err != nil { |
| return err |
| } |
| if err := ValidateCurrentInputFileConfig(c.CurrentInputFile); err != nil { |
| return err |
| } |
| if err := ValidateAccountProxyReferences(c.Accounts, c.Proxies); err != nil { |
| return err |
| } |
| return nil |
| } |
|
|
| func ValidateProxyConfig(proxies []Proxy) error { |
| seen := make(map[string]struct{}, len(proxies)) |
| for _, proxy := range proxies { |
| proxy = NormalizeProxy(proxy) |
| if err := ValidateTrimmedString("proxies.id", proxy.ID, true); err != nil { |
| return err |
| } |
| switch proxy.Type { |
| case "socks5", "socks5h": |
| default: |
| return fmt.Errorf("proxies.type must be one of socks5, socks5h") |
| } |
| if err := ValidateTrimmedString("proxies.host", proxy.Host, true); err != nil { |
| return err |
| } |
| if err := ValidateIntRange("proxies.port", proxy.Port, 1, 65535, true); err != nil { |
| return err |
| } |
| if _, ok := seen[proxy.ID]; ok { |
| return fmt.Errorf("duplicate proxy id: %s", proxy.ID) |
| } |
| seen[proxy.ID] = struct{}{} |
| } |
| return nil |
| } |
|
|
| func ValidateAccountProxyReferences(accounts []Account, proxies []Proxy) error { |
| if len(accounts) == 0 { |
| return nil |
| } |
| ids := make(map[string]struct{}, len(proxies)) |
| for _, proxy := range proxies { |
| ids[NormalizeProxy(proxy).ID] = struct{}{} |
| } |
| for _, acc := range accounts { |
| proxyID := strings.TrimSpace(acc.ProxyID) |
| if proxyID == "" { |
| continue |
| } |
| if _, ok := ids[proxyID]; !ok { |
| return fmt.Errorf("account proxy_id references unknown proxy: %s", proxyID) |
| } |
| } |
| return nil |
| } |
|
|
| func ValidateAdminConfig(admin AdminConfig) error { |
| return ValidateIntRange("admin.jwt_expire_hours", admin.JWTExpireHours, 1, 720, false) |
| } |
|
|
| func ValidateRuntimeConfig(runtime RuntimeConfig) error { |
| if err := ValidateIntRange("runtime.account_max_inflight", runtime.AccountMaxInflight, 1, 256, false); err != nil { |
| return err |
| } |
| if err := ValidateIntRange("runtime.account_max_queue", runtime.AccountMaxQueue, 1, 200000, false); err != nil { |
| return err |
| } |
| if err := ValidateIntRange("runtime.global_max_inflight", runtime.GlobalMaxInflight, 1, 200000, false); err != nil { |
| return err |
| } |
| if err := ValidateIntRange("runtime.token_refresh_interval_hours", runtime.TokenRefreshIntervalHours, 1, 720, false); err != nil { |
| return err |
| } |
| if runtime.AccountMaxInflight > 0 && runtime.GlobalMaxInflight > 0 && runtime.GlobalMaxInflight < runtime.AccountMaxInflight { |
| return fmt.Errorf("runtime.global_max_inflight must be >= runtime.account_max_inflight") |
| } |
| return nil |
| } |
|
|
| func ValidateResponsesConfig(responses ResponsesConfig) error { |
| return ValidateIntRange("responses.store_ttl_seconds", responses.StoreTTLSeconds, 30, 86400, false) |
| } |
|
|
| func ValidateEmbeddingsConfig(embeddings EmbeddingsConfig) error { |
| return ValidateTrimmedString("embeddings.provider", embeddings.Provider, false) |
| } |
|
|
| func ValidateAutoDeleteConfig(autoDelete AutoDeleteConfig) error { |
| return ValidateAutoDeleteMode(autoDelete.Mode) |
| } |
|
|
| func ValidateCurrentInputFileConfig(currentInputFile CurrentInputFileConfig) error { |
| if currentInputFile.MinChars != 0 { |
| return ValidateIntRange("current_input_file.min_chars", currentInputFile.MinChars, 1, 100000000, true) |
| } |
| return nil |
| } |
|
|
| func ValidateIntRange(name string, value, min, max int, required bool) error { |
| if value == 0 && !required { |
| return nil |
| } |
| if value < min || value > max { |
| return fmt.Errorf("%s must be between %d and %d", name, min, max) |
| } |
| return nil |
| } |
|
|
| func ValidateTrimmedString(name, value string, required bool) error { |
| trimmed := strings.TrimSpace(value) |
| if trimmed == "" { |
| if !required && value == "" { |
| return nil |
| } |
| return fmt.Errorf("%s cannot be empty", name) |
| } |
| return nil |
| } |
|
|
| func ValidateAutoDeleteMode(mode string) error { |
| mode = strings.ToLower(strings.TrimSpace(mode)) |
| switch mode { |
| case "", "none", "single", "all": |
| return nil |
| default: |
| return fmt.Errorf("auto_delete.mode must be one of none, single, all") |
| } |
| } |
|
|