platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
117
selective-vpn-api/app/egress_identity_refresh_runner.go
Normal file
117
selective-vpn-api/app/egress_identity_refresh_runner.go
Normal file
@@ -0,0 +1,117 @@
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user