64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
package aggregate
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/netsynth/netsynth/classify"
|
||
|
|
)
|
||
|
|
|
||
|
|
// DefaultWindowMs is the default time window duration in milliseconds.
|
||
|
|
const DefaultWindowMs = 500
|
||
|
|
|
||
|
|
// Aggregate reads ClassifiedPackets from events, accumulates counts per TrafficClass
|
||
|
|
// in time windows of windowMs duration, and emits a WindowSnapshot per window.
|
||
|
|
// When done is closed, flushes the current partial window and closes the output channel.
|
||
|
|
// If onSnapshot is non-nil, it is called with each snapshot before sending to the output channel
|
||
|
|
// (used for --verbose stderr output).
|
||
|
|
func Aggregate(done <-chan struct{}, events <-chan classify.ClassifiedPacket,
|
||
|
|
windowMs int, onSnapshot func(classify.WindowSnapshot)) <-chan classify.WindowSnapshot {
|
||
|
|
|
||
|
|
out := make(chan classify.WindowSnapshot, 8)
|
||
|
|
go func() {
|
||
|
|
defer close(out)
|
||
|
|
ticker := time.NewTicker(time.Duration(windowMs) * time.Millisecond)
|
||
|
|
defer ticker.Stop()
|
||
|
|
|
||
|
|
counts := make(map[classify.TrafficClass]int64)
|
||
|
|
var totalPackets int64
|
||
|
|
windowIndex := 0
|
||
|
|
|
||
|
|
flush := func() {
|
||
|
|
snap := classify.WindowSnapshot{
|
||
|
|
Counts: counts,
|
||
|
|
TotalPackets: totalPackets,
|
||
|
|
WindowIndex: windowIndex,
|
||
|
|
}
|
||
|
|
if onSnapshot != nil {
|
||
|
|
onSnapshot(snap)
|
||
|
|
}
|
||
|
|
out <- snap
|
||
|
|
counts = make(map[classify.TrafficClass]int64)
|
||
|
|
totalPackets = 0
|
||
|
|
windowIndex++
|
||
|
|
}
|
||
|
|
|
||
|
|
for {
|
||
|
|
select {
|
||
|
|
case <-done:
|
||
|
|
flush() // flush final partial window
|
||
|
|
return
|
||
|
|
case <-ticker.C:
|
||
|
|
flush()
|
||
|
|
case ev, ok := <-events:
|
||
|
|
if !ok {
|
||
|
|
flush()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
counts[ev.Class]++
|
||
|
|
totalPackets++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}()
|
||
|
|
return out
|
||
|
|
}
|