initial commit
This commit is contained in:
131
internal/collector/sort.go
Normal file
131
internal/collector/sort.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SortField represents a field to sort by
|
||||
type SortField string
|
||||
|
||||
const (
|
||||
SortByPID SortField = "pid"
|
||||
SortByProcess SortField = "process"
|
||||
SortByUser SortField = "user"
|
||||
SortByProto SortField = "proto"
|
||||
SortByState SortField = "state"
|
||||
SortByLaddr SortField = "laddr"
|
||||
SortByLport SortField = "lport"
|
||||
SortByRaddr SortField = "raddr"
|
||||
SortByRport SortField = "rport"
|
||||
SortByInterface SortField = "if"
|
||||
SortByRxBytes SortField = "rx_bytes"
|
||||
SortByTxBytes SortField = "tx_bytes"
|
||||
SortByRttMs SortField = "rtt_ms"
|
||||
SortByTimestamp SortField = "ts"
|
||||
)
|
||||
|
||||
// SortDirection represents ascending or descending order
|
||||
type SortDirection int
|
||||
|
||||
const (
|
||||
SortAsc SortDirection = iota
|
||||
SortDesc
|
||||
)
|
||||
|
||||
// SortOptions configures how connections are sorted
|
||||
type SortOptions struct {
|
||||
Field SortField
|
||||
Direction SortDirection
|
||||
}
|
||||
|
||||
// ParseSortOptions parses a sort string like "pid:desc" or "lport"
|
||||
func ParseSortOptions(s string) SortOptions {
|
||||
if s == "" {
|
||||
return SortOptions{Field: SortByLport, Direction: SortAsc}
|
||||
}
|
||||
|
||||
parts := strings.SplitN(s, ":", 2)
|
||||
field := SortField(strings.ToLower(parts[0]))
|
||||
direction := SortAsc
|
||||
|
||||
if len(parts) > 1 && strings.ToLower(parts[1]) == "desc" {
|
||||
direction = SortDesc
|
||||
}
|
||||
|
||||
return SortOptions{Field: field, Direction: direction}
|
||||
}
|
||||
|
||||
// SortConnections sorts a slice of connections in place
|
||||
func SortConnections(conns []Connection, opts SortOptions) {
|
||||
if len(conns) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
sort.SliceStable(conns, func(i, j int) bool {
|
||||
less := compareConnections(conns[i], conns[j], opts.Field)
|
||||
if opts.Direction == SortDesc {
|
||||
return !less
|
||||
}
|
||||
return less
|
||||
})
|
||||
}
|
||||
|
||||
func compareConnections(a, b Connection, field SortField) bool {
|
||||
switch field {
|
||||
case SortByPID:
|
||||
return a.PID < b.PID
|
||||
case SortByProcess:
|
||||
return strings.ToLower(a.Process) < strings.ToLower(b.Process)
|
||||
case SortByUser:
|
||||
return strings.ToLower(a.User) < strings.ToLower(b.User)
|
||||
case SortByProto:
|
||||
return a.Proto < b.Proto
|
||||
case SortByState:
|
||||
return stateOrder(a.State) < stateOrder(b.State)
|
||||
case SortByLaddr:
|
||||
return a.Laddr < b.Laddr
|
||||
case SortByLport:
|
||||
return a.Lport < b.Lport
|
||||
case SortByRaddr:
|
||||
return a.Raddr < b.Raddr
|
||||
case SortByRport:
|
||||
return a.Rport < b.Rport
|
||||
case SortByInterface:
|
||||
return a.Interface < b.Interface
|
||||
case SortByRxBytes:
|
||||
return a.RxBytes < b.RxBytes
|
||||
case SortByTxBytes:
|
||||
return a.TxBytes < b.TxBytes
|
||||
case SortByRttMs:
|
||||
return a.RttMs < b.RttMs
|
||||
case SortByTimestamp:
|
||||
return a.TS.Before(b.TS)
|
||||
default:
|
||||
return a.Lport < b.Lport
|
||||
}
|
||||
}
|
||||
|
||||
// stateOrder returns a numeric order for connection states
|
||||
// puts LISTEN first, then ESTABLISHED, then others
|
||||
func stateOrder(state string) int {
|
||||
order := map[string]int{
|
||||
"LISTEN": 0,
|
||||
"ESTABLISHED": 1,
|
||||
"SYN_SENT": 2,
|
||||
"SYN_RECV": 3,
|
||||
"FIN_WAIT1": 4,
|
||||
"FIN_WAIT2": 5,
|
||||
"TIME_WAIT": 6,
|
||||
"CLOSE_WAIT": 7,
|
||||
"LAST_ACK": 8,
|
||||
"CLOSING": 9,
|
||||
"CLOSED": 10,
|
||||
}
|
||||
|
||||
if o, exists := order[strings.ToUpper(state)]; exists {
|
||||
return o
|
||||
}
|
||||
return 99
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user