ipv6 network test
This commit is contained in:
226
pkg/http/ip.go
226
pkg/http/ip.go
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
@@ -15,150 +14,161 @@ import (
|
||||
)
|
||||
|
||||
type IPRepository struct {
|
||||
ipv4 []string
|
||||
ipv6 []string
|
||||
latencyMap map[string]float64
|
||||
log *logutil.Logger
|
||||
ipv4client *HTTPClient
|
||||
ipv6client *HTTPClient
|
||||
ipv4latencyMap map[string]float64
|
||||
ipv6latencyMap map[string]float64
|
||||
log *logutil.Logger
|
||||
}
|
||||
|
||||
func NewIPRepository(log *logutil.Logger) *IPRepository {
|
||||
func NewIPRepository(ipv4client *HTTPClient, ipv6client *HTTPClient, log *logutil.Logger) *IPRepository {
|
||||
repo := &IPRepository{
|
||||
ipv4: []string{},
|
||||
ipv6: []string{},
|
||||
latencyMap: make(map[string]float64),
|
||||
log: log,
|
||||
ipv4client: ipv4client,
|
||||
ipv6client: ipv6client,
|
||||
ipv4latencyMap: make(map[string]float64),
|
||||
ipv6latencyMap: make(map[string]float64),
|
||||
log: log,
|
||||
}
|
||||
|
||||
repo.lookupDomains()
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func (r *IPRepository) NetworkTest(downloadClient *HTTPClient, forceRun bool) {
|
||||
latencyFile := "data/latency.json"
|
||||
func (r *IPRepository) NetworkTest(forceRun bool) {
|
||||
ipv4latencyFile := "data/latency4.json"
|
||||
ipv6latencyFile := "data/latency6.json"
|
||||
if !forceRun {
|
||||
latencyData := r.readLatencyFile(latencyFile)
|
||||
latencyData := r.readLatencyFile(ipv4latencyFile)
|
||||
if latencyData != nil {
|
||||
r.latencyMap = *latencyData
|
||||
return
|
||||
r.ipv4latencyMap = *latencyData
|
||||
}
|
||||
latencyData = r.readLatencyFile(ipv6latencyFile)
|
||||
if latencyData != nil {
|
||||
r.ipv6latencyMap = *latencyData
|
||||
}
|
||||
}
|
||||
|
||||
r.log.Info("Network test will start now. Note that it will only run once and record the latency of each domain for future use.")
|
||||
r.latencyTest(downloadClient)
|
||||
r.log.Infof("Network test completed. Saving the results to %s", latencyFile)
|
||||
r.writeLatencyFile(latencyFile)
|
||||
r.log.Info("Network test will start now. IGNORE THE WARNINGS!")
|
||||
r.runLatencyTest()
|
||||
r.log.Infof("Network test completed. Saving the results to %s and %s", ipv4latencyFile, ipv6latencyFile)
|
||||
r.log.Debugf("ipv4 %v", r.ipv4latencyMap)
|
||||
r.log.Debugf("ipv6 %v", r.ipv6latencyMap)
|
||||
r.writeLatencyFile(ipv4latencyFile, r.ipv4latencyMap)
|
||||
r.writeLatencyFile(ipv6latencyFile, r.ipv6latencyMap)
|
||||
}
|
||||
|
||||
func (r *IPRepository) lookupDomains() {
|
||||
func (r *IPRepository) runLatencyTest() {
|
||||
limit := 99
|
||||
increment := 10
|
||||
start := 0
|
||||
for {
|
||||
lastDomainWorked := false
|
||||
lastDomainsWorked := false
|
||||
for i := start; i <= limit; i++ {
|
||||
domain := fmt.Sprintf("%d.download.real-debrid.com", i)
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err == nil && len(ips) > 0 {
|
||||
hasIPv6 := false
|
||||
for _, ip := range ips {
|
||||
if ip.To4() == nil {
|
||||
hasIPv6 = true
|
||||
}
|
||||
}
|
||||
// assume it always has ipv4
|
||||
r.ipv4 = append(r.ipv4, domain)
|
||||
if hasIPv6 {
|
||||
r.ipv6 = append(r.ipv6, domain)
|
||||
}
|
||||
if i == limit {
|
||||
lastDomainWorked = true
|
||||
// ips, err := net.LookupIP(domain)
|
||||
// if err != nil || len(ips) == 0 {
|
||||
// continue
|
||||
// }
|
||||
|
||||
latency, err := r.testDomainLatency(r.ipv4client, domain)
|
||||
if err == nil {
|
||||
r.ipv4latencyMap[domain] = latency
|
||||
r.log.Debugf("Latency from ipv4 %s: %.5f seconds", domain, latency)
|
||||
if i >= limit-2 {
|
||||
lastDomainsWorked = true
|
||||
}
|
||||
}
|
||||
|
||||
domain2 := fmt.Sprintf("%d.download.real-debrid.cloud", i)
|
||||
ips2, err := net.LookupIP(domain2)
|
||||
if err == nil && len(ips2) > 0 {
|
||||
hasIPv6 := false
|
||||
for _, ip := range ips {
|
||||
if ip.To4() == nil {
|
||||
hasIPv6 = true
|
||||
}
|
||||
latency, err = r.testDomainLatency(r.ipv6client, domain)
|
||||
if err == nil {
|
||||
r.ipv6latencyMap[domain] = latency
|
||||
r.log.Debugf("Latency from ipv6 %s: %.5f seconds", domain, latency)
|
||||
if i >= limit-2 {
|
||||
lastDomainsWorked = true
|
||||
}
|
||||
r.ipv4 = append(r.ipv4, domain2)
|
||||
if hasIPv6 {
|
||||
r.ipv6 = append(r.ipv6, domain2)
|
||||
}
|
||||
|
||||
domain = fmt.Sprintf("%d.download.real-debrid.cloud", i)
|
||||
// ips, err = net.LookupIP(domain)
|
||||
// if err != nil || len(ips) == 0 {
|
||||
// continue
|
||||
// }
|
||||
|
||||
latency, err = r.testDomainLatency(r.ipv4client, domain)
|
||||
if err == nil {
|
||||
r.ipv4latencyMap[domain] = latency
|
||||
r.log.Debugf("Latency from ipv4 %s: %.5f seconds", domain, latency)
|
||||
if i >= limit-2 {
|
||||
lastDomainsWorked = true
|
||||
}
|
||||
if i == limit {
|
||||
lastDomainWorked = true
|
||||
}
|
||||
|
||||
latency, err = r.testDomainLatency(r.ipv6client, domain)
|
||||
if err == nil {
|
||||
r.ipv6latencyMap[domain] = latency
|
||||
r.log.Debugf("Latency from ipv6 %s: %.5f seconds", domain, latency)
|
||||
if i >= limit-2 {
|
||||
lastDomainsWorked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if lastDomainWorked {
|
||||
if lastDomainsWorked {
|
||||
start = limit + 1
|
||||
limit += increment
|
||||
limit += 10
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
r.log.Infof("Found %d IPv4 domains and %d IPv6 domains", len(r.ipv4), len(r.ipv6))
|
||||
}
|
||||
|
||||
func (r *IPRepository) latencyTest(downloadClient *HTTPClient) {
|
||||
const testFileSize = 1
|
||||
func (r *IPRepository) testDomainLatency(client *HTTPClient, domain string) (float64, error) {
|
||||
const testFileSize = 1 // byte
|
||||
const iterations = 3
|
||||
url := fmt.Sprintf("https://%s/speedtest/test.rar/%f", domain, rand.Float64())
|
||||
|
||||
for _, domain := range r.ipv4 {
|
||||
url := fmt.Sprintf("https://%s/speedtest/test.rar/%f", domain, rand.Float64())
|
||||
var totalDuration float64
|
||||
var retErr error
|
||||
for i := 0; i < iterations; i++ {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var totalDuration float64
|
||||
hasError := false
|
||||
for i := 0; i < iterations; i++ {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), iterations*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
r.log.Warnf("Failed to create request for %s: %v", domain, err)
|
||||
hasError = true
|
||||
break
|
||||
}
|
||||
|
||||
headers := make(http.Header)
|
||||
headers.Set("Range", fmt.Sprintf("bytes=0-%d", testFileSize-1))
|
||||
req.Header = headers
|
||||
|
||||
start := time.Now()
|
||||
resp, err := downloadClient.Do(req)
|
||||
if err != nil {
|
||||
r.log.Warnf("Failed to download from %s: %v", domain, err)
|
||||
hasError = true
|
||||
break
|
||||
}
|
||||
|
||||
limitedReader := io.LimitReader(resp.Body, testFileSize)
|
||||
|
||||
_, err = io.Copy(io.Discard, limitedReader)
|
||||
resp.Body.Close()
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
r.log.Warnf("Failed to read from %s: %v", domain, err)
|
||||
hasError = true
|
||||
break
|
||||
}
|
||||
|
||||
duration := time.Since(start).Seconds()
|
||||
totalDuration += duration
|
||||
}
|
||||
if hasError {
|
||||
continue
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
r.log.Warnf("Failed to create request for %s: %v", domain, err)
|
||||
retErr = err
|
||||
break
|
||||
}
|
||||
|
||||
r.latencyMap[domain] = totalDuration / 3
|
||||
headers := make(http.Header)
|
||||
headers.Set("Range", fmt.Sprintf("bytes=0-%d", testFileSize-1))
|
||||
req.Header = headers
|
||||
|
||||
r.log.Debugf("Latency from %s: %.5f seconds", domain, r.latencyMap[domain])
|
||||
start := time.Now()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
r.log.Warnf("Failed to download from %s: %v", domain, err)
|
||||
retErr = err
|
||||
break
|
||||
}
|
||||
|
||||
limitedReader := io.LimitReader(resp.Body, testFileSize)
|
||||
|
||||
_, err = io.Copy(io.Discard, limitedReader)
|
||||
resp.Body.Close()
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
r.log.Warnf("Failed to read from %s: %v", domain, err)
|
||||
retErr = err
|
||||
break
|
||||
}
|
||||
|
||||
duration := time.Since(start).Seconds()
|
||||
totalDuration += duration
|
||||
}
|
||||
if retErr != nil {
|
||||
return 0, retErr
|
||||
}
|
||||
|
||||
avgDuration := totalDuration / 3
|
||||
return avgDuration, nil
|
||||
}
|
||||
|
||||
func (r *IPRepository) readLatencyFile(latencyFile string) *map[string]float64 {
|
||||
@@ -172,16 +182,16 @@ func (r *IPRepository) readLatencyFile(latencyFile string) *map[string]float64 {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var latencyMap map[string]float64
|
||||
if err := json.Unmarshal(jsonData, &latencyMap); err != nil {
|
||||
var ipv4latencyMap map[string]float64
|
||||
if err := json.Unmarshal(jsonData, &ipv4latencyMap); err != nil {
|
||||
return nil
|
||||
}
|
||||
return &latencyMap
|
||||
return &ipv4latencyMap
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *IPRepository) writeLatencyFile(latencyFile string) {
|
||||
func (r *IPRepository) writeLatencyFile(latencyFile string, data interface{}) {
|
||||
file, err := os.Create(latencyFile)
|
||||
if err != nil {
|
||||
r.log.Warnf("Cannot create latency file %s: %v", latencyFile, err)
|
||||
@@ -189,7 +199,7 @@ func (r *IPRepository) writeLatencyFile(latencyFile string) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
jsonData, err := json.Marshal(r.latencyMap)
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
r.log.Warnf("Cannot marshal latency map: %v", err)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user