safing-portmaster/spn/navigator/map_stats.go

85 lines
1.8 KiB
Go

package navigator
import (
"fmt"
"sort"
"strings"
)
// MapStats holds generic map statistics.
type MapStats struct {
Name string
States map[PinState]int
Lanes map[int]int
ActiveTerminals int
}
// Stats collects and returns statistics from the map.
func (m *Map) Stats() *MapStats {
m.Lock()
defer m.Unlock()
// Create stats struct.
stats := &MapStats{
Name: m.Name,
States: make(map[PinState]int),
Lanes: make(map[int]int),
}
for _, state := range allStates {
stats.States[state] = 0
}
// Iterate over all Pins to collect data.
for _, pin := range m.all {
// Count active terminals.
if pin.HasActiveTerminal() {
stats.ActiveTerminals++
}
// Check all states.
for _, state := range allStates {
if pin.State.Has(state) {
stats.States[state]++
}
}
// Count lanes.
laneCnt, ok := stats.Lanes[len(pin.ConnectedTo)]
if ok {
stats.Lanes[len(pin.ConnectedTo)] = laneCnt + 1
} else {
stats.Lanes[len(pin.ConnectedTo)] = 1
}
}
return stats
}
func (ms *MapStats) String() string {
var builder strings.Builder
// Write header.
fmt.Fprintf(&builder, "Stats for Map %s:\n", ms.Name)
// Write State Stats
stateSummary := make([]string, 0, len(ms.States))
for state, cnt := range ms.States {
stateSummary = append(stateSummary, fmt.Sprintf("State %s: %d Hubs", state, cnt))
}
sort.Strings(stateSummary)
for _, stateSum := range stateSummary {
fmt.Fprintln(&builder, stateSum)
}
// Write Lane Stats
laneStats := make([]string, 0, len(ms.Lanes))
for laneCnt, pinCnt := range ms.Lanes {
laneStats = append(laneStats, fmt.Sprintf("%d Lanes: %d Hubs", laneCnt, pinCnt))
}
sort.Strings(laneStats)
for _, laneStat := range laneStats {
fmt.Fprintln(&builder, laneStat)
}
return builder.String()
}