mirror of
https://github.com/XIU2/CloudflareSpeedTest.git
synced 2026-03-17 21:06:03 +08:00
rebuild download
This commit is contained in:
149
task/download.go
Normal file
149
task/download.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"CloudflareSpeedTest/utils"
|
||||
|
||||
"github.com/VividCortex/ewma"
|
||||
)
|
||||
|
||||
const (
|
||||
bufferSize = 1024
|
||||
defaultURL = "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png"
|
||||
defaultTimeout = 10 * time.Second
|
||||
defaultDisableDownlaod = false
|
||||
defaultTestNum = 20
|
||||
defaultMinSpeed float64 = 0.0
|
||||
)
|
||||
|
||||
var (
|
||||
// download test url
|
||||
URL = defaultURL
|
||||
// download timeout
|
||||
Timeout = defaultTimeout
|
||||
// disable download
|
||||
Disable = defaultDisableDownlaod
|
||||
|
||||
TestCount = defaultTestNum
|
||||
MinSpeed = defaultMinSpeed
|
||||
)
|
||||
|
||||
func checkDownloadDefault() {
|
||||
if URL == "" {
|
||||
URL = defaultURL
|
||||
}
|
||||
if Timeout <= 0 {
|
||||
Timeout = defaultTimeout
|
||||
}
|
||||
if TestCount <= 0 {
|
||||
TestCount = defaultTestNum
|
||||
}
|
||||
if MinSpeed <= 0.0 {
|
||||
MinSpeed = defaultMinSpeed
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadSpeed(ipSet utils.PingDelaySet) (sppedSet utils.DownloadSpeedSet) {
|
||||
checkDownloadDefault()
|
||||
if Disable {
|
||||
return utils.DownloadSpeedSet(ipSet)
|
||||
}
|
||||
if len(ipSet) <= 0 { // IP数组长度(IP数量) 大于 0 时才会继续下载测速
|
||||
fmt.Println("\n[信息] 延迟测速结果 IP 数量为 0,跳过下载测速。")
|
||||
return
|
||||
}
|
||||
testNum := TestCount
|
||||
if len(ipSet) < TestCount || MinSpeed > 0 { // 如果IP数组长度(IP数量) 小于下载测速数量(-dn),则次数修正为IP数
|
||||
testNum = len(ipSet)
|
||||
}
|
||||
|
||||
fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum)
|
||||
bar := utils.NewBar(TestCount)
|
||||
for i := 0; i < testNum; i++ {
|
||||
speed := downloadSpeedHandler(&ipSet[i].IP)
|
||||
ipSet[i].DownloadSpeed = speed
|
||||
// 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果
|
||||
if speed >= MinSpeed*1024*1024 {
|
||||
sppedSet = append(sppedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中
|
||||
bar.Grow(1)
|
||||
if len(sppedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
bar.Done()
|
||||
// 按速度排序
|
||||
sort.Sort(sppedSet)
|
||||
return
|
||||
}
|
||||
|
||||
func getDialContext(ip *net.IPAddr) func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
fakeSourceAddr := ip.String() + ":443"
|
||||
if IPv6 { // IPv6 需要加上 []
|
||||
fakeSourceAddr = "[" + ip.String() + "]:443"
|
||||
}
|
||||
return func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return (&net.Dialer{}).DialContext(ctx, network, fakeSourceAddr)
|
||||
}
|
||||
}
|
||||
|
||||
//bool : can download,float32 downloadSpeed
|
||||
func downloadSpeedHandler(ip *net.IPAddr) float64 {
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{DialContext: getDialContext(ip)},
|
||||
Timeout: Timeout,
|
||||
}
|
||||
response, err := client.Get(URL)
|
||||
if err != nil {
|
||||
return 0.0
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != 200 {
|
||||
return 0.0
|
||||
}
|
||||
timeStart := time.Now()
|
||||
timeEnd := timeStart.Add(Timeout)
|
||||
|
||||
contentLength := response.ContentLength
|
||||
buffer := make([]byte, bufferSize)
|
||||
|
||||
var (
|
||||
contentRead int64 = 0
|
||||
timeSlice = Timeout / 100
|
||||
timeCounter = 1
|
||||
lastContentRead int64 = 0
|
||||
)
|
||||
|
||||
var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
|
||||
e := ewma.NewMovingAverage()
|
||||
|
||||
for contentLength != contentRead {
|
||||
currentTime := time.Now()
|
||||
if currentTime.After(nextTime) {
|
||||
timeCounter++
|
||||
nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
|
||||
e.Add(float64(contentRead - lastContentRead))
|
||||
lastContentRead = contentRead
|
||||
}
|
||||
if currentTime.After(timeEnd) {
|
||||
break
|
||||
}
|
||||
bufferRead, err := response.Body.Read(buffer)
|
||||
contentRead += int64(bufferRead)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
break
|
||||
}
|
||||
e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice)))
|
||||
}
|
||||
}
|
||||
return e.Value() / (Timeout.Seconds() / 120)
|
||||
|
||||
}
|
||||
@@ -3,4 +3,8 @@ package task
|
||||
var (
|
||||
// IPv6 IP version is 6
|
||||
IPv6 = false
|
||||
// TestAll test all ip
|
||||
TestAll = false
|
||||
// IPFile is the filename of IP Rangs
|
||||
IPFile = "ip.txt"
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ package task
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -12,12 +13,15 @@ import (
|
||||
const (
|
||||
tcpConnectTimeout = time.Second * 1
|
||||
maxRoutine = 1000
|
||||
defaultRoutines = 200
|
||||
defaultPort = 443
|
||||
defaultPingTimes = 4
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultRoutine = 200
|
||||
TCPPort int = 443
|
||||
PingTimes int = 4
|
||||
Routines = defaultRoutines
|
||||
TCPPort int = defaultPort
|
||||
PingTimes int = defaultPingTimes
|
||||
)
|
||||
|
||||
type Ping struct {
|
||||
@@ -29,14 +33,27 @@ type Ping struct {
|
||||
bar *utils.Bar
|
||||
}
|
||||
|
||||
func checkPingDefault() {
|
||||
if Routines <= 0 {
|
||||
Routines = defaultRoutines
|
||||
}
|
||||
if TCPPort <= 0 || TCPPort >= 65535 {
|
||||
TCPPort = defaultPort
|
||||
}
|
||||
if PingTimes <= 0 {
|
||||
PingTimes = defaultPingTimes
|
||||
}
|
||||
}
|
||||
|
||||
func NewPing(ips []net.IPAddr) *Ping {
|
||||
checkPingDefault()
|
||||
return &Ping{
|
||||
wg: &sync.WaitGroup{},
|
||||
m: &sync.Mutex{},
|
||||
ips: ips,
|
||||
csv: make(utils.PingDelaySet, 0),
|
||||
control: make(chan bool, DefaultRoutine),
|
||||
bar: utils.NewBar(len(ips) * PingTimes),
|
||||
control: make(chan bool, Routines),
|
||||
bar: utils.NewBar(len(ips)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +65,7 @@ func (p *Ping) Run() utils.PingDelaySet {
|
||||
}
|
||||
p.wg.Wait()
|
||||
p.bar.Done()
|
||||
sort.Sort(p.csv)
|
||||
return p.csv
|
||||
}
|
||||
|
||||
@@ -112,7 +130,7 @@ func (p *Ping) tcpingHandler(ip net.IPAddr) {
|
||||
break
|
||||
}
|
||||
}
|
||||
p.bar.Grow(PingTimes)
|
||||
p.bar.Grow(1)
|
||||
if !ipCanConnect {
|
||||
return
|
||||
}
|
||||
@@ -126,7 +144,7 @@ func (p *Ping) tcpingHandler(ip net.IPAddr) {
|
||||
// }
|
||||
data := &utils.PingData{
|
||||
IP: ip,
|
||||
Sended: PingTimes,
|
||||
Sended: PingTimes,
|
||||
Received: pingRecv,
|
||||
Delay: delay / time.Duration(pingRecv),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user