platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
127
selective-vpn-api/app/resolver/timeout_recheck.go
Normal file
127
selective-vpn-api/app/resolver/timeout_recheck.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package resolver
|
||||
|
||||
import "strings"
|
||||
|
||||
func RunTimeoutQuarantineRecheck(
|
||||
domains []string,
|
||||
now int,
|
||||
limit int,
|
||||
workers int,
|
||||
domainCache *DomainCacheState,
|
||||
cacheSourceForHost func(string) DomainCacheSource,
|
||||
resolveHost func(string) ([]string, DNSMetrics),
|
||||
) ResolverTimeoutRecheckStats {
|
||||
stats := ResolverTimeoutRecheckStats{}
|
||||
if limit <= 0 || now <= 0 || domainCache == nil || resolveHost == nil {
|
||||
return stats
|
||||
}
|
||||
if workers < 1 {
|
||||
workers = 1
|
||||
}
|
||||
if workers > 200 {
|
||||
workers = 200
|
||||
}
|
||||
|
||||
resolveSource := cacheSourceForHost
|
||||
if resolveSource == nil {
|
||||
resolveSource = func(string) DomainCacheSource { return DomainCacheSourceDirect }
|
||||
}
|
||||
|
||||
seen := map[string]struct{}{}
|
||||
capHint := len(domains)
|
||||
if capHint > limit {
|
||||
capHint = limit
|
||||
}
|
||||
candidates := make([]string, 0, capHint)
|
||||
for _, raw := range domains {
|
||||
host := strings.TrimSpace(strings.ToLower(raw))
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[host]; ok {
|
||||
continue
|
||||
}
|
||||
seen[host] = struct{}{}
|
||||
|
||||
source := resolveSource(host)
|
||||
if _, _, ok := domainCache.GetQuarantine(host, source, now); !ok {
|
||||
continue
|
||||
}
|
||||
kind, ok := domainCache.GetLastErrorKind(host, source)
|
||||
if !ok || kind != DNSErrorTimeout {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, host)
|
||||
if len(candidates) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
return stats
|
||||
}
|
||||
|
||||
recoveredIPSet := map[string]struct{}{}
|
||||
|
||||
type result struct {
|
||||
host string
|
||||
source DomainCacheSource
|
||||
ips []string
|
||||
dns DNSMetrics
|
||||
}
|
||||
|
||||
jobs := make(chan string, len(candidates))
|
||||
results := make(chan result, len(candidates))
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
go func() {
|
||||
for host := range jobs {
|
||||
src := resolveSource(host)
|
||||
ips, dnsStats := resolveHost(host)
|
||||
results <- result{host: host, source: src, ips: ips, dns: dnsStats}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for _, host := range candidates {
|
||||
jobs <- host
|
||||
}
|
||||
close(jobs)
|
||||
|
||||
for i := 0; i < len(candidates); i++ {
|
||||
r := <-results
|
||||
stats.Checked++
|
||||
if len(r.ips) > 0 {
|
||||
for _, ip := range r.ips {
|
||||
ip = strings.TrimSpace(ip)
|
||||
if ip == "" {
|
||||
continue
|
||||
}
|
||||
recoveredIPSet[ip] = struct{}{}
|
||||
}
|
||||
domainCache.Set(r.host, r.source, r.ips, now)
|
||||
stats.Recovered++
|
||||
continue
|
||||
}
|
||||
if r.dns.TotalErrors() > 0 {
|
||||
domainCache.SetErrorWithStats(r.host, r.source, r.dns, now)
|
||||
}
|
||||
kind, ok := ClassifyHostErrorKind(r.dns)
|
||||
if !ok {
|
||||
stats.NoSignal++
|
||||
continue
|
||||
}
|
||||
switch kind {
|
||||
case DNSErrorTimeout:
|
||||
stats.StillTimeout++
|
||||
case DNSErrorNXDomain:
|
||||
stats.NowNXDomain++
|
||||
case DNSErrorTemporary:
|
||||
stats.NowTemporary++
|
||||
default:
|
||||
stats.NowOther++
|
||||
}
|
||||
}
|
||||
|
||||
stats.RecoveredIPs = len(recoveredIPSet)
|
||||
return stats
|
||||
}
|
||||
Reference in New Issue
Block a user