From 1abcc5045f292c44ea45b898c2f6b384dc74907e Mon Sep 17 00:00:00 2001 From: JaguarJack Date: Thu, 2 Jul 2020 18:41:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=A4=E7=89=8C=E6=A1=B6?= =?UTF-8?q?=E9=99=90=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extend/catcher/library/rate/RateLimiter.php | 177 ++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 extend/catcher/library/rate/RateLimiter.php diff --git a/extend/catcher/library/rate/RateLimiter.php b/extend/catcher/library/rate/RateLimiter.php new file mode 100644 index 0000000..758ffc0 --- /dev/null +++ b/extend/catcher/library/rate/RateLimiter.php @@ -0,0 +1,177 @@ +key = $key; + } + + /** + * 处理 + * + * @time 2020年07月02日 + * @return void + */ + public function overflow() + { + // 添加 token + if ($this->canAddToken()) { + $this->addTokens(); + } + + if (!$this->tokens()) { + throw new FailedException('访问限制'); + } + + // 每次请求拿走一个 token + $this->removeToken(); + } + + /** + * + * + * @time 2020年07月02日 +d * @return void + */ + protected function addTokens() + { + $leftTokens = $this->capacity - $this->tokens(); + + $tokens = array_fill(0, $leftTokens < $this->eachTokens ? $leftTokens : $this->eachTokens, 1); + + $this->getRedis()->lPush($this->key, ...$tokens); + + $this->rememberAddTokenTime(); + } + + /** + * 拿走一个 token + * + * @time 2020年07月02日 + * @return void + */ + protected function removeToken() + { + $this->getRedis()->rPop($this->key); + } + + /** + * 设置令牌桶数量 + * + * @time 2020年07月02日 + * @param $capacity + * @return $this + */ + public function setCapacity($capacity) + { + $this->capacity = $capacity; + + return $this; + } + + /** + * 剩余的 token 数量 + * + * @time 2020年07月02日 + * @return bool|int + */ + protected function tokens() + { + return $this->getRedis()->lLen($this->key); + } + + + /** + * 设置时间间隔 + * + * @time 2020年07月02日 + * @param $seconds + * @return $this + */ + public function setInterval($seconds) + { + $this->interval = $seconds; + + return $this; + } + + /** + * 是否可以添加 token + * + * @time 2020年07月02日 + * @return bool + */ + protected function canAddToken() + { + $currentTime = \time(); + + $lastAddTokenTime = $this->getRedis()->get($this->key. $this->addTokenTimeKey); + + // 如果是满的 则不添加 + if ($this->tokens() == $this->capacity) { + return false; + } + + return ($currentTime - $lastAddTokenTime) > $this->interval; + } + + /** + * 记录添加 token 的时间 + * + * @time 2020年07月02日 + * @return void + */ + protected function rememberAddTokenTime() + { + $this->getRedis()->set($this->key. $this->addTokenTimeKey, time()); + } +} \ No newline at end of file