redis = \Illuminate\Support\Facades\Redis::connection('sentinel-cache'); } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param array $limits * @return \Symfony\Component\HttpFoundation\Response * * @throws \Illuminate\Http\Exceptions\ThrottleRequestsException */ protected function handleRequest($request, Closure $next, array $limits) { foreach ($limits as $limit) { if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decayMinutes)) { throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback); } } $response = $next($request); foreach ($limits as $limit) { $response = $this->addHeaders( $response, $limit->maxAttempts, $this->calculateRemainingAttempts($limit->key, $limit->maxAttempts) ); } return $response; } /** * Determine if the given key has been "accessed" too many times. * * @param string $key * @param int $maxAttempts * @param int $decayMinutes * @return mixed */ protected function tooManyAttempts($key, $maxAttempts, $decayMinutes) { $limiter = new DurationLimiter( $this->redis, $key, $maxAttempts, $decayMinutes * 60 ); return tap(! $limiter->acquire(), function () use ($key, $limiter) { [$this->decaysAt[$key], $this->remaining[$key]] = [ $limiter->decaysAt, $limiter->remaining, ]; }); } /** * Calculate the number of remaining attempts. * * @param string $key * @param int $maxAttempts * @param int|null $retryAfter * @return int */ protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null) { return is_null($retryAfter) ? $this->remaining[$key] : 0; } /** * Get the number of seconds until the lock is released. * * @param string $key * @return int */ protected function getTimeUntilNextRetry($key) { return $this->decaysAt[$key] - $this->currentTime(); } }