platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
140
selective-vpn-api/app/dns_settings_benchmark_handler.go
Normal file
140
selective-vpn-api/app/dns_settings_benchmark_handler.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
dnscfgpkg "selective-vpn-api/app/dnscfg"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func handleDNSBenchmark(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req DNSBenchmarkRequest
|
||||
if r.Body != nil {
|
||||
defer r.Body.Close()
|
||||
if err := json.NewDecoder(io.LimitReader(r.Body, 1<<20)).Decode(&req); err != nil && err != io.EOF {
|
||||
http.Error(w, "bad json", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
upstreams := normalizeBenchmarkUpstreams(req.Upstreams)
|
||||
if len(upstreams) == 0 {
|
||||
pool := loadDNSUpstreamPoolState()
|
||||
if len(pool) > 0 {
|
||||
tmp := make([]DNSBenchmarkUpstream, 0, len(pool))
|
||||
for _, item := range pool {
|
||||
tmp = append(tmp, DNSBenchmarkUpstream{Addr: item.Addr, Enabled: item.Enabled})
|
||||
}
|
||||
upstreams = normalizeBenchmarkUpstreams(tmp)
|
||||
}
|
||||
if len(upstreams) == 0 {
|
||||
cfg := loadDNSUpstreamsConf()
|
||||
upstreams = dnscfgpkg.NormalizeBenchmarkUpstreamStrings([]string{
|
||||
cfg.Default1,
|
||||
cfg.Default2,
|
||||
cfg.Meta1,
|
||||
cfg.Meta2,
|
||||
}, normalizeDNSUpstream)
|
||||
}
|
||||
}
|
||||
if len(upstreams) == 0 {
|
||||
http.Error(w, "no upstreams", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
domains := dnscfgpkg.NormalizeBenchmarkDomains(req.Domains)
|
||||
if len(domains) == 0 {
|
||||
domains = append(domains, dnsBenchmarkDefaultDomains...)
|
||||
}
|
||||
|
||||
timeoutMS := req.TimeoutMS
|
||||
if timeoutMS <= 0 {
|
||||
timeoutMS = 1800
|
||||
}
|
||||
if timeoutMS < 300 {
|
||||
timeoutMS = 300
|
||||
}
|
||||
if timeoutMS > 5000 {
|
||||
timeoutMS = 5000
|
||||
}
|
||||
|
||||
attempts := req.Attempts
|
||||
if attempts <= 0 {
|
||||
attempts = 1
|
||||
}
|
||||
if attempts > 3 {
|
||||
attempts = 3
|
||||
}
|
||||
profile := dnscfgpkg.NormalizeBenchmarkProfile(req.Profile)
|
||||
if profile == dnsBenchmarkProfileLoad && attempts < 2 {
|
||||
// Load profile should emulate real resolver pressure.
|
||||
attempts = 2
|
||||
}
|
||||
|
||||
concurrency := req.Concurrency
|
||||
if concurrency <= 0 {
|
||||
concurrency = 6
|
||||
}
|
||||
if concurrency < 1 {
|
||||
concurrency = 1
|
||||
}
|
||||
if concurrency > 32 {
|
||||
concurrency = 32
|
||||
}
|
||||
if concurrency > len(upstreams) {
|
||||
concurrency = len(upstreams)
|
||||
}
|
||||
opts := dnscfgpkg.MakeDNSBenchmarkOptions(profile, concurrency)
|
||||
|
||||
results := make([]DNSBenchmarkResult, 0, len(upstreams))
|
||||
var mu sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
sem := make(chan struct{}, concurrency)
|
||||
timeout := time.Duration(timeoutMS) * time.Millisecond
|
||||
|
||||
for _, upstream := range upstreams {
|
||||
wg.Add(1)
|
||||
sem <- struct{}{}
|
||||
go func(upstream string) {
|
||||
defer wg.Done()
|
||||
defer func() { <-sem }()
|
||||
result := benchmarkDNSUpstream(upstream, domains, timeout, attempts, opts)
|
||||
mu.Lock()
|
||||
results = append(results, result)
|
||||
mu.Unlock()
|
||||
}(upstream)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
if results[i].Score == results[j].Score {
|
||||
if results[i].AvgMS == results[j].AvgMS {
|
||||
if results[i].OK == results[j].OK {
|
||||
return results[i].Upstream < results[j].Upstream
|
||||
}
|
||||
return results[i].OK > results[j].OK
|
||||
}
|
||||
return results[i].AvgMS < results[j].AvgMS
|
||||
}
|
||||
return results[i].Score > results[j].Score
|
||||
})
|
||||
|
||||
resp := DNSBenchmarkResponse{
|
||||
Results: results,
|
||||
DomainsUsed: domains,
|
||||
TimeoutMS: timeoutMS,
|
||||
AttemptsPerDomain: attempts,
|
||||
Profile: profile,
|
||||
}
|
||||
resp.RecommendedDefault = benchmarkTopN(results, 2, upstreams)
|
||||
resp.RecommendedMeta = benchmarkTopN(results, 2, upstreams)
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
Reference in New Issue
Block a user