ax(mining): rename RateLimiter.mu to mutex; fix prose comment to usage example
AX Principle 1 (predictable names): `mu` abbreviates `mutex` — rename to `mutex`.
AX Principle 2 (comments as usage examples): struct doc was prose ("provides token
bucket rate limiting per IP address") — replace with concrete call examples.
Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
3565479521
commit
b53e5f2b19
1 changed files with 12 additions and 11 deletions
|
|
@ -8,12 +8,13 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// RateLimiter provides token bucket rate limiting per IP address
|
||||
// rl := NewRateLimiter(10, 20) // 10 req/s, burst 20
|
||||
// router.Use(rl.Middleware())
|
||||
type RateLimiter struct {
|
||||
requestsPerSecond int
|
||||
burst int
|
||||
clients map[string]*rateLimitClient
|
||||
mu sync.RWMutex
|
||||
mutex sync.RWMutex
|
||||
stopChan chan struct{}
|
||||
stopped bool
|
||||
}
|
||||
|
|
@ -56,8 +57,8 @@ func (rl *RateLimiter) cleanupLoop() {
|
|||
|
||||
// rl.cleanup() // called every minute by cleanupLoop; evicts IPs idle for >5 minutes
|
||||
func (rl *RateLimiter) cleanup() {
|
||||
rl.mu.Lock()
|
||||
defer rl.mu.Unlock()
|
||||
rl.mutex.Lock()
|
||||
defer rl.mutex.Unlock()
|
||||
|
||||
for ip, client := range rl.clients {
|
||||
if time.Since(client.lastCheck) > 5*time.Minute {
|
||||
|
|
@ -68,8 +69,8 @@ func (rl *RateLimiter) cleanup() {
|
|||
|
||||
// rl.Stop() // call on shutdown to release the cleanup goroutine
|
||||
func (rl *RateLimiter) Stop() {
|
||||
rl.mu.Lock()
|
||||
defer rl.mu.Unlock()
|
||||
rl.mutex.Lock()
|
||||
defer rl.mutex.Unlock()
|
||||
|
||||
if !rl.stopped {
|
||||
close(rl.stopChan)
|
||||
|
|
@ -82,7 +83,7 @@ func (rl *RateLimiter) Middleware() gin.HandlerFunc {
|
|||
return func(c *gin.Context) {
|
||||
ip := c.ClientIP()
|
||||
|
||||
rl.mu.Lock()
|
||||
rl.mutex.Lock()
|
||||
client, exists := rl.clients[ip]
|
||||
if !exists {
|
||||
client = &rateLimitClient{tokens: float64(rl.burst), lastCheck: time.Now()}
|
||||
|
|
@ -99,7 +100,7 @@ func (rl *RateLimiter) Middleware() gin.HandlerFunc {
|
|||
client.lastCheck = now
|
||||
|
||||
if client.tokens < 1 {
|
||||
rl.mu.Unlock()
|
||||
rl.mutex.Unlock()
|
||||
respondWithError(c, http.StatusTooManyRequests, "RATE_LIMITED",
|
||||
"too many requests", "rate limit exceeded")
|
||||
c.Abort()
|
||||
|
|
@ -107,14 +108,14 @@ func (rl *RateLimiter) Middleware() gin.HandlerFunc {
|
|||
}
|
||||
|
||||
client.tokens--
|
||||
rl.mu.Unlock()
|
||||
rl.mutex.Unlock()
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// if rl.ClientCount() == 0 { /* no active clients */ }
|
||||
func (rl *RateLimiter) ClientCount() int {
|
||||
rl.mu.RLock()
|
||||
defer rl.mu.RUnlock()
|
||||
rl.mutex.RLock()
|
||||
defer rl.mutex.RUnlock()
|
||||
return len(rl.clients)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue