127 lines
4.5 KiB
Go
127 lines
4.5 KiB
Go
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) {}
|