package app import ( "net/http" "sync" "time" ) const ( egressIdentityFreshTTL = 3 * time.Minute egressIdentityBackoffMin = 3 * time.Second egressIdentityBackoffMax = 2 * time.Minute egressIdentityProbeTimeout = 4 * time.Second egressIdentityGeoTimeout = 4 * time.Second egressIdentityGeoCacheTTL = 24 * time.Hour egressIdentityGeoFailTTL = 30 * time.Second egressIdentityMaxConcurrency = 2 ) var ( egressIdentitySWR = newEgressIdentityService( envInt("SVPN_EGRESS_MAX_PARALLEL", egressIdentityMaxConcurrency), ) egressHTTPClient = &http.Client{} ) type egressScopeTarget struct { Scope string Source string SourceID string } type egressSourceProvider interface { Probe(target egressScopeTarget) (string, error) } type egressIdentityEntry struct { item EgressIdentity swr refreshCoordinator } type egressGeoCacheEntry struct { CountryCode string CountryName string LastError string ExpiresAt time.Time } type egressIdentityService struct { mu sync.Mutex entries map[string]*egressIdentityEntry sem chan struct{} providers map[string]egressSourceProvider geoMu sync.Mutex geoCache map[string]egressGeoCacheEntry } type egressSystemProvider struct{} type egressAdGuardProvider struct{} type egressTransportProvider struct{} func newEgressIdentityService(maxConcurrent int) *egressIdentityService { n := maxConcurrent if n <= 0 { n = egressIdentityMaxConcurrency } return &egressIdentityService{ entries: map[string]*egressIdentityEntry{}, sem: make(chan struct{}, n), providers: map[string]egressSourceProvider{ "system": egressSystemProvider{}, "adguardvpn": egressAdGuardProvider{}, "transport": egressTransportProvider{}, }, geoCache: map[string]egressGeoCacheEntry{}, } }