download.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package task
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "net"
  7. "net/http"
  8. "sort"
  9. "time"
  10. "CloudflareSpeedTest/utils"
  11. "github.com/VividCortex/ewma"
  12. )
  13. const (
  14. bufferSize = 1024
  15. defaultURL = "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png"
  16. defaultTimeout = 10 * time.Second
  17. defaultDisableDownload = false
  18. defaultTestNum = 10
  19. defaultMinSpeed float64 = 0.0
  20. )
  21. var (
  22. // download test url
  23. URL = defaultURL
  24. // download timeout
  25. Timeout = defaultTimeout
  26. // disable download
  27. Disable = defaultDisableDownload
  28. TestCount = defaultTestNum
  29. MinSpeed = defaultMinSpeed
  30. )
  31. func checkDownloadDefault() {
  32. if URL == "" {
  33. URL = defaultURL
  34. }
  35. if Timeout <= 0 {
  36. Timeout = defaultTimeout
  37. }
  38. if TestCount <= 0 {
  39. TestCount = defaultTestNum
  40. }
  41. if MinSpeed <= 0.0 {
  42. MinSpeed = defaultMinSpeed
  43. }
  44. }
  45. func TestDownloadSpeed(ipSet utils.PingDelaySet) (speedSet utils.DownloadSpeedSet) {
  46. checkDownloadDefault()
  47. if Disable {
  48. return utils.DownloadSpeedSet(ipSet)
  49. }
  50. if len(ipSet) <= 0 { // IP数组长度(IP数量) 大于 0 时才会继续下载测速
  51. fmt.Println("\n[信息] 延迟测速结果 IP 数量为 0,跳过下载测速。")
  52. return
  53. }
  54. testNum := TestCount
  55. if len(ipSet) < TestCount || MinSpeed > 0 { // 如果IP数组长度(IP数量) 小于下载测速数量(-dn),则次数修正为IP数
  56. testNum = len(ipSet)
  57. }
  58. fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum)
  59. bar := utils.NewBar(TestCount)
  60. for i := 0; i < testNum; i++ {
  61. speed := downloadHandler(ipSet[i].IP)
  62. ipSet[i].DownloadSpeed = speed
  63. // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果
  64. if speed >= MinSpeed*1024*1024 {
  65. bar.Grow(1)
  66. speedSet = append(speedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中
  67. if len(speedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环
  68. break
  69. }
  70. }
  71. }
  72. bar.Done()
  73. if len(speedSet) == 0 { // 没有符合速度限制的数据,返回所有测试数据
  74. speedSet = utils.DownloadSpeedSet(ipSet)
  75. }
  76. // 按速度排序
  77. sort.Sort(speedSet)
  78. return
  79. }
  80. func getDialContext(ip *net.IPAddr) func(ctx context.Context, network, address string) (net.Conn, error) {
  81. fakeSourceAddr := ip.String() + ":443"
  82. if IPv6 { // IPv6 需要加上 []
  83. fakeSourceAddr = "[" + ip.String() + "]:443"
  84. }
  85. return func(ctx context.Context, network, address string) (net.Conn, error) {
  86. return (&net.Dialer{}).DialContext(ctx, network, fakeSourceAddr)
  87. }
  88. }
  89. // return download Speed
  90. func downloadHandler(ip *net.IPAddr) float64 {
  91. client := &http.Client{
  92. Transport: &http.Transport{DialContext: getDialContext(ip)},
  93. Timeout: Timeout,
  94. }
  95. response, err := client.Get(URL)
  96. if err != nil {
  97. return 0.0
  98. }
  99. defer response.Body.Close()
  100. if response.StatusCode != 200 {
  101. return 0.0
  102. }
  103. timeStart := time.Now()
  104. timeEnd := timeStart.Add(Timeout)
  105. contentLength := response.ContentLength
  106. buffer := make([]byte, bufferSize)
  107. var (
  108. contentRead int64 = 0
  109. timeSlice = Timeout / 100
  110. timeCounter = 1
  111. lastContentRead int64 = 0
  112. )
  113. var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
  114. e := ewma.NewMovingAverage()
  115. for contentLength != contentRead {
  116. currentTime := time.Now()
  117. if currentTime.After(nextTime) {
  118. timeCounter++
  119. nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
  120. e.Add(float64(contentRead - lastContentRead))
  121. lastContentRead = contentRead
  122. }
  123. if currentTime.After(timeEnd) {
  124. break
  125. }
  126. bufferRead, err := response.Body.Read(buffer)
  127. if err != nil {
  128. if err != io.EOF {
  129. break
  130. }
  131. e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice)))
  132. }
  133. contentRead += int64(bufferRead)
  134. }
  135. return e.Value() / (Timeout.Seconds() / 120)
  136. }