package sendguard import ( "errors" "sync" "time" "golang.org/x/time/rate" ) var ErrSendRateLimited = errors.New("send rate limited") // RateLimiter limits outbound send API requests per user. type RateLimiter struct { mu sync.Mutex limits map[string]*rate.Limiter limit rate.Limit burst int } func NewRateLimiter(perMinute int, burst int) *RateLimiter { if perMinute < 1 { perMinute = 30 } if burst < 1 { burst = 10 } return &RateLimiter{ limits: make(map[string]*rate.Limiter), limit: rate.Every(time.Minute / time.Duration(perMinute)), burst: burst, } } func (r *RateLimiter) Allow(userID string) error { if userID == "" { return ErrSendRateLimited } lim := r.limiter(userID) if !lim.Allow() { return ErrSendRateLimited } return nil } func (r *RateLimiter) limiter(userID string) *rate.Limiter { r.mu.Lock() defer r.mu.Unlock() lim, ok := r.limits[userID] if !ok { lim = rate.NewLimiter(r.limit, r.burst) r.limits[userID] = lim } return lim }