/
speeduser.go
138 lines (120 loc) · 3.04 KB
/
speeduser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package healthcheck
import (
"bytes"
"encoding/xml"
"errors"
"math"
"time"
C "github.com/Dreamacro/clash/constant"
)
// Server information
type Server struct {
URL string `xml:"url,attr"`
Lat string `xml:"lat,attr"`
Lon string `xml:"lon,attr"`
Name string `xml:"name,attr"`
Country string `xml:"country,attr"`
Sponsor string `xml:"sponsor,attr"`
ID string `xml:"id,attr"`
URL2 string `xml:"url2,attr"`
Host string `xml:"host,attr"`
Distance float64
DLSpeed float64
}
// ServerList : List of Server. for xml decoding
type ServerList struct {
Servers []Server `xml:"servers>server"`
}
// Servers : For sorting servers.
type Servers []Server
// ByDistance : For sorting servers.
type ByDistance struct {
Servers
}
// Len : length of servers. For sorting servers.
func (s Servers) Len() int {
return len(s)
}
// Swap : swap i-th and j-th. For sorting servers.
func (s Servers) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// Less : compare the distance. For sorting servers.
func (b ByDistance) Less(i, j int) bool {
return b.Servers[i].Distance < b.Servers[j].Distance
}
func fetchServerList(clashProxy C.Proxy) (ServerList, error) {
url := "http://www.speedtest.net/speedtest-servers-static.php"
body, err := HTTPGetBodyViaProxy(clashProxy, url)
if err != nil {
return ServerList{}, err
}
if len(body) == 0 {
url = "http://c.speedtest.net/speedtest-servers-static.php"
body, err = HTTPGetBodyViaProxy(clashProxy, url)
if err != nil {
return ServerList{}, err
}
}
// Decode xml
decoder := xml.NewDecoder(bytes.NewReader(body))
var serverList ServerList
for {
t, _ := decoder.Token()
if t == nil {
break
}
switch se := t.(type) {
case xml.StartElement:
_ = decoder.DecodeElement(&serverList, &se)
}
}
if len(serverList.Servers) == 0 {
return ServerList{}, errors.New("no speedtest server")
}
return serverList, nil
}
func distance(lat1 float64, lon1 float64, lat2 float64, lon2 float64) float64 {
radius := 6378.137
a1 := lat1 * math.Pi / 180.0
b1 := lon1 * math.Pi / 180.0
a2 := lat2 * math.Pi / 180.0
b2 := lon2 * math.Pi / 180.0
x := math.Sin(a1)*math.Sin(a2) + math.Cos(a1)*math.Cos(a2)*math.Cos(b2-b1)
return radius * math.Acos(x)
}
// StartTest : start testing to the servers.
func (svrs Servers) StartTest(clashProxy C.Proxy) {
for i := range svrs {
latency := pingTest(clashProxy, svrs[i].URL)
if latency == time.Second*5 { // fail to get latency, skip
continue
} else {
dlSpeed := downloadTest(clashProxy, svrs[i].URL, latency)
if dlSpeed > 0 {
svrs[i].DLSpeed = dlSpeed
break // once effective, end the test
}
}
}
}
// GetResult : return testing result. -1 for no effective result
func (svrs Servers) GetResult() float64 {
if len(svrs) == 1 {
return svrs[0].DLSpeed
} else {
avgDL := 0.0
count := 0
for _, s := range svrs {
if s.DLSpeed > 0 {
avgDL = avgDL + s.DLSpeed
count++
}
}
if count == 0 {
return -1
}
//fmt.Printf("Download Avg: %5.2f Mbit/s\n", avgDL/float64(len(svrs)))
return avgDL / float64(count)
}
}