| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- package middleware
- import (
- "net/http"
- "sync"
- "time"
- "golang.org/x/time/rate"
- )
- type RateLimiter struct {
- visitors map[string]*rate.Limiter
- mu sync.Mutex
- rate rate.Limit
- burst int
- lastSeen map[string]time.Time
- }
- func NewRateLimiter(r rate.Limit, burst int) *RateLimiter {
- rl := &RateLimiter{
- visitors: make(map[string]*rate.Limiter),
- rate: r,
- burst: burst,
- lastSeen: make(map[string]time.Time),
- }
- go rl.cleanup()
- return rl
- }
- func (rl *RateLimiter) cleanup() {
- for {
- time.Sleep(10 * time.Minute)
- rl.mu.Lock()
- for ip, last := range rl.lastSeen {
- if time.Since(last) > 30*time.Minute {
- delete(rl.visitors, ip)
- delete(rl.lastSeen, ip)
- }
- }
- rl.mu.Unlock()
- }
- }
- func (rl *RateLimiter) Middleware() func(http.Handler) http.Handler {
- rl := &RateLimiter{
- visitors: make(map[string]*rate.Limiter),
- rate: 60,
- burst: 60,
- }
- return func(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ip := r.RemoteAddr
- rl.mu.Lock()
- limiter, ok := rl.visitors[ip]
- if !ok {
- limiter = rate.NewLimiter(rl.rate, rl.burst)
- rl.visitors[ip] = limiter
- }
- rl.mu.Unlock()
- if !limiter.Allow() {
- http.Error(w, `{"error":"rate limit exceeded"}`, http.StatusTooManyRequests)
- return
- }
- next.ServeHTTP(w, r)
- })
- }
- }
|