limit.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package util
  2. import (
  3. "errors"
  4. "io"
  5. "sync"
  6. )
  7. // ErrLimitReached is the error returned by the Limiter and LimitWriter when the predefined limit has been reached
  8. var ErrLimitReached = errors.New("limit reached")
  9. // Limiter is a helper that allows adding values up to a well-defined limit. Once the limit is reached
  10. // ErrLimitReached will be returned. Limiter may be used by multiple goroutines.
  11. type Limiter struct {
  12. value int64
  13. limit int64
  14. mu sync.Mutex
  15. }
  16. // NewLimiter creates a new Limiter
  17. func NewLimiter(limit int64) *Limiter {
  18. return &Limiter{
  19. limit: limit,
  20. }
  21. }
  22. // Add adds n to the limiters internal value, but only if the limit has not been reached. If the limit was
  23. // exceeded after adding n, ErrLimitReached is returned.
  24. func (l *Limiter) Add(n int64) error {
  25. l.mu.Lock()
  26. defer l.mu.Unlock()
  27. if l.value+n > l.limit {
  28. return ErrLimitReached
  29. }
  30. l.value += n
  31. return nil
  32. }
  33. // Sub subtracts a value from the limiters internal value
  34. func (l *Limiter) Sub(n int64) {
  35. l.Add(-n)
  36. }
  37. // Set sets the value of the limiter to n. This function ignores the limit. It is meant to set the value
  38. // based on reality.
  39. func (l *Limiter) Set(n int64) {
  40. l.mu.Lock()
  41. l.value = n
  42. l.mu.Unlock()
  43. }
  44. // Value returns the internal value of the limiter
  45. func (l *Limiter) Value() int64 {
  46. l.mu.Lock()
  47. defer l.mu.Unlock()
  48. return l.value
  49. }
  50. // Limit returns the defined limit
  51. func (l *Limiter) Limit() int64 {
  52. return l.limit
  53. }
  54. // LimitWriter implements an io.Writer that will pass through all Write calls to the underlying
  55. // writer w until any of the limiter's limit is reached, at which point a Write will return ErrLimitReached.
  56. // Each limiter's value is increased with every write.
  57. type LimitWriter struct {
  58. w io.Writer
  59. written int64
  60. limiters []*Limiter
  61. mu sync.Mutex
  62. }
  63. // NewLimitWriter creates a new LimitWriter
  64. func NewLimitWriter(w io.Writer, limiters ...*Limiter) *LimitWriter {
  65. return &LimitWriter{
  66. w: w,
  67. limiters: limiters,
  68. }
  69. }
  70. // Write passes through all writes to the underlying writer until any of the given limiter's limit is reached
  71. func (w *LimitWriter) Write(p []byte) (n int, err error) {
  72. w.mu.Lock()
  73. defer w.mu.Unlock()
  74. for i := 0; i < len(w.limiters); i++ {
  75. if err := w.limiters[i].Add(int64(len(p))); err != nil {
  76. for j := i - 1; j >= 0; j-- {
  77. w.limiters[j].Sub(int64(len(p)))
  78. }
  79. return 0, ErrLimitReached
  80. }
  81. }
  82. n, err = w.w.Write(p)
  83. w.written += int64(n)
  84. return
  85. }