package cachevalkey import ( "context" "time" ) // rateLimiterStoreShape mirrors web/mw.RateLimiterStore for compile-time duck-type verification. // Cache-valkey must not import web (D-1), so the shape is defined locally. type rateLimiterStoreShape interface { Allow(ctx context.Context, key string) (bool, error) } var _ rateLimiterStoreShape = (*RateLimiterStore)(nil) // RateLimiterStore is a Valkey-backed fixed-window rate limiter. // Satisfies web/mw.RateLimiterStore via duck typing — no import of that package required. // // window is the length of the time window; limit is the maximum number of requests // allowed within that window. When the store is temporarily unavailable, Allow returns // (false, err); the web middleware fails open on non-nil errors. type RateLimiterStore struct { provider Provider window time.Duration limit int64 } // NewRateLimiterStore returns a RateLimiterStore backed by p. // window is the rate limit window; limit is the maximum requests per window. func NewRateLimiterStore(p Provider, window time.Duration, limit int64) *RateLimiterStore { return &RateLimiterStore{provider: p, window: window, limit: limit} } // Allow reports whether the request identified by key is within the rate limit. // Uses a fixed-window counter stored in Valkey (atomically via Lua). func (s *RateLimiterStore) Allow(ctx context.Context, key string) (bool, error) { count, err := s.provider.IncrWithTTL(ctx, key, s.window) if err != nil { return false, err } return count <= s.limit, nil }