refactor: modularize chat backend, update docs for .m4s segments
This commit is contained in:
1 parent
46e878bef6
commit
b3a10ba3ef
24 files changed
+3771
-2781
No files matched your search
@@ -0,0 +1,75 @@
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RedisClient is the subset of Redis operations needed for rate limiting.
|
||||
type RedisClient interface {
|
||||
Incr(ctx context.Context, key string) (int64, error)
|
||||
Expire(ctx context.Context, key string, expiration time.Duration) error
|
||||
Decr(ctx context.Context, key string) (int64, error)
|
||||
}
|
||||
|
||||
// CheckMessageRate checks if a user has exceeded the message rate limit.
|
||||
// Returns true if allowed, false if rate limited.
|
||||
func CheckMessageRate(ctx context.Context, redis RedisClient, username string, max int, window time.Duration) (bool, error) {
|
||||
if redis == nil {
|
||||
return true, nil // No Redis = no rate limiting
|
||||
}
|
||||
key := fmt.Sprintf("rate:%s", username)
|
||||
count, err := redis.Incr(ctx, key)
|
||||
if err != nil {
|
||||
return true, err // Fail open on Redis error
|
||||
}
|
||||
if count == 1 {
|
||||
_ = redis.Expire(ctx, key, window)
|
||||
}
|
||||
return count <= int64(max), nil
|
||||
}
|
||||
|
||||
// CheckLoginRate checks if an IP has exceeded the login attempt limit.
|
||||
// Returns true if allowed, false if rate limited.
|
||||
func CheckLoginRate(ctx context.Context, redis RedisClient, clientIP string) (bool, error) {
|
||||
if redis == nil {
|
||||
return true, nil
|
||||
}
|
||||
key := fmt.Sprintf("login_attempts:%s", clientIP)
|
||||
count, err := redis.Incr(ctx, key)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if count == 1 {
|
||||
_ = redis.Expire(ctx, key, 5*time.Minute)
|
||||
}
|
||||
return count <= 5, nil
|
||||
}
|
||||
|
||||
// CheckWSConnRate checks if an IP has exceeded the WebSocket connection limit.
|
||||
// Returns true if allowed, false if rate limited.
|
||||
// Caller must call Decr on disconnect.
|
||||
func CheckWSConnRate(ctx context.Context, redis RedisClient, clientIP string) (bool, error) {
|
||||
if redis == nil {
|
||||
return true, nil
|
||||
}
|
||||
key := fmt.Sprintf("ws_conn:%s", clientIP)
|
||||
count, err := redis.Incr(ctx, key)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if count == 1 {
|
||||
_ = redis.Expire(ctx, key, 60*time.Second)
|
||||
}
|
||||
return count <= 5, nil
|
||||
}
|
||||
|
||||
// DecrWSConn decrements the WebSocket connection counter for an IP.
|
||||
func DecrWSConn(ctx context.Context, redis RedisClient, clientIP string) {
|
||||
if redis == nil {
|
||||
return
|
||||
}
|
||||
key := fmt.Sprintf("ws_conn:%s", clientIP)
|
||||
_, _ = redis.Decr(ctx, key)
|
||||
}
|
||||
Reference in new issue
Block a user