package bootstrap import ( "errors" "math" "sort" "strings" "time" "proxy-pool/internal/adapters/providerapi" "proxy-pool/internal/config" "proxy-pool/internal/controller/pool" controllerProvider "proxy-pool/internal/controller/provider" ) var ErrProviderRuntime = errors.New("invalid Provider runtime configuration") func newProviderFleet(configuration *config.Config, opened ports) (*controllerProvider.Fleet, error) { if configuration == nil { return nil, ErrProviderRuntime } names := make([]string, 0, len(configuration.Upstreams)) for name, upstream := range configuration.Upstreams { if upstream.Enabled { names = append(names, name) } } if len(names) == 0 { return nil, nil } builder, err := providerRuntimeBuilder(opened) if err != nil { return nil, err } sort.Strings(names) runtimes := make([]*controllerProvider.UpstreamRuntime, 0, len(names)) for _, name := range names { runtime, err := builder(name, configuration.Upstreams[name]) if err != nil { return nil, err } runtimes = append(runtimes, runtime) } return controllerProvider.NewFleet(runtimes...) } type buildUpstreamRuntime func(string, config.Upstream) (*controllerProvider.UpstreamRuntime, error) func providerRuntimeBuilder(opened ports) (buildUpstreamRuntime, error) { if nilInterface(opened.coordinator) || nilInterface(opened.activity) || nilInterface(opened.credentials) { return nil, ErrProviderRuntime } results := opened.providerResults if nilInterface(results) { results = discardProviderResults{} } return func(name string, upstream config.Upstream) (*controllerProvider.UpstreamRuntime, error) { upstream.Enabled = true mapped, err := providerRuntimeConfig(name, upstream) if err != nil { return nil, err } adapter, err := providerapi.NewHTTPAdapter(upstream.API, upstream.Fetch, nil) if err != nil { return nil, err } parser, err := providerapi.NewTemplateParser(name, upstream, opened.credentials) if err != nil { return nil, err } return controllerProvider.NewUpstreamRuntime(mapped, controllerProvider.UpstreamRuntimeDependencies{ Coordinator: opened.coordinator, Inventory: opened.activity, Adapter: adapter, Parser: parser, Activity: opened.activity, Results: results, }) }, nil } func providerRuntimeConfig( upstreamID string, upstream config.Upstream, ) (controllerProvider.UpstreamRuntimeConfig, error) { if strings.TrimSpace(upstreamID) != upstreamID || upstreamID == "" || !upstream.Enabled || upstream.Fetch.EstimatedIPsPerCall <= 0 || upstream.Capacity.MaxConcurrencyPerProxy <= 0 || upstream.Pool.MaxSize > config.MaximumPoolSize || int64(upstream.Fetch.EstimatedIPsPerCall) > controllerProvider.MaximumCoordinationInteger || int64(upstream.Fetch.MaxInFlight) > controllerProvider.MaximumCoordinationInteger || int64(upstream.Fetch.MaxTotal) > controllerProvider.MaximumCoordinationInteger || int64(upstream.Fetch.EstimatedIPsPerCall) > math.MaxInt64/int64(upstream.Capacity.MaxConcurrencyPerProxy) { return controllerProvider.UpstreamRuntimeConfig{}, ErrProviderRuntime } expectedSlots := int64(upstream.Fetch.EstimatedIPsPerCall) * int64(upstream.Capacity.MaxConcurrencyPerProxy) return controllerProvider.UpstreamRuntimeConfig{ Provider: controllerProvider.Config{ UpstreamID: upstreamID, RequestInterval: time.Duration(upstream.Fetch.RequestInterval), Timeout: time.Duration(upstream.Fetch.Timeout), MaxAttempts: upstream.Fetch.MaxAttempts, MaxInFlight: upstream.Fetch.MaxInFlight, MaxTotal: int64(upstream.Fetch.MaxTotal), MaxSize: upstream.Pool.MaxSize, TTL: time.Duration(upstream.Lifecycle.TTL), AllocationSafetyMargin: time.Duration(upstream.Lifecycle.AllocationSafetyMargin), Retry: controllerProvider.RetryConfig{ Initial: time.Duration(upstream.Fetch.Retry.Initial), Max: time.Duration(upstream.Fetch.Retry.Max), Jitter: upstream.Fetch.Retry.Jitter, }, }, ReconcilePolicy: pool.ReconcilePolicy{ MinimumAvailableSlots: upstream.Refill.MinimumAvailableSlots, TargetAvailableSlots: upstream.Refill.TargetAvailableSlots, ExpectedPerFetch: upstream.Fetch.EstimatedIPsPerCall, ExpectedSlotsPerFetch: expectedSlots, SafetyMargin: time.Duration(upstream.Lifecycle.AllocationSafetyMargin), }, ReconcileInterval: time.Duration(upstream.Refill.ReconcileInterval), }, nil } type discardProviderResults struct{} func (discardProviderResults) Record(controllerProvider.Result) {}