106 lines
2.3 KiB
Go
106 lines
2.3 KiB
Go
package bitrate
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// Bitrate allows calculating bitrates for a set of network interfaces.
|
|
// This implementation is not thread-safe.
|
|
type Bitrate struct {
|
|
measures map[string]*measure
|
|
minDelayBetweenMeasures time.Duration
|
|
}
|
|
|
|
// New returns a new bitrate measurer.
|
|
func New(minDelayBetweenMeasures time.Duration) *Bitrate {
|
|
return &Bitrate{
|
|
measures: make(map[string]*measure),
|
|
minDelayBetweenMeasures: minDelayBetweenMeasures,
|
|
}
|
|
}
|
|
|
|
// mesure saves the counter values at a specific point in time.
|
|
type measure struct {
|
|
Counters
|
|
Last time.Time
|
|
}
|
|
|
|
// Counters contain Tx and Rx counters for a network interface.
|
|
type Counters struct {
|
|
Tx, Rx uint64
|
|
}
|
|
|
|
// Swap swaps Tx and Rx counters.
|
|
func (c *Counters) Swap() {
|
|
c.Rx, c.Tx = c.Tx, c.Rx
|
|
}
|
|
|
|
// Bitrates for Tx and Rx.
|
|
type Bitrates struct {
|
|
// Tx bitrate, can be nil if not available.
|
|
Tx *BitrateSpec
|
|
// Rx bitrate, can be nil if not available.
|
|
Rx *BitrateSpec
|
|
}
|
|
|
|
// BitrateSpec contains the value of the bitrate
|
|
type BitrateSpec struct {
|
|
// Value of the bitrate (in Mbit/s). Will be 0 if Reset is true.
|
|
Value float64
|
|
// Reset is true when the counter was reset.
|
|
Reset bool
|
|
}
|
|
|
|
// ShouldMeasure returns true if a measure should be done.
|
|
func (b *Bitrate) ShouldMeasure(name string) bool {
|
|
last, ok := b.measures[name]
|
|
if !ok {
|
|
return true
|
|
}
|
|
|
|
return time.Now().Sub(last.Last) > b.minDelayBetweenMeasures
|
|
}
|
|
|
|
// Measure saves the current measure and returns the current RX/TX bitrates.
|
|
func (b *Bitrate) Measure(name string, current *Counters) *Bitrates {
|
|
br := &Bitrates{}
|
|
|
|
last, ok := b.measures[name]
|
|
|
|
// Only calculate bitrates if there is a previous measure.
|
|
if ok && !last.Last.IsZero() {
|
|
elapsed := time.Now().Sub(last.Last)
|
|
|
|
if elapsed.Seconds() > 0 {
|
|
diff := current.Rx - last.Rx
|
|
if diff >= 0 {
|
|
br.Rx = &BitrateSpec{
|
|
Value: BytesPerSecToMbits(float64(diff) / elapsed.Seconds()),
|
|
}
|
|
} else {
|
|
br.Rx = &BitrateSpec{
|
|
Reset: true,
|
|
}
|
|
}
|
|
|
|
diff = current.Tx - last.Tx
|
|
if diff >= 0 {
|
|
br.Tx = &BitrateSpec{
|
|
Value: BytesPerSecToMbits(float64(diff) / elapsed.Seconds()),
|
|
}
|
|
} else {
|
|
br.Tx = &BitrateSpec{
|
|
Reset: true,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save this measure as the latest.
|
|
b.measures[name] = &measure{
|
|
Counters: *current,
|
|
Last: time.Now(),
|
|
}
|
|
|
|
return br
|
|
}
|