github.com/cavaliergopher/grab/v3@v3.0.1/pkg/bps/bps.go (about)

     1  /*
     2  Package bps provides gauges for calculating the Bytes Per Second transfer rate
     3  of data streams.
     4  */
     5  package bps
     6  
     7  import (
     8  	"context"
     9  	"time"
    10  )
    11  
    12  // Gauge is the common interface for all BPS gauges in this package. Given a
    13  // set of samples over time, each gauge type can be used to measure the Bytes
    14  // Per Second transfer rate of a data stream.
    15  //
    16  // All samples must monotonically increase in timestamp and value. Each sample
    17  // should represent the total number of bytes sent in a stream, rather than
    18  // accounting for the number sent since the last sample.
    19  //
    20  // To ensure a gauge can report progress as quickly as possible, take an initial
    21  // sample when your stream first starts.
    22  //
    23  // All gauge implementations are safe for concurrent use.
    24  type Gauge interface {
    25  	// Sample adds a new sample of the progress of the monitored stream.
    26  	Sample(t time.Time, n int64)
    27  
    28  	// BPS returns the calculated Bytes Per Second rate of the monitored stream.
    29  	BPS() float64
    30  }
    31  
    32  // SampleFunc is used by Watch to take periodic samples of a monitored stream.
    33  type SampleFunc func() (n int64)
    34  
    35  // Watch will periodically call the given SampleFunc to sample the progress of
    36  // a monitored stream and update the given gauge. SampleFunc should return the
    37  // total number of bytes transferred by the stream since it started.
    38  //
    39  // Watch is a blocking call and should typically be called in a new goroutine.
    40  // To prevent the goroutine from leaking, make sure to cancel the given context
    41  // once the stream is completed or canceled.
    42  func Watch(ctx context.Context, g Gauge, f SampleFunc, interval time.Duration) {
    43  	g.Sample(time.Now(), f())
    44  	t := time.NewTicker(interval)
    45  	defer t.Stop()
    46  	for {
    47  		select {
    48  		case <-ctx.Done():
    49  			return
    50  		case now := <-t.C:
    51  			g.Sample(now, f())
    52  		}
    53  	}
    54  }