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 }