package config import ( "fmt" "log/slog" "net" "net/mail" "strings" ) // Validate reports whether cfg stores a usable Mail Service process // configuration. func (cfg Config) Validate() error { switch { case cfg.ShutdownTimeout <= 0: return fmt.Errorf("%s must be positive", shutdownTimeoutEnvVar) case cfg.AttemptWorkerConcurrency <= 0: return fmt.Errorf("%s must be positive", attemptWorkerConcurrencyEnvVar) case cfg.StreamBlockTimeout <= 0: return fmt.Errorf("%s must be positive", streamBlockTimeoutEnvVar) case cfg.OperatorRequestTimeout <= 0: return fmt.Errorf("%s must be positive", operatorRequestTimeoutEnvVar) case cfg.IdempotencyTTL <= 0: return fmt.Errorf("%s must be positive", idempotencyTTLEnvVar) } if err := cfg.InternalHTTP.Validate(); err != nil { return err } if err := cfg.Redis.Validate(); err != nil { return err } if err := cfg.Postgres.Validate(); err != nil { return fmt.Errorf("postgres: %w", err) } if err := cfg.Retention.Validate(); err != nil { return err } if err := cfg.SMTP.Validate(); err != nil { return err } if err := cfg.Templates.Validate(); err != nil { return err } if err := cfg.Telemetry.Validate(); err != nil { return err } return nil } func validateSlogLevel(level string) error { var slogLevel slog.Level if err := slogLevel.UnmarshalText([]byte(strings.TrimSpace(level))); err != nil { return fmt.Errorf("invalid slog level %q: %w", level, err) } return nil } func isTCPAddr(value string) bool { host, port, err := net.SplitHostPort(strings.TrimSpace(value)) if err != nil { return false } if port == "" { return false } if host == "" { return true } return !strings.Contains(host, " ") } func validateMailbox(name string, value string) error { trimmed := strings.TrimSpace(value) if trimmed == "" { return fmt.Errorf("%s must not be empty", name) } parsed, err := mail.ParseAddress(trimmed) if err != nil || parsed == nil || parsed.Name != "" || parsed.Address != trimmed { return fmt.Errorf("%s %q must be a single valid email address", name, value) } return nil }