package config import ( "time" "github.com/tech/sendico/pkg/db" "github.com/tech/sendico/pkg/messaging" ) const ( defaultShutdownTimeoutSeconds = 15 defaultMetricsAddress = ":9420" defaultWorkerConcurrency = 8 defaultWorkerPollIntervalMS = 200 defaultLockTTLSeconds = 30 defaultRequestTimeoutMS = 10000 defaultMaxAttempts = 8 defaultMinDelayMS = 1000 defaultMaxDelayMS = 300000 defaultJitterRatio = 0.20 defaultDNSResolveTimeoutMS = 2000 defaultSecretsVaultField = "value" ) // Loader parses callbacks service configuration. type Loader interface { Load(path string) (*Config, error) } // Config is the full callbacks service configuration. type Config struct { Runtime *RuntimeConfig `yaml:"runtime"` Metrics *MetricsConfig `yaml:"metrics"` Database *db.Config `yaml:"database"` Messaging *messaging.Config `yaml:"messaging"` Delivery DeliveryConfig `yaml:"delivery"` Security SecurityConfig `yaml:"security"` Secrets SecretsConfig `yaml:"secrets"` } // RuntimeConfig contains process lifecycle settings. type RuntimeConfig struct { ShutdownTimeoutSeconds int `yaml:"shutdown_timeout_seconds"` } func (c *RuntimeConfig) ShutdownTimeout() time.Duration { if c == nil || c.ShutdownTimeoutSeconds <= 0 { return defaultShutdownTimeoutSeconds * time.Second } return time.Duration(c.ShutdownTimeoutSeconds) * time.Second } // MetricsConfig configures observability endpoints. type MetricsConfig struct { Address string `yaml:"address"` } func (c *MetricsConfig) ListenAddress() string { if c == nil || c.Address == "" { return defaultMetricsAddress } return c.Address } // DeliveryConfig controls dispatcher behavior. type DeliveryConfig struct { WorkerConcurrency int `yaml:"worker_concurrency"` WorkerPollMS int `yaml:"worker_poll_ms"` LockTTLSeconds int `yaml:"lock_ttl_seconds"` RequestTimeoutMS int `yaml:"request_timeout_ms"` MaxAttempts int `yaml:"max_attempts"` MinDelayMS int `yaml:"min_delay_ms"` MaxDelayMS int `yaml:"max_delay_ms"` JitterRatio float64 `yaml:"jitter_ratio"` } func (c *DeliveryConfig) WorkerPollInterval() time.Duration { if c.WorkerPollMS <= 0 { return time.Duration(defaultWorkerPollIntervalMS) * time.Millisecond } return time.Duration(c.WorkerPollMS) * time.Millisecond } func (c *DeliveryConfig) LockTTL() time.Duration { if c.LockTTLSeconds <= 0 { return time.Duration(defaultLockTTLSeconds) * time.Second } return time.Duration(c.LockTTLSeconds) * time.Second } func (c *DeliveryConfig) RequestTimeout() time.Duration { if c.RequestTimeoutMS <= 0 { return time.Duration(defaultRequestTimeoutMS) * time.Millisecond } return time.Duration(c.RequestTimeoutMS) * time.Millisecond } func (c *DeliveryConfig) MinDelay() time.Duration { if c.MinDelayMS <= 0 { return time.Duration(defaultMinDelayMS) * time.Millisecond } return time.Duration(c.MinDelayMS) * time.Millisecond } func (c *DeliveryConfig) MaxDelay() time.Duration { if c.MaxDelayMS <= 0 { return time.Duration(defaultMaxDelayMS) * time.Millisecond } return time.Duration(c.MaxDelayMS) * time.Millisecond } // SecurityConfig controls outbound callback safety checks. type SecurityConfig struct { RequireHTTPS bool `yaml:"require_https"` AllowedHosts []string `yaml:"allowed_hosts"` AllowedPorts []int `yaml:"allowed_ports"` DNSResolveTimeout int `yaml:"dns_resolve_timeout_ms"` } func (c *SecurityConfig) DNSResolveTimeoutMS() time.Duration { if c.DNSResolveTimeout <= 0 { return time.Duration(defaultDNSResolveTimeoutMS) * time.Millisecond } return time.Duration(c.DNSResolveTimeout) * time.Millisecond } // SecretsConfig controls secret lookup behavior. type SecretsConfig struct { CacheTTLSeconds int `yaml:"cache_ttl_seconds"` Static map[string]string `yaml:"static"` Vault VaultSecretsConfig `yaml:"vault"` } // VaultSecretsConfig controls Vault KV secret resolution. type VaultSecretsConfig struct { Address string `yaml:"address"` TokenEnv string `yaml:"token_env"` Namespace string `yaml:"namespace"` MountPath string `yaml:"mount_path"` DefaultField string `yaml:"default_field"` } func (c *SecretsConfig) CacheTTL() time.Duration { if c == nil || c.CacheTTLSeconds <= 0 { return 0 } return time.Duration(c.CacheTTLSeconds) * time.Second }