package app import ( "log" "strings" "time" egressutilpkg "selective-vpn-api/app/egressutil" ) func (s *egressIdentityService) refreshScope(target egressScopeTarget, force bool) { s.acquire() defer s.release() now := time.Now().UTC() provider := s.providerFor(target.Source) if provider == nil { s.finishError(target, "provider is not configured for scope source", now) return } ip, err := provider.Probe(target) if err != nil { s.finishError(target, err.Error(), now) return } code, name, geoErr := s.lookupGeo(ip, force) s.finishSuccess(target, ip, code, name, geoErr, now) } func (s *egressIdentityService) providerFor(source string) egressSourceProvider { s.mu.Lock() defer s.mu.Unlock() return s.providers[strings.ToLower(strings.TrimSpace(source))] } func (s *egressIdentityService) finishError(target egressScopeTarget, msg string, at time.Time) { s.mu.Lock() entry := s.ensureEntryLocked(target) prev := s.entrySnapshotLocked(entry, target, at) entry.swr.finishError(msg, at) next := s.entrySnapshotLocked(entry, target, at) changed := egressIdentityChanged(prev, next) s.mu.Unlock() if changed { events.push("egress_identity_changed", map[string]any{ "scope": next.Scope, "ip": next.IP, "country_code": next.CountryCode, "country_name": next.CountryName, "updated_at": next.UpdatedAt, "stale": next.Stale, "last_error": next.LastError, }) if target.Source == "transport" { publishTransportRuntimeObservabilitySnapshotChanged( "egress_identity_changed", []string{target.SourceID}, nil, ) } } } func (s *egressIdentityService) finishSuccess( target egressScopeTarget, ip string, code string, name string, geoErr error, at time.Time, ) { s.mu.Lock() entry := s.ensureEntryLocked(target) prev := s.entrySnapshotLocked(entry, target, at) previousIP := strings.TrimSpace(entry.item.IP) entry.item.Scope = target.Scope entry.item.Source = target.Source entry.item.SourceID = target.SourceID entry.item.IP = strings.TrimSpace(ip) if geoErr == nil { entry.item.CountryCode = egressutilpkg.NormalizeCountryCode(code) entry.item.CountryName = strings.TrimSpace(name) } else if previousIP != strings.TrimSpace(ip) { entry.item.CountryCode = "" entry.item.CountryName = "" } entry.swr.finishSuccess(at) next := s.entrySnapshotLocked(entry, target, at) changed := egressIdentityChanged(prev, next) s.mu.Unlock() if geoErr != nil { log.Printf("egress geo lookup warning: scope=%s ip=%s err=%v", target.Scope, ip, geoErr) } if changed { events.push("egress_identity_changed", map[string]any{ "scope": next.Scope, "ip": next.IP, "country_code": next.CountryCode, "country_name": next.CountryName, "updated_at": next.UpdatedAt, "stale": next.Stale, "last_error": next.LastError, }) if target.Source == "transport" { publishTransportRuntimeObservabilitySnapshotChanged( "egress_identity_changed", []string{target.SourceID}, nil, ) } } }