169 lines
4.4 KiB
Go
169 lines
4.4 KiB
Go
package widgets
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/VictoriaMetrics/metrics"
|
|
psNet "github.com/shirou/gopsutil/v3/net"
|
|
|
|
ui "github.com/xxxserxxx/gotop/v4/termui"
|
|
"github.com/xxxserxxx/gotop/v4/utils"
|
|
)
|
|
|
|
const (
|
|
// NetInterfaceAll enables all network interfaces
|
|
NetInterfaceAll = "all"
|
|
// NetInterfaceVpn is the VPN interface
|
|
NetInterfaceVpn = "tun0"
|
|
)
|
|
|
|
type NetWidget struct {
|
|
*ui.SparklineGroup
|
|
updateInterval time.Duration
|
|
|
|
// used to calculate recent network activity
|
|
totalBytesRecv uint64
|
|
totalBytesSent uint64
|
|
NetInterface []string
|
|
sentMetric *metrics.Counter
|
|
recvMetric *metrics.Counter
|
|
Mbps bool
|
|
}
|
|
|
|
// TODO: state:merge #169 % option for network use (jrswab/networkPercentage)
|
|
func NewNetWidget(netInterface string) *NetWidget {
|
|
recvSparkline := ui.NewSparkline()
|
|
recvSparkline.Data = []int{}
|
|
|
|
sentSparkline := ui.NewSparkline()
|
|
sentSparkline.Data = []int{}
|
|
|
|
spark := ui.NewSparklineGroup(recvSparkline, sentSparkline)
|
|
self := &NetWidget{
|
|
SparklineGroup: spark,
|
|
updateInterval: time.Second,
|
|
NetInterface: strings.Split(netInterface, ","),
|
|
}
|
|
self.Title = tr.Value("widget.label.net")
|
|
if netInterface != "all" {
|
|
self.Title = tr.Value("widget.label.netint", netInterface)
|
|
}
|
|
|
|
self.update()
|
|
|
|
go func() {
|
|
for range time.NewTicker(self.updateInterval).C {
|
|
self.Lock()
|
|
self.update()
|
|
self.Unlock()
|
|
}
|
|
}()
|
|
|
|
return self
|
|
}
|
|
|
|
func (net *NetWidget) EnableMetric() {
|
|
net.recvMetric = metrics.NewCounter(makeName("net", "recv"))
|
|
net.sentMetric = metrics.NewCounter(makeName("net", "sent"))
|
|
}
|
|
|
|
func (net *NetWidget) update() {
|
|
interfaces, err := psNet.IOCounters(true)
|
|
if err != nil {
|
|
log.Println(tr.Value("widget.net.err.netactivity", err.Error()))
|
|
return
|
|
}
|
|
|
|
var totalBytesRecv uint64
|
|
var totalBytesSent uint64
|
|
interfaceMap := make(map[string]bool)
|
|
// Default behaviour
|
|
interfaceMap[NetInterfaceAll] = true
|
|
interfaceMap[NetInterfaceVpn] = false
|
|
// Build a map with wanted status for each interfaces.
|
|
for _, iface := range net.NetInterface {
|
|
if strings.HasPrefix(iface, "!") {
|
|
interfaceMap[strings.TrimPrefix(iface, "!")] = false
|
|
} else {
|
|
// if we specify a wanted interface, remove capture on all.
|
|
delete(interfaceMap, NetInterfaceAll)
|
|
interfaceMap[iface] = true
|
|
}
|
|
}
|
|
for _, _interface := range interfaces {
|
|
wanted, ok := interfaceMap[_interface.Name]
|
|
if wanted && ok { // Simple case
|
|
totalBytesRecv += _interface.BytesRecv
|
|
totalBytesSent += _interface.BytesSent
|
|
} else if ok { // Present but unwanted
|
|
continue
|
|
} else if interfaceMap[NetInterfaceAll] { // Capture other
|
|
totalBytesRecv += _interface.BytesRecv
|
|
totalBytesSent += _interface.BytesSent
|
|
}
|
|
}
|
|
|
|
var recentBytesRecv uint64
|
|
var recentBytesSent uint64
|
|
|
|
if net.totalBytesRecv != 0 { // if this isn't the first update
|
|
recentBytesRecv = totalBytesRecv - net.totalBytesRecv
|
|
recentBytesSent = totalBytesSent - net.totalBytesSent
|
|
|
|
if int(recentBytesRecv) < 0 {
|
|
v := fmt.Sprintf("%d", recentBytesRecv)
|
|
log.Println(tr.Value("widget.net.err.negvalrecv", v))
|
|
// recover from error
|
|
recentBytesRecv = 0
|
|
}
|
|
if int(recentBytesSent) < 0 {
|
|
v := fmt.Sprintf("%d", recentBytesSent)
|
|
log.Printf(tr.Value("widget.net.err.negvalsent", v))
|
|
// recover from error
|
|
recentBytesSent = 0
|
|
}
|
|
|
|
net.Lines[0].Data = append(net.Lines[0].Data, int(recentBytesRecv))
|
|
net.Lines[1].Data = append(net.Lines[1].Data, int(recentBytesSent))
|
|
if net.sentMetric != nil {
|
|
net.sentMetric.Add(int(recentBytesSent))
|
|
net.recvMetric.Add(int(recentBytesRecv))
|
|
}
|
|
}
|
|
|
|
// used in later calls to update
|
|
net.totalBytesRecv = totalBytesRecv
|
|
net.totalBytesSent = totalBytesSent
|
|
|
|
rx, tx := "RX/s", "TX/s"
|
|
if net.Mbps {
|
|
rx, tx = "mbps", "mbps"
|
|
}
|
|
format := " %s: %9.1f %2s/s"
|
|
|
|
var total, recent uint64
|
|
var label, unitRecent, rate string
|
|
var recentConverted float64
|
|
// render widget titles
|
|
for i := 0; i < 2; i++ {
|
|
if i == 0 {
|
|
total, label, rate, recent = totalBytesRecv, "RX", rx, recentBytesRecv
|
|
} else {
|
|
total, label, rate, recent = totalBytesSent, "TX", tx, recentBytesSent
|
|
}
|
|
|
|
totalConverted, unitTotal := utils.ConvertBytes(total)
|
|
if net.Mbps {
|
|
recentConverted, unitRecent, format = float64(recent)*0.000008, "", " %s: %11.3f %2s"
|
|
} else {
|
|
recentConverted, unitRecent = utils.ConvertBytes(recent)
|
|
}
|
|
|
|
net.Lines[i].Title1 = fmt.Sprintf(" %s %s: %5.1f %s", tr.Value("total"), label, totalConverted, unitTotal)
|
|
net.Lines[i].Title2 = fmt.Sprintf(format, rate, recentConverted, unitRecent)
|
|
}
|
|
}
|