Initial open source release

This commit is contained in:
A 2026-06-04 01:37:39 +08:00
commit 74992e893f
377 changed files with 118084 additions and 0 deletions

View file

@ -0,0 +1,57 @@
package redisstore
import (
"context"
"fmt"
"math"
"time"
"github.com/redis/go-redis/v9"
)
// RateLimiter 用 Redis INCR + TTL 实现固定窗口限流。
type RateLimiter struct {
c *redis.Client
}
// NewRateLimiter 创建 Redis-backed RateLimiter。
func NewRateLimiter(c *redis.Client) *RateLimiter {
return &RateLimiter{c: c}
}
func rateLimitKey(key string) string {
return "ratelimit:" + key
}
func (l *RateLimiter) Allow(ctx context.Context, key string, limit int, window time.Duration) (bool, int, error) {
if limit <= 0 {
return true, 0, nil
}
if window <= 0 {
window = time.Second
}
if l == nil || l.c == nil {
return false, 0, fmt.Errorf("redis rate limiter: nil client")
}
redisKey := rateLimitKey(key)
count, err := l.c.Incr(ctx, redisKey).Result()
if err != nil {
return false, 0, fmt.Errorf("redis incr rate limit: %w", err)
}
if count == 1 {
if err := l.c.Expire(ctx, redisKey, window).Err(); err != nil {
return false, 0, fmt.Errorf("redis expire rate limit: %w", err)
}
}
if count <= int64(limit) {
return true, 0, nil
}
ttl, err := l.c.TTL(ctx, redisKey).Result()
if err != nil {
return false, 0, fmt.Errorf("redis ttl rate limit: %w", err)
}
if ttl <= 0 {
ttl = window
}
return false, int(math.Ceil(ttl.Seconds())), nil
}