You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
3.8 KiB

  1. //
  2. // Written by Maxim Khitrov (November 2012)
  3. //
  4. package flowrate
  5. import (
  6. "errors"
  7. "io"
  8. )
  9. // ErrLimit is returned by the Writer when a non-blocking write is short due to
  10. // the transfer rate limit.
  11. var ErrLimit = errors.New("flowrate: flow rate limit exceeded")
  12. // Limiter is implemented by the Reader and Writer to provide a consistent
  13. // interface for monitoring and controlling data transfer.
  14. type Limiter interface {
  15. Done() int64
  16. Status() Status
  17. SetTransferSize(bytes int64)
  18. SetLimit(new int64) (old int64)
  19. SetBlocking(new bool) (old bool)
  20. }
  21. // Reader implements io.ReadCloser with a restriction on the rate of data
  22. // transfer.
  23. type Reader struct {
  24. io.Reader // Data source
  25. *Monitor // Flow control monitor
  26. limit int64 // Rate limit in bytes per second (unlimited when <= 0)
  27. block bool // What to do when no new bytes can be read due to the limit
  28. }
  29. // NewReader restricts all Read operations on r to limit bytes per second.
  30. func NewReader(r io.Reader, limit int64) *Reader {
  31. return &Reader{r, New(0, 0), limit, true}
  32. }
  33. // Read reads up to len(p) bytes into p without exceeding the current transfer
  34. // rate limit. It returns (0, nil) immediately if r is non-blocking and no new
  35. // bytes can be read at this time.
  36. func (r *Reader) Read(p []byte) (n int, err error) {
  37. p = p[:r.Limit(len(p), r.limit, r.block)]
  38. if len(p) > 0 {
  39. n, err = r.IO(r.Reader.Read(p))
  40. }
  41. return
  42. }
  43. // SetLimit changes the transfer rate limit to new bytes per second and returns
  44. // the previous setting.
  45. func (r *Reader) SetLimit(new int64) (old int64) {
  46. old, r.limit = r.limit, new
  47. return
  48. }
  49. // SetBlocking changes the blocking behavior and returns the previous setting. A
  50. // Read call on a non-blocking reader returns immediately if no additional bytes
  51. // may be read at this time due to the rate limit.
  52. func (r *Reader) SetBlocking(new bool) (old bool) {
  53. old, r.block = r.block, new
  54. return
  55. }
  56. // Close closes the underlying reader if it implements the io.Closer interface.
  57. func (r *Reader) Close() error {
  58. defer r.Done()
  59. if c, ok := r.Reader.(io.Closer); ok {
  60. return c.Close()
  61. }
  62. return nil
  63. }
  64. // Writer implements io.WriteCloser with a restriction on the rate of data
  65. // transfer.
  66. type Writer struct {
  67. io.Writer // Data destination
  68. *Monitor // Flow control monitor
  69. limit int64 // Rate limit in bytes per second (unlimited when <= 0)
  70. block bool // What to do when no new bytes can be written due to the limit
  71. }
  72. // NewWriter restricts all Write operations on w to limit bytes per second. The
  73. // transfer rate and the default blocking behavior (true) can be changed
  74. // directly on the returned *Writer.
  75. func NewWriter(w io.Writer, limit int64) *Writer {
  76. return &Writer{w, New(0, 0), limit, true}
  77. }
  78. // Write writes len(p) bytes from p to the underlying data stream without
  79. // exceeding the current transfer rate limit. It returns (n, ErrLimit) if w is
  80. // non-blocking and no additional bytes can be written at this time.
  81. func (w *Writer) Write(p []byte) (n int, err error) {
  82. var c int
  83. for len(p) > 0 && err == nil {
  84. s := p[:w.Limit(len(p), w.limit, w.block)]
  85. if len(s) > 0 {
  86. c, err = w.IO(w.Writer.Write(s))
  87. } else {
  88. return n, ErrLimit
  89. }
  90. p = p[c:]
  91. n += c
  92. }
  93. return
  94. }
  95. // SetLimit changes the transfer rate limit to new bytes per second and returns
  96. // the previous setting.
  97. func (w *Writer) SetLimit(new int64) (old int64) {
  98. old, w.limit = w.limit, new
  99. return
  100. }
  101. // SetBlocking changes the blocking behavior and returns the previous setting. A
  102. // Write call on a non-blocking writer returns as soon as no additional bytes
  103. // may be written at this time due to the rate limit.
  104. func (w *Writer) SetBlocking(new bool) (old bool) {
  105. old, w.block = w.block, new
  106. return
  107. }
  108. // Close closes the underlying writer if it implements the io.Closer interface.
  109. func (w *Writer) Close() error {
  110. defer w.Done()
  111. if c, ok := w.Writer.(io.Closer); ok {
  112. return c.Close()
  113. }
  114. return nil
  115. }