From cf515f6e81541b9968d0e14fc64e3b5c6b03fa07 Mon Sep 17 00:00:00 2001 From: Luke Austin Date: Wed, 21 Sep 2022 10:17:28 +0100 Subject: [PATCH] Add support for limit per day --- .gitignore | 1 + src/RateLimiter.php | 5 +++ src/RateLimiterMiddleware.php | 12 ++++++ tests/RateLimiterMiddlewareTest.php | 5 +++ tests/RateLimiterTest.php | 65 +++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+) diff --git a/.gitignore b/.gitignore index b4a9ae4..896e906 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ composer.lock docs vendor coverage +.phpunit.result.cache diff --git a/src/RateLimiter.php b/src/RateLimiter.php index eda2072..20d19fc 100644 --- a/src/RateLimiter.php +++ b/src/RateLimiter.php @@ -6,6 +6,7 @@ class RateLimiter { const TIME_FRAME_MINUTE = 'minute'; const TIME_FRAME_SECOND = 'second'; + const TIME_FRAME_DAY = 'day'; /** @var int */ protected $limit; @@ -74,6 +75,10 @@ protected function timeFrameLengthInMilliseconds(): int return 60 * 1000; } + if ($this->timeFrame === self::TIME_FRAME_DAY) { + return 24 * 60 * 60 * 1000; + } + return 1000; } } diff --git a/src/RateLimiterMiddleware.php b/src/RateLimiterMiddleware.php index e646597..9be8e4e 100755 --- a/src/RateLimiterMiddleware.php +++ b/src/RateLimiterMiddleware.php @@ -38,6 +38,18 @@ public static function perMinute(int $limit, Store $store = null, Deferrer $defe return new static($rateLimiter); } + public static function perDay(int $limit, Store $store = null, Deferrer $deferrer = null): RateLimiterMiddleware + { + $rateLimiter = new RateLimiter( + $limit, + RateLimiter::TIME_FRAME_DAY, + $store ?? new InMemoryStore(), + $deferrer ?? new SleepDeferrer() + ); + + return new static($rateLimiter); + } + public function __invoke(callable $handler) { return function (RequestInterface $request, array $options) use ($handler) { diff --git a/tests/RateLimiterMiddlewareTest.php b/tests/RateLimiterMiddlewareTest.php index 3d6451c..b10158f 100644 --- a/tests/RateLimiterMiddlewareTest.php +++ b/tests/RateLimiterMiddlewareTest.php @@ -18,5 +18,10 @@ public function it_has_named_constructors_to_create_instances() RateLimiterMiddleware::class, RateLimiterMiddleware::perMinute(5) ); + + $this->assertInstanceOf( + RateLimiterMiddleware::class, + RateLimiterMiddleware::perDay(10000) + ); } } diff --git a/tests/RateLimiterTest.php b/tests/RateLimiterTest.php index 02bf7c6..f20e9c9 100644 --- a/tests/RateLimiterTest.php +++ b/tests/RateLimiterTest.php @@ -135,4 +135,69 @@ public function it_defers_actions_when_it_reaches_a_limit_in_minutes() $this->assertEquals(60000, $this->deferrer->getCurrentTime()); } + + /** @test */ + public function it_execute_actions_below_a_limit_for_day() + { + $rateLimiter = $this->createRateLimiter(3, RateLimiter::TIME_FRAME_DAY); + + $this->assertEquals(0, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + $this->deferrer->sleep(100); + }); + + $this->assertEquals(100, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + $this->deferrer->sleep(100); + }); + + $this->assertEquals(200, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + $this->deferrer->sleep(100); + }); + + $this->assertEquals(300, $this->deferrer->getCurrentTime()); + + $dayInMilliseconds = 24 * 60 * 60 * 1000; + + $this->deferrer->sleep($dayInMilliseconds - 300); + + $rateLimiter->handle(function () { + $this->deferrer->sleep(100); + }); + + $this->assertEquals($dayInMilliseconds + 100, $this->deferrer->getCurrentTime()); + } + + /** @test */ + public function it_defers_actions_when_it_reaches_a_limit_in_day() + { + $rateLimiter = $this->createRateLimiter(3, RateLimiter::TIME_FRAME_DAY); + + $this->assertEquals(0, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + }); + + $this->assertEquals(0, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + }); + + $this->assertEquals(0, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + }); + + $this->assertEquals(0, $this->deferrer->getCurrentTime()); + + $rateLimiter->handle(function () { + }); + + $this->assertEquals(24 * 60 * 60 * 1000, $this->deferrer->getCurrentTime()); + } + }