CloudflareSpeedTest/utils/csv.go

188 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package utils
import (
"encoding/csv"
"fmt"
"log"
"net"
"os"
"strconv"
"time"
)
const (
defaultOutput = "result.csv"
maxDelay = 9999 * time.Millisecond
minDelay = 0 * time.Millisecond
maxLossRate float32 = 1.0
)
var (
InputMaxDelay = maxDelay
InputMinDelay = minDelay
InputMaxLossRate = maxLossRate
Output = defaultOutput
PrintNum = 10
)
// 是否打印测试结果
func NoPrintResult() bool {
return PrintNum == 0
}
// 是否输出到文件
func noOutput() bool {
return Output == "" || Output == " "
}
type PingData struct {
IP *net.IPAddr
Sended int
Received int
Delay time.Duration
}
type CloudflareIPData struct {
*PingData
lossRate float32
DownloadSpeed float64
}
// 计算丢包率
func (cf *CloudflareIPData) getLossRate() float32 {
if cf.lossRate == 0 {
pingLost := cf.Sended - cf.Received
cf.lossRate = float32(pingLost) / float32(cf.Sended)
}
return cf.lossRate
}
func (cf *CloudflareIPData) toString() []string {
result := make([]string, 6)
result[0] = cf.IP.String()
result[1] = strconv.Itoa(cf.Sended)
result[2] = strconv.Itoa(cf.Received)
result[3] = strconv.FormatFloat(float64(cf.getLossRate()), 'f', 2, 32)
result[4] = strconv.FormatFloat(cf.Delay.Seconds()*1000, 'f', 2, 32)
result[5] = strconv.FormatFloat(cf.DownloadSpeed/1024/1024, 'f', 2, 32)
return result
}
func ExportCsv(data []CloudflareIPData) {
if noOutput() || len(data) == 0 {
return
}
fp, err := os.Create(Output)
if err != nil {
log.Fatalf("创建文件[%s]失败:%v", Output, err)
return
}
defer fp.Close()
w := csv.NewWriter(fp) //创建一个新的写入文件流
_ = w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"})
_ = w.WriteAll(convertToString(data))
w.Flush()
}
func convertToString(data []CloudflareIPData) [][]string {
result := make([][]string, 0)
for _, v := range data {
result = append(result, v.toString())
}
return result
}
// 延迟丢包排序
type PingDelaySet []CloudflareIPData
// 延迟条件过滤
func (s PingDelaySet) FilterDelay() (data PingDelaySet) {
if InputMaxDelay > maxDelay || InputMinDelay < minDelay { // 当输入的延迟条件不在默认范围内时,不进行过滤
return s
}
if InputMaxDelay == maxDelay && InputMinDelay == minDelay { // 当输入的延迟条件为默认值时,不进行过滤
return s
}
for _, v := range s {
if v.Delay > InputMaxDelay { // 平均延迟上限,延迟大于条件最大值时,后面的数据都不满足条件,直接跳出循环
break
}
if v.Delay < InputMinDelay { // 平均延迟下限,延迟小于条件最小值时,不满足条件,跳过
continue
}
data = append(data, v) // 延迟满足条件时,添加到新数组中
}
return
}
// 丢包条件过滤
func (s PingDelaySet) FilterLossRate() (data PingDelaySet) {
if InputMaxLossRate >= maxLossRate { // 当输入的丢包条件为默认值时,不进行过滤
return s
}
for _, v := range s {
if v.getLossRate() > InputMaxLossRate { // 丢包几率上限
break
}
data = append(data, v) // 丢包率满足条件时,添加到新数组中
}
return
}
func (s PingDelaySet) Len() int {
return len(s)
}
func (s PingDelaySet) Less(i, j int) bool {
iRate, jRate := s[i].getLossRate(), s[j].getLossRate()
if iRate != jRate {
return iRate < jRate
}
return s[i].Delay < s[j].Delay
}
func (s PingDelaySet) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// 下载速度排序
type DownloadSpeedSet []CloudflareIPData
func (s DownloadSpeedSet) Len() int {
return len(s)
}
func (s DownloadSpeedSet) Less(i, j int) bool {
return s[i].DownloadSpeed > s[j].DownloadSpeed
}
func (s DownloadSpeedSet) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s DownloadSpeedSet) Print() {
if NoPrintResult() {
return
}
if len(s) <= 0 { // IP数组长度(IP数量) 大于 0 时继续
fmt.Println("\n[信息] 完整测速结果 IP 数量为 0跳过输出结果。")
return
}
dateString := convertToString(s) // 转为多维数组 [][]String
if len(dateString) < PrintNum { // 如果IP数组长度(IP数量) 小于 打印次数则次数改为IP数量
PrintNum = len(dateString)
}
headFormat := "%-16s%-5s%-5s%-5s%-6s%-11s\n"
dataFormat := "%-18s%-8s%-8s%-8s%-10s%-15s\n"
for i := 0; i < PrintNum; i++ { // 如果要输出的 IP 中包含 IPv6那么就需要调整一下间隔
if len(dateString[i][0]) > 15 {
headFormat = "%-40s%-5s%-5s%-5s%-6s%-11s\n"
dataFormat = "%-42s%-8s%-8s%-8s%-10s%-15s\n"
break
}
}
fmt.Printf(headFormat, "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)")
for i := 0; i < PrintNum; i++ {
fmt.Printf(dataFormat, dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5])
}
if !noOutput() {
fmt.Printf("\n完整测速结果已写入 %v 文件,可使用记事本/表格软件查看。\n", Output)
}
}