173 lines
3.6 KiB
Go
173 lines
3.6 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"os/signal"
|
||
"syscall"
|
||
"time"
|
||
|
||
"github.com/meowrain/nodeprobe/internal/netstat"
|
||
)
|
||
|
||
func main() {
|
||
// 1. 获取初始数据
|
||
prevStats, err := netstat.GetInterfaceStats()
|
||
if err != nil {
|
||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
if len(prevStats) == 0 {
|
||
fmt.Println("No network interfaces found")
|
||
os.Exit(1)
|
||
}
|
||
|
||
// 2. 设置刷新间隔(默认 1 秒)
|
||
interval := 1 * time.Second
|
||
|
||
// 3. 隐藏光标
|
||
fmt.Print("\033[?25l")
|
||
defer fmt.Print("\033[?25h") // 退出时恢复光标
|
||
|
||
// 4. 创建 ticker 定时器
|
||
ticker := time.NewTicker(interval)
|
||
defer ticker.Stop()
|
||
|
||
// 5. 监听 Ctrl+C 退出
|
||
sigChan := make(chan os.Signal, 1)
|
||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||
|
||
// 6. 首次显示
|
||
clearScreen()
|
||
currStats, _ := netstat.GetInterfaceStats()
|
||
rates := netstat.CalculateRate(prevStats, currStats, interval)
|
||
printHeader()
|
||
printStats(rates, currStats)
|
||
prevStats = currStats
|
||
|
||
// 7. 主循环
|
||
for {
|
||
select {
|
||
case <-ticker.C:
|
||
// 获取当前统计数据
|
||
currStats, err := netstat.GetInterfaceStats()
|
||
if err != nil {
|
||
continue
|
||
}
|
||
|
||
// 计算速率
|
||
rates := netstat.CalculateRate(prevStats, currStats, interval)
|
||
|
||
// 移动光标到开头并打印统计
|
||
moveCursorToTop()
|
||
printHeader()
|
||
printStats(rates, currStats)
|
||
|
||
// 更新上一次的数据
|
||
prevStats = currStats
|
||
|
||
case <-sigChan:
|
||
fmt.Print("\033[?25h") // 恢复光标
|
||
fmt.Println("\nExiting...")
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清屏
|
||
func clearScreen() {
|
||
fmt.Print("\033[2J")
|
||
fmt.Print("\033[H")
|
||
}
|
||
|
||
// 移动光标到顶部
|
||
func moveCursorToTop() {
|
||
fmt.Print("\033[H")
|
||
}
|
||
|
||
func printHeader() {
|
||
fmt.Println("Network Interface Traffic Monitor")
|
||
fmt.Println("----------------------------------")
|
||
fmt.Printf("%-20s %30s %30s %15s %15s\n",
|
||
"Interface", "Download", "Upload", "RX Total", "TX Total")
|
||
fmt.Println("----------------------------------")
|
||
}
|
||
|
||
func printStats(rates []netstat.TrafficRate, stats []netstat.InterfaceStats) {
|
||
// 创建统计 map
|
||
statsMap := make(map[string]netstat.InterfaceStats)
|
||
for _, s := range stats {
|
||
statsMap[s.Name] = s
|
||
}
|
||
|
||
// 找出最大速率用于归一化
|
||
maxRate := 0.0
|
||
for _, r := range rates {
|
||
if r.RxKbps*1000 > maxRate {
|
||
maxRate = r.RxKbps * 1000
|
||
}
|
||
if r.TxKbps*1000 > maxRate {
|
||
maxRate = r.TxKbps * 1000
|
||
}
|
||
}
|
||
if maxRate == 0 {
|
||
maxRate = 1
|
||
}
|
||
|
||
for _, r := range rates {
|
||
s := statsMap[r.Name]
|
||
|
||
// 生成下载和上传的可视化条形图
|
||
rxBar := makeTrafficBar(r.RxKbps*1000, maxRate, true)
|
||
txBar := makeTrafficBar(r.TxKbps*1000, maxRate, false)
|
||
|
||
fmt.Printf("%-20s %30s %30s %15s %15s\n",
|
||
r.Name,
|
||
rxBar,
|
||
txBar,
|
||
netstat.FormatBytes(float64(s.RxBytes)),
|
||
netstat.FormatBytes(float64(s.TxBytes)),
|
||
)
|
||
}
|
||
// 清除剩余行(如果接口数量减少)
|
||
fmt.Print("\033[J")
|
||
}
|
||
|
||
// 生成流量条形图
|
||
func makeTrafficBar(bps, maxBps float64, isDownload bool) string {
|
||
// ANSI 颜色代码
|
||
green := "\033[32m" // 下载用绿色
|
||
blue := "\033[36m" // 上传用青色
|
||
reset := "\033[0m"
|
||
|
||
color := blue
|
||
if isDownload {
|
||
color = green
|
||
}
|
||
|
||
// 计算条形图长度(最多10个字符)
|
||
barLength := 10
|
||
filledLength := int((bps / maxBps) * float64(barLength))
|
||
if filledLength > barLength {
|
||
filledLength = barLength
|
||
}
|
||
|
||
// 使用不同的字符显示强度
|
||
blocks := []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
|
||
bar := ""
|
||
|
||
for i := 0; i < barLength; i++ {
|
||
if i < filledLength {
|
||
bar += string(blocks[7]) // 满格
|
||
} else {
|
||
bar += string(blocks[0]) // 空格
|
||
}
|
||
}
|
||
|
||
// 格式化速率信息
|
||
speedStr := netstat.FormatBps(bps)
|
||
|
||
return fmt.Sprintf("%s%s%s %9s", color, bar, reset, speedStr)
|
||
}
|