Files
ai-disclosure-standard/internal/bulk/config.go
T
jbergner 13efcfb986
release-tag / release-image (push) Successful in 1m50s
Update auf 1.8.0 mit Bulk-Option
2026-07-22 22:27:42 +02:00

99 lines
2.7 KiB
Go

package bulk
import (
"fmt"
"net/url"
"os"
"strconv"
"strings"
"time"
)
type Config struct {
ListenAddress string
CoreInternalURL string
DisclosureBaseURL string
GeneratorURL string
PublicName string
MaxURLs int
Workers int
RequestTimeout time.Duration
}
func ConfigFromEnv() Config {
return Config{
ListenAddress: env("BULK_LISTEN_ADDRESS", ":8081"),
CoreInternalURL: strings.TrimRight(env("CORE_INTERNAL_URL", "http://app:8080"), "/"),
DisclosureBaseURL: strings.TrimRight(env("DISCLOSURE_BASE_URL", "http://localhost:8080"), "/"),
GeneratorURL: strings.TrimRight(env("GENERATOR_URL", env("DISCLOSURE_BASE_URL", "http://localhost:8080")), "/"),
PublicName: env("BULK_PUBLIC_NAME", "AI Disclosure Bulk"),
MaxURLs: intEnv("BULK_MAX_URLS", 500),
Workers: intEnv("BULK_WORKERS", 4),
RequestTimeout: durationEnv("BULK_REQUEST_TIMEOUT", 8*time.Second),
}
}
func ValidateConfig(cfg Config) error {
for name, value := range map[string]string{
"CORE_INTERNAL_URL": cfg.CoreInternalURL,
"DISCLOSURE_BASE_URL": cfg.DisclosureBaseURL,
"GENERATOR_URL": cfg.GeneratorURL,
} {
if err := validateOrigin(name, value); err != nil {
return err
}
}
if strings.TrimSpace(cfg.PublicName) == "" {
return fmt.Errorf("BULK_PUBLIC_NAME must not be empty")
}
if cfg.MaxURLs < 1 || cfg.MaxURLs > 5000 {
return fmt.Errorf("BULK_MAX_URLS must be between 1 and 5000")
}
if cfg.Workers < 1 || cfg.Workers > 32 {
return fmt.Errorf("BULK_WORKERS must be between 1 and 32")
}
if cfg.RequestTimeout < time.Second || cfg.RequestTimeout > 60*time.Second {
return fmt.Errorf("BULK_REQUEST_TIMEOUT must be between 1s and 60s")
}
return nil
}
func validateOrigin(name, value string) error {
u, err := url.Parse(value)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" || u.User != nil || (u.Path != "" && u.Path != "/") || u.RawQuery != "" || u.Fragment != "" {
return fmt.Errorf("%s must be an absolute http(s) origin without path, query, credentials or fragment", name)
}
return nil
}
func env(key, fallback string) string {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
}
return fallback
}
func intEnv(key string, fallback int) int {
value := strings.TrimSpace(os.Getenv(key))
if value == "" {
return fallback
}
parsed, err := strconv.Atoi(value)
if err != nil {
return fallback
}
return parsed
}
func durationEnv(key string, fallback time.Duration) time.Duration {
value := strings.TrimSpace(os.Getenv(key))
if value == "" {
return fallback
}
parsed, err := time.ParseDuration(value)
if err != nil {
return fallback
}
return parsed
}