1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 18:34:46 +00:00

imp: mo status network graph

This commit is contained in:
Andrei Murariu
2026-01-15 14:53:34 +02:00
parent 9cdd0c868a
commit 205f3adbd2
3 changed files with 93 additions and 18 deletions

View File

@@ -22,18 +22,19 @@ type MetricsSnapshot struct {
HealthScore int // 0-100 system health score
HealthScoreMsg string // Brief explanation
CPU CPUStatus
GPU []GPUStatus
Memory MemoryStatus
Disks []DiskStatus
DiskIO DiskIOStatus
Network []NetworkStatus
Proxy ProxyStatus
Batteries []BatteryStatus
Thermal ThermalStatus
Sensors []SensorReading
Bluetooth []BluetoothDevice
TopProcesses []ProcessInfo
CPU CPUStatus
GPU []GPUStatus
Memory MemoryStatus
Disks []DiskStatus
DiskIO DiskIOStatus
Network []NetworkStatus
NetworkHistory NetworkHistory
Proxy ProxyStatus
Batteries []BatteryStatus
Thermal ThermalStatus
Sensors []SensorReading
Bluetooth []BluetoothDevice
TopProcesses []ProcessInfo
}
type HardwareInfo struct {
@@ -104,6 +105,12 @@ type NetworkStatus struct {
TxRateMBs float64
IP string
}
type NetworkHistory struct {
RxHistory []float64
TxHistory []float64
}
const NetworkHistorySize = 20 // number of checks to keep
type ProxyStatus struct {
Enabled bool
@@ -156,6 +163,7 @@ type Collector struct {
// Fast metrics (1s).
prevNet map[string]net.IOCountersStat
lastNetAt time.Time
netHistory NetworkHistory
lastGPUAt time.Time
cachedGPU []GPUStatus
prevDiskIO disk.IOCountersStat
@@ -263,6 +271,7 @@ func (c *Collector) Collect() (MetricsSnapshot, error) {
Disks: diskStats,
DiskIO: diskIO,
Network: netStats,
NetworkHistory: c.netHistory,
Proxy: proxyStats,
Batteries: batteryStats,
Thermal: thermalStats,

View File

@@ -70,6 +70,20 @@ func (c *Collector) collectNetwork(now time.Time) ([]NetworkStatus, error) {
result = result[:3]
}
var totalRx, totalTx float64
for _, r := range result {
totalRx += r.RxRateMBs
totalTx += r.TxRateMBs
}
c.netHistory.RxHistory = append(c.netHistory.RxHistory, totalRx)
c.netHistory.TxHistory = append(c.netHistory.TxHistory, totalTx)
if len(c.netHistory.RxHistory) > NetworkHistorySize {
c.netHistory.RxHistory = c.netHistory.RxHistory[len(c.netHistory.RxHistory)-NetworkHistorySize:]
}
if len(c.netHistory.TxHistory) > NetworkHistorySize {
c.netHistory.TxHistory = c.netHistory.TxHistory[len(c.netHistory.TxHistory)-NetworkHistorySize:]
}
return result, nil
}

View File

@@ -208,7 +208,7 @@ func buildCards(m MetricsSnapshot, _ int) []cardData {
renderDiskCard(m.Disks, m.DiskIO),
renderBatteryCard(m.Batteries, m.Thermal),
renderProcessCard(m.TopProcesses),
renderNetworkCard(m.Network, m.Proxy),
renderNetworkCard(m.Network, m.NetworkHistory, m.Proxy),
}
if hasSensorData(m.Sensors) {
cards = append(cards, renderSensorsCard(m.Sensors))
@@ -425,7 +425,7 @@ func miniBar(percent float64) string {
return colorizePercent(percent, strings.Repeat("▮", filled)+strings.Repeat("▯", 5-filled))
}
func renderNetworkCard(netStats []NetworkStatus, proxy ProxyStatus) cardData {
func renderNetworkCard(netStats []NetworkStatus, history NetworkHistory, proxy ProxyStatus) cardData {
var lines []string
var totalRx, totalTx float64
var primaryIP string
@@ -441,10 +441,11 @@ func renderNetworkCard(netStats []NetworkStatus, proxy ProxyStatus) cardData {
if len(netStats) == 0 {
lines = []string{subtleStyle.Render("Collecting...")}
} else {
rxBar := netBar(totalRx)
txBar := netBar(totalTx)
lines = append(lines, fmt.Sprintf("Down %s %s", rxBar, formatRate(totalRx)))
lines = append(lines, fmt.Sprintf("Up %s %s", txBar, formatRate(totalTx)))
// sparkline graphs
rxSparkline := sparkline(history.RxHistory, totalRx)
txSparkline := sparkline(history.TxHistory, totalTx)
lines = append(lines, fmt.Sprintf("Down %s %s", rxSparkline, formatRate(totalRx)))
lines = append(lines, fmt.Sprintf("Up %s %s", txSparkline, formatRate(totalTx)))
// Show proxy and IP on one line.
var infoParts []string
if proxy.Enabled {
@@ -475,6 +476,57 @@ func netBar(rate float64) string {
return okStyle.Render(bar)
}
// 8 levels: ▁▂▃▄▅▆▇█
func sparkline(history []float64, current float64) string {
const width = 16
blocks := []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
data := make([]float64, 0, width)
if len(history) > 0 {
// Take the most recent points.
start := 0
if len(history) > width {
start = len(history) - width
}
data = append(data, history[start:]...)
}
// padding with zeros at the start
for len(data) < width {
data = append([]float64{0}, data...)
}
if len(data) > width {
data = data[len(data)-width:]
}
maxVal := 0.1
for _, v := range data {
if v > maxVal {
maxVal = v
}
}
var builder strings.Builder
for _, v := range data {
level := int((v / maxVal) * float64(len(blocks)-1))
if level < 0 {
level = 0
}
if level >= len(blocks) {
level = len(blocks) - 1
}
builder.WriteRune(blocks[level])
}
result := builder.String()
if current > 8 {
return dangerStyle.Render(result)
}
if current > 3 {
return warnStyle.Render(result)
}
return okStyle.Render(result)
}
func renderBatteryCard(batts []BatteryStatus, thermal ThermalStatus) cardData {
var lines []string
if len(batts) == 0 {