FDN-01: repository & projektgerüst
Git-Repository für bestehenden archivdms-Code initialisiert, Branch-/Commit-Konvention (feature/<ticket>-<slug>-Branches, Ticket-Prefix in Commit-Nachricht) etabliert.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// keyedRateLimiter is a minimal in-memory token-bucket limiter keyed by an
|
||||
// arbitrary string (used for per-(tenant,loginName) and per-IP LDAP login
|
||||
// throttling). No external dependency, no Redis — buckets are created lazily
|
||||
// and idle ones are swept periodically to bound memory.
|
||||
type keyedRateLimiter struct {
|
||||
mu sync.Mutex
|
||||
buckets map[string]*bucket
|
||||
burst float64
|
||||
refillPerSec float64
|
||||
lastSweep time.Time
|
||||
}
|
||||
|
||||
type bucket struct {
|
||||
tokens float64
|
||||
last time.Time
|
||||
}
|
||||
|
||||
func newKeyedRateLimiter(burst, refillPerSec float64) *keyedRateLimiter {
|
||||
return &keyedRateLimiter{
|
||||
buckets: make(map[string]*bucket),
|
||||
burst: burst,
|
||||
refillPerSec: refillPerSec,
|
||||
lastSweep: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// allow consumes one token for key, returning false when the bucket is empty.
|
||||
func (l *keyedRateLimiter) allow(key string) bool {
|
||||
now := time.Now()
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.sweepLocked(now)
|
||||
|
||||
b, ok := l.buckets[key]
|
||||
if !ok {
|
||||
b = &bucket{tokens: l.burst, last: now}
|
||||
l.buckets[key] = b
|
||||
}
|
||||
b.tokens += now.Sub(b.last).Seconds() * l.refillPerSec
|
||||
if b.tokens > l.burst {
|
||||
b.tokens = l.burst
|
||||
}
|
||||
b.last = now
|
||||
|
||||
if b.tokens < 1 {
|
||||
return false
|
||||
}
|
||||
b.tokens--
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *keyedRateLimiter) sweepLocked(now time.Time) {
|
||||
if now.Sub(l.lastSweep) < time.Minute {
|
||||
return
|
||||
}
|
||||
l.lastSweep = now
|
||||
for k, b := range l.buckets {
|
||||
if now.Sub(b.last) > 30*time.Minute {
|
||||
delete(l.buckets, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user