rebuild download

This commit is contained in:
mazhuang
2021-11-10 17:12:12 +08:00
parent 4d64abb94d
commit f1a9b5c966
8 changed files with 287 additions and 390 deletions

149
task/download.go Normal file
View 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)
}

View File

@@ -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"
)

View File

@@ -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),
}