diff --git a/src/slow/reader.go b/src/slow/reader.go new file mode 100644 index 0000000..137c721 --- /dev/null +++ b/src/slow/reader.go @@ -0,0 +1,39 @@ +package slow + +import ( + "context" + "io" + + "golang.org/x/time/rate" +) + +type Reader struct { + ctx context.Context + limiter *rate.Limiter + r io.Reader +} + +var _ io.Reader = Reader{} + +func NewReader(ctx context.Context, bps rate.Limit, r io.Reader) Reader { + return Reader{ + ctx: ctx, + limiter: rate.NewLimiter(bps, 8192), + r: r, + } +} + +func (r Reader) Read(b []byte) (int, error) { + n, err := r.r.Read(b) + + m := 0 + burst := r.limiter.Burst() + for m < n { + if err := r.limiter.WaitN(r.ctx, burst); err != nil { + return n, err + } + m += burst + } + + return n, err +} diff --git a/src/slow/reader_test.go b/src/slow/reader_test.go new file mode 100644 index 0000000..981e6e4 --- /dev/null +++ b/src/slow/reader_test.go @@ -0,0 +1,20 @@ +package slow_test + +import "show-rss/src/slow" +import "testing" +import "context" +import "bytes" +import "io" + +func TestReader(t *testing.T) { + junk := bytes.NewReader(bytes.Repeat([]byte("1"), 256_000)) + + slowReader := slow.NewReader(context.Background(), 300_000, junk) + + buff := bytes.NewBuffer(nil) + if n, err := io.Copy(buff, slowReader); err != nil { + t.Fatal(err) + } else if n != 256_000 { + t.Fatal(n) + } +}