diff --git a/src/framework/utils/ping/ping.go b/src/framework/utils/ping/ping.go new file mode 100644 index 0000000..24635d1 --- /dev/null +++ b/src/framework/utils/ping/ping.go @@ -0,0 +1,139 @@ +package ping + +import ( + "encoding/json" + "fmt" + "runtime" + "time" + + probing "github.com/prometheus-community/pro-bing" +) + +// Ping 探针发包参数 +type Ping struct { + DesAddr string `json:"desAddr"` // 目的 IP 地址(字符串类型,必填) + VRFName string `json:"vrfName"` // VRF 名称(字符串类型,可选) + DSCP int `json:"dscp"` // DSCP 优先级(整数类型,可选,取值范围:0-63,默认值:0) + SrcAddr string `json:"srcAddr"` // 源 IP 地址(字符串类型,可选) + SendInterval int `json:"sendInterval"` // 发包间隔(整数类型,可选,单位:毫秒,取值范围:10-10000,默认值:1000) + TTL int `json:"ttl"` // TTL(整数类型,可选,取值范围:1-255,默认值:255) + SentPkts int `json:"sentPkts"` // 发包数(整数类型,可选,取值范围:1-65535,默认值:5) + Size int `json:"size"` // 报文大小(整数类型,可选,取值范围:36-8192,默认值:36) + TimeOut int `json:"timeOut"` // 报文超时时间(整数类型,可选,单位:秒,取值范围:1-60,默认值:2) +} + +// CopyFrom 将map复制到当前同key名的结构体 +func (p *Ping) CopyFrom(from any) error { + b, err := json.Marshal(from) + if err != nil { + return err + } + if err = json.Unmarshal(b, p); err != nil { + return err + } + return nil +} + +// setDefaultValue 设置默认值 +func (p *Ping) setDefaultValue() { + if p.SendInterval < 10 || p.SendInterval > 10000 { + p.SendInterval = 1000 + } + if p.TTL < 1 || p.TTL > 255 { + p.TTL = 255 + } + if p.SentPkts < 1 || p.SentPkts > 65535 { + p.SentPkts = 5 + } + if p.Size < 36 || p.Size > 8192 { + p.Size = 36 + } + if p.DSCP < 0 || p.DSCP > 63 { + p.DSCP = 0 + } + if p.TimeOut < 1 || p.TimeOut > 60 { + p.TimeOut = 2 + } +} + +// Statistics ping数据结果 +func (p *Ping) Statistics() (*probing.Statistics, error) { + p.setDefaultValue() + + pinger, err := probing.NewPinger(p.DesAddr) + if err != nil { + return nil, err + } + if p.SrcAddr != "" { + pinger.Source = p.SrcAddr + } + pinger.Interval = time.Duration(p.SendInterval) * time.Millisecond + pinger.TTL = p.TTL + pinger.Count = p.SentPkts + pinger.Size = p.Size + pinger.Timeout = time.Duration(p.TimeOut) * time.Second + + // 设置特权模式(需要管理员权限) + if runtime.GOOS == "windows" { + pinger.SetPrivileged(true) + } + err = pinger.Run() + if err != nil { + fmt.Println(err) + return nil, err + } + + return pinger.Statistics(), nil +} + +// StatsInfo ping基本信息 +func (p *Ping) StatsInfo() (map[string]any, error) { + stats, err := p.Statistics() + if err != nil { + return nil, err + } + return map[string]any{ + "minTime": stats.MinRtt.Milliseconds(), // 最小时延(整数类型,可选,单位:毫秒) + "maxTime": stats.MaxRtt.Milliseconds(), // 最大时延(整数类型,可选,单位:毫秒) + "avgTime": stats.AvgRtt.Milliseconds(), // 平均时延(整数类型,可选,单位:毫秒) + "lossRate": int64(stats.PacketLoss), // 丢包率(整数类型,可选,单位:%) + "jitter": stats.StdDevRtt.Milliseconds(), // 时延抖动(整数类型,可选,单位:毫秒) + }, nil +} + +// StatsInfo ping探测发送的所有往返时间 +func (p *Ping) StatsRtt() (map[string][]map[string]any, error) { + stats, err := p.Statistics() + if err != nil { + return nil, err + } + data := map[string][]map[string]any{ + // hopList 节点列表 + "hopList": { + { + // hopIndex 序号 + "hopIndex": 1, + // probeList 探测信息列表 + "probeList": []map[string]any{ + { + "probeIndex": 1, // probeIndex 探测报文序号 + "hopAddress": "-", // hopAddress 地址 + "probeTime": 0, // probeTime 探测时长 + }, + }, + }, + }, + } + + rtts := []map[string]any{} + for i, tts := range stats.Rtts { + rtts = append(rtts, map[string]any{ + "probeIndex": i + 1, // probeIndex 探测报文序号 + "hopAddress": stats.IPAddr.String(), // hopAddress 地址 + "probeTime": tts.Milliseconds(), // probeTime 探测时长 + }) + } + data["hopList"][0]["probeList"] = rtts + + return data, nil +}