mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 08:23:50 +01:00
80 lines
1.5 KiB
Go
80 lines
1.5 KiB
Go
package bandwidthlimit
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
|
|
"github.com/juju/ratelimit"
|
|
)
|
|
|
|
type Wrapper interface {
|
|
WrapReadCloser(io.ReadCloser) io.ReadCloser
|
|
}
|
|
|
|
type Config struct {
|
|
// Units in this struct are in _bytes_.
|
|
|
|
Max int64 // < 0 means no limit, BucketCapacity is irrelevant then
|
|
BucketCapacity int64
|
|
}
|
|
|
|
func NoLimitConfig() Config {
|
|
return Config{
|
|
Max: -1,
|
|
BucketCapacity: -1,
|
|
}
|
|
}
|
|
|
|
func ValidateConfig(conf Config) error {
|
|
if conf.BucketCapacity == 0 {
|
|
return errors.New("BucketCapacity must not be zero")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func WrapperFromConfig(conf Config) Wrapper {
|
|
if err := ValidateConfig(conf); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if conf.Max < 0 {
|
|
return noLimit{}
|
|
}
|
|
|
|
return &withLimit{
|
|
bucket: ratelimit.NewBucketWithRate(float64(conf.Max), conf.BucketCapacity),
|
|
}
|
|
}
|
|
|
|
type noLimit struct{}
|
|
|
|
func (_ noLimit) WrapReadCloser(rc io.ReadCloser) io.ReadCloser { return rc }
|
|
|
|
type withLimit struct {
|
|
bucket *ratelimit.Bucket
|
|
}
|
|
|
|
func (l *withLimit) WrapReadCloser(rc io.ReadCloser) io.ReadCloser {
|
|
return WrapReadCloser(rc, l.bucket)
|
|
}
|
|
|
|
type withLimitReadCloser struct {
|
|
orig io.Closer
|
|
limited io.Reader
|
|
}
|
|
|
|
func (r *withLimitReadCloser) Read(buf []byte) (int, error) {
|
|
return r.limited.Read(buf)
|
|
}
|
|
|
|
func (r *withLimitReadCloser) Close() error {
|
|
return r.orig.Close()
|
|
}
|
|
|
|
func WrapReadCloser(rc io.ReadCloser, bucket *ratelimit.Bucket) io.ReadCloser {
|
|
return &withLimitReadCloser{
|
|
limited: ratelimit.Reader(rc, bucket),
|
|
orig: rc,
|
|
}
|
|
}
|