|
|
- //
- // Written by Maxim Khitrov (November 2012)
- //
-
- package flowrate
-
- import (
- "errors"
- "io"
- )
-
- // ErrLimit is returned by the Writer when a non-blocking write is short due to
- // the transfer rate limit.
- var ErrLimit = errors.New("flowrate: flow rate limit exceeded")
-
- // Limiter is implemented by the Reader and Writer to provide a consistent
- // interface for monitoring and controlling data transfer.
- type Limiter interface {
- Done() int64
- Status() Status
- SetTransferSize(bytes int64)
- SetLimit(new int64) (old int64)
- SetBlocking(new bool) (old bool)
- }
-
- // Reader implements io.ReadCloser with a restriction on the rate of data
- // transfer.
- type Reader struct {
- io.Reader // Data source
- *Monitor // Flow control monitor
-
- limit int64 // Rate limit in bytes per second (unlimited when <= 0)
- block bool // What to do when no new bytes can be read due to the limit
- }
-
- // NewReader restricts all Read operations on r to limit bytes per second.
- func NewReader(r io.Reader, limit int64) *Reader {
- return &Reader{r, New(0, 0), limit, true}
- }
-
- // Read reads up to len(p) bytes into p without exceeding the current transfer
- // rate limit. It returns (0, nil) immediately if r is non-blocking and no new
- // bytes can be read at this time.
- func (r *Reader) Read(p []byte) (n int, err error) {
- p = p[:r.Limit(len(p), r.limit, r.block)]
- if len(p) > 0 {
- n, err = r.IO(r.Reader.Read(p))
- }
- return
- }
-
- // SetLimit changes the transfer rate limit to new bytes per second and returns
- // the previous setting.
- func (r *Reader) SetLimit(new int64) (old int64) {
- old, r.limit = r.limit, new
- return
- }
-
- // SetBlocking changes the blocking behavior and returns the previous setting. A
- // Read call on a non-blocking reader returns immediately if no additional bytes
- // may be read at this time due to the rate limit.
- func (r *Reader) SetBlocking(new bool) (old bool) {
- old, r.block = r.block, new
- return
- }
-
- // Close closes the underlying reader if it implements the io.Closer interface.
- func (r *Reader) Close() error {
- defer r.Done()
- if c, ok := r.Reader.(io.Closer); ok {
- return c.Close()
- }
- return nil
- }
-
- // Writer implements io.WriteCloser with a restriction on the rate of data
- // transfer.
- type Writer struct {
- io.Writer // Data destination
- *Monitor // Flow control monitor
-
- limit int64 // Rate limit in bytes per second (unlimited when <= 0)
- block bool // What to do when no new bytes can be written due to the limit
- }
-
- // NewWriter restricts all Write operations on w to limit bytes per second. The
- // transfer rate and the default blocking behavior (true) can be changed
- // directly on the returned *Writer.
- func NewWriter(w io.Writer, limit int64) *Writer {
- return &Writer{w, New(0, 0), limit, true}
- }
-
- // Write writes len(p) bytes from p to the underlying data stream without
- // exceeding the current transfer rate limit. It returns (n, ErrLimit) if w is
- // non-blocking and no additional bytes can be written at this time.
- func (w *Writer) Write(p []byte) (n int, err error) {
- var c int
- for len(p) > 0 && err == nil {
- s := p[:w.Limit(len(p), w.limit, w.block)]
- if len(s) > 0 {
- c, err = w.IO(w.Writer.Write(s))
- } else {
- return n, ErrLimit
- }
- p = p[c:]
- n += c
- }
- return
- }
-
- // SetLimit changes the transfer rate limit to new bytes per second and returns
- // the previous setting.
- func (w *Writer) SetLimit(new int64) (old int64) {
- old, w.limit = w.limit, new
- return
- }
-
- // SetBlocking changes the blocking behavior and returns the previous setting. A
- // Write call on a non-blocking writer returns as soon as no additional bytes
- // may be written at this time due to the rate limit.
- func (w *Writer) SetBlocking(new bool) (old bool) {
- old, w.block = w.block, new
- return
- }
-
- // Close closes the underlying writer if it implements the io.Closer interface.
- func (w *Writer) Close() error {
- defer w.Done()
- if c, ok := w.Writer.(io.Closer); ok {
- return c.Close()
- }
- return nil
- }
|