github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/http/fast/middleware/limiter/ratelimit.go (about)

     1  package limiter
     2  
     3  import (
     4  	"github.com/angenalZZZ/gofunc/http/fast"
     5  	"github.com/angenalZZZ/gofunc/http/ratelimit"
     6  	"github.com/valyala/fasthttp"
     7  	"sync/atomic"
     8  	"time"
     9  )
    10  
    11  // RateLimit holds the configuration for the RateLimit middleware handler.
    12  type RateLimit struct {
    13  	// RPS is the number of requests per seconds. Tokens will fill at an
    14  	// interval that closely respects that RPS value.
    15  	RPS int64
    16  	// MaxWait is the maximum time to wait for an available token for a
    17  	// request to be allowed. If no token is available, the request is
    18  	// denied without waiting and a status code 429 is returned.
    19  	MaxWait time.Duration
    20  
    21  	// X-Rate-Limit response headers.
    22  	RateLimitHeader func(*fast.Ctx, *RateLimit, bool)
    23  	// Http Handler when too many requests.
    24  	DenyHandler func(*fast.Ctx, *RateLimit)
    25  
    26  	// rate limit Bucket
    27  	*ratelimit.Bucket
    28  	start int32
    29  }
    30  
    31  // NewRateLimiter new RateLimit.
    32  // rps is the number of requests per seconds, msg for the request to be not allowed.
    33  func NewRateLimiterPerSecond(rps int) *RateLimit {
    34  	capacity := int64(rps)
    35  	if capacity < 1 {
    36  		capacity = 1
    37  	}
    38  	return &RateLimit{
    39  		RPS:     capacity,         // RPS is the number of requests per seconds.
    40  		MaxWait: time.Millisecond, // http request is blocking in a milli second.
    41  		Bucket:  ratelimit.NewBucket(time.Second, capacity),
    42  		RateLimitHeader: func(c *fast.Ctx, r *RateLimit, allowed bool) {
    43  			ResponseRateLimitHeader(c, &ErrRateLimitHeader{
    44  				Allowed: true,
    45  				Header: RateLimitHeader{
    46  					Limit:      r.Bucket.Capacity(),
    47  					Remaining:  r.Bucket.Available(),
    48  					Reset:      1,
    49  					RetryAfter: 1,
    50  				},
    51  			})
    52  		},
    53  		DenyHandler: func(c *fast.Ctx, r *RateLimit) {
    54  			c.Status(fasthttp.StatusTooManyRequests).SendString(ErrTooManyRequests.Error())
    55  		},
    56  	}
    57  }
    58  
    59  // Wrap returns a handler that allows only the configured number of requests.
    60  // The wrapped handler h is called only if the request is allowed by the rate
    61  // limiter, otherwise a status code 429 is returned.
    62  func (rl *RateLimit) Wrap(handler func(*fast.Ctx)) func(*fast.Ctx) {
    63  	go rl.Refill()
    64  	return func(c *fast.Ctx) {
    65  		// request to be allowed
    66  		if _, ok := rl.Bucket.TakeMaxDuration(1, rl.MaxWait); ok {
    67  			if rl.start == 0 {
    68  				atomic.AddInt32(&rl.start, 1)
    69  			}
    70  			rl.RateLimitHeader(c, rl, true)
    71  			handler(c)
    72  			return
    73  		}
    74  		// request to be deny
    75  		if rl.DenyHandler == nil {
    76  			rl.RateLimitHeader(c, rl, false)
    77  			c.Status(fasthttp.StatusTooManyRequests)
    78  			return
    79  		}
    80  		rl.RateLimitHeader(c, rl, false)
    81  		rl.DenyHandler(c, rl)
    82  	}
    83  }
    84  
    85  // Renew refill, start new rate limit Bucket.
    86  func (rl *RateLimit) Refill() {
    87  	a := time.Second - rl.MaxWait
    88  	for {
    89  		time.Sleep(time.Microsecond)
    90  		if rl.start == 0 {
    91  			continue
    92  		}
    93  		select {
    94  		case <-time.After(a):
    95  			rl.Restart()
    96  		}
    97  	}
    98  }
    99  
   100  // Restart start new rate limit Bucket.
   101  func (rl *RateLimit) Restart() {
   102  	rl.start, rl.Bucket = 0, ratelimit.NewBucket(time.Second, rl.RPS)
   103  }