From 3bc0fc69ff0312f2b330b1f6cf956e1c62303051 Mon Sep 17 00:00:00 2001 From: gzydong <837215079@qq.com> Date: Thu, 20 May 2021 16:53:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Cache/Contracts/HashRedisInterface.php | 23 +++ app/Cache/Contracts/ListRedisInterface.php | 18 ++ app/Cache/Contracts/LockRedisInterface.php | 10 ++ app/Cache/Contracts/SetRedisInterface.php | 20 +++ app/Cache/Contracts/StreamRedisInterface.php | 26 +++ app/Cache/Contracts/StringRedisInterface.php | 16 ++ app/Cache/Contracts/ZSetRedisInterface.php | 26 +++ app/Cache/Repository/HashRedis.php | 116 +++++++++++++ app/Cache/Repository/ListRedis.php | 80 +++++++++ app/Cache/Repository/LockRedis.php | 74 ++++++++ app/Cache/Repository/RedisTrait.php | 63 +++++++ app/Cache/Repository/SetRedis.php | 94 +++++++++++ app/Cache/Repository/StreamRedis.php | 155 +++++++++++++++++ app/Cache/Repository/StringRedis.php | 74 ++++++++ app/Cache/Repository/ZSetRedis.php | 169 +++++++++++++++++++ app/Command/TestCommand.php | 103 +++++++++++ app/Controller/Api/V1/ContactsController.php | 2 +- 17 files changed, 1068 insertions(+), 1 deletion(-) create mode 100644 app/Cache/Contracts/HashRedisInterface.php create mode 100644 app/Cache/Contracts/ListRedisInterface.php create mode 100644 app/Cache/Contracts/LockRedisInterface.php create mode 100644 app/Cache/Contracts/SetRedisInterface.php create mode 100644 app/Cache/Contracts/StreamRedisInterface.php create mode 100644 app/Cache/Contracts/StringRedisInterface.php create mode 100644 app/Cache/Contracts/ZSetRedisInterface.php create mode 100644 app/Cache/Repository/HashRedis.php create mode 100644 app/Cache/Repository/ListRedis.php create mode 100644 app/Cache/Repository/LockRedis.php create mode 100644 app/Cache/Repository/RedisTrait.php create mode 100644 app/Cache/Repository/SetRedis.php create mode 100644 app/Cache/Repository/StreamRedis.php create mode 100644 app/Cache/Repository/StringRedis.php create mode 100644 app/Cache/Repository/ZSetRedis.php create mode 100644 app/Command/TestCommand.php diff --git a/app/Cache/Contracts/HashRedisInterface.php b/app/Cache/Contracts/HashRedisInterface.php new file mode 100644 index 0000000..2811c38 --- /dev/null +++ b/app/Cache/Contracts/HashRedisInterface.php @@ -0,0 +1,23 @@ +redis()->hGet($this->getKeyName(), $k); + }; + + if (func_num_args() == 1) return $func($key[0]); + + $array = []; + foreach ($key as $arg) { + $array[$arg] = $func($arg); + } + + return $array; + } + + /** + * 设置 Hash 值 + * + * @param string $key + * @param string $value + */ + public function add(string $key, string $value) + { + $this->redis()->hSet($this->getKeyName(), $key, $value); + } + + /** + * 删除 hash 值 + * + * @param string ...$key + * @return bool|int + */ + public function rem(string ...$key) + { + return $this->redis()->hDel($this->getKeyName(), ...$key); + } + + /** + * 给指定元素累加值 + * + * @param string $member 元素 + * @param int $score + * @return float + */ + public function incr(string $member, int $score) + { + return $this->redis()->hincrby($this->getKeyName(), $member, $score); + } + + /** + * 获取 Hash 中元素总数 + * + * @return int + */ + public function count() + { + return (int)$this->redis()->hLen($this->getKeyName()); + } + + /** + * 获取 Hash 中所有元素 + * + * @return array + */ + public function all() + { + return $this->redis()->hGetAll($this->getKeyName()); + } + + /** + * 判断 hash 表中是否存在某个值 + * + * @param string $key + * @return bool + */ + public function isMember(string $key) + { + return $this->redis()->hExists($this->getKeyName(), $key); + } + + /** + * 删除 Hash 表 + * + * @return bool + */ + public function delete() + { + return (bool)$this->redis()->del($this->getKeyName()); + } +} diff --git a/app/Cache/Repository/ListRedis.php b/app/Cache/Repository/ListRedis.php new file mode 100644 index 0000000..291dbe7 --- /dev/null +++ b/app/Cache/Repository/ListRedis.php @@ -0,0 +1,80 @@ +redis()->lPush($this->getKeyName(), ...$value); + } + + /** + * 获取队列中的任务 + * + * @return bool|mixed + */ + public function pop() + { + return $this->redis()->rPop($this->getKeyName()); + } + + /** + * 获取列表中元素总数 + * + * @return int + */ + public function count() + { + return (int)$this->redis()->lLen($this->getKeyName()); + } + + /** + * 清除列表中所有元素 + * + * @return boolean + */ + public function clear() + { + return $this->redis()->lTrim($this->getKeyName(), 1, 0); + } + + /** + * 获取列表中所有元素 + * + * @return array + */ + public function all() + { + return $this->redis()->lRange($this->getKeyName(), 0, -1); + } + + /** + * 删除 List + * + * @return bool + */ + public function delete() + { + return (bool)$this->redis()->del($this->getKeyName()); + } +} diff --git a/app/Cache/Repository/LockRedis.php b/app/Cache/Repository/LockRedis.php new file mode 100644 index 0000000..0233a0c --- /dev/null +++ b/app/Cache/Repository/LockRedis.php @@ -0,0 +1,74 @@ +getCacheKey($key); + + $start = $this->time(); + do { + $lock = $this->redis()->set($lockName, $this->lockValue, ['nx', 'ex' => $lockTime]); + if ($lock || $timeout === 0) { + break; + } + + // 默认 0.1 秒一次取锁 + usleep(100000); + } while ($this->time() < $start + $timeout); + + return $lock; + } + + /** + * 释放 Redis 锁 + * + * @param string $key + * @return mixed + */ + public function delete(string $key) + { + $script = <<redis()->eval($script, [$this->getCacheKey($key), $this->lockValue,], 1); + } +} diff --git a/app/Cache/Repository/RedisTrait.php b/app/Cache/Repository/RedisTrait.php new file mode 100644 index 0000000..c3ea84c --- /dev/null +++ b/app/Cache/Repository/RedisTrait.php @@ -0,0 +1,63 @@ +prefix, ':'), trim($key, ':')); + } + + /** + * 获取缓存 KEY + * + * @return string + */ + private function getKeyName() + { + return $this->getCacheKey($this->name); + } + + /** + * 加载数据到缓存 + */ + public function reload() + { + + } +} diff --git a/app/Cache/Repository/SetRedis.php b/app/Cache/Repository/SetRedis.php new file mode 100644 index 0000000..3bfc30b --- /dev/null +++ b/app/Cache/Repository/SetRedis.php @@ -0,0 +1,94 @@ +redis()->sAdd($this->getKeyName(), ...$member); + } + + /** + * 删除集合元素 + * + * @param string ...$member + * @return int + */ + public function rem(string ...$member) + { + return $this->redis()->sRem($this->getKeyName(), ...$member); + } + + /** + * 判断是否是集合元素 + * + * @param string $member + * @return bool + */ + public function isMember(string $member) + { + return $this->redis()->sIsMember($this->getKeyName(), $member); + } + + /** + * 获取集合中所有元素 + * + * @return array + */ + public function all() + { + return $this->redis()->sMembers($this->getKeyName()); + } + + /** + * 获取集合中元素个数 + * + * @return int + */ + public function count() + { + return $this->redis()->scard($this->getKeyName()); + } + + /** + * 获取随机集合中的元素 + * + * @param int $count + * @return array|bool|mixed|string + */ + public function randMember($count = 1) + { + return $this->redis()->sRandMember($this->getKeyName(), $count); + } + + /** + * 删除 Set 集合表 + * + * @return bool + */ + public function delete() + { + return (bool)$this->redis()->del($this->getKeyName()); + } +} diff --git a/app/Cache/Repository/StreamRedis.php b/app/Cache/Repository/StreamRedis.php new file mode 100644 index 0000000..6c352ca --- /dev/null +++ b/app/Cache/Repository/StreamRedis.php @@ -0,0 +1,155 @@ +redis()->xAdd($this->getKeyName(), '*', $messages, $maxLen, $isApproximate); + } + + /** + * 删除消息 + * + * @param string ...$id 消息ID + * @return int + */ + public function rem(string ...$id) + { + return $this->redis()->xDel($this->getKeyName(), $id); + } + + /** + * 消费者消息确认 + * + * @param string $group 消费组 + * @param string $id 消息ID + * @return int + */ + public function ack(string $group, string $id) + { + return $this->redis()->xAck($this->getKeyName(), $group, [$id]); + } + + /** + * 获取消息总数 + * + * @return int + */ + public function count() + { + return $this->redis()->xLen($this->getKeyName()); + } + + /** + * 获取所有消息 + * + * @return array + */ + public function all() + { + return $this->redis()->xRange($this->getKeyName(), '-', '+'); + } + + /** + * 清空消息队列 + * + * @return bool + */ + public function clear() + { + foreach ($this->all() as $k => $v) { + $this->rem($k); + } + + return true; + } + + /** + * 删除消息队列 KEY + * + * @return int + */ + public function delete() + { + return $this->redis()->del($this->getKeyName()); + } + + /** + * 对消息队列进行修剪,限制长度 + * + * @param int $maxLen + * @param bool $isApproximate + * @return int + */ + public function trim(int $maxLen, bool $isApproximate = false) + { + return $this->redis()->xTrim($this->getKeyName(), $maxLen, $isApproximate); + } + + public function group($operation, $group, $msgId = '', $mkStream = false) + { + return $this->redis()->xGroup($operation, $this->getKeyName(), $group, $msgId, $mkStream); + } + + public function pending($group, $start = null, $end = null, $count = null, $consumer = null) + { + return $this->redis()->xPending($this->getKeyName(), $group, $start, $end, $count, $consumer); + } + + /** + * 查看队列信息 + * + * @param string $operation [stream:队列信息,groups:消费组信息] + * @return mixed + */ + public function info(string $operation = 'stream') + { + return $this->redis()->xInfo($operation, $this->getKeyName()); + } + + /** + * 运行消息队列 + * + * @param Closure $closure 闭包函数 + * @param string $group 消费组 + * @param string $consumer 消费者 + * @param int $count 同时获取的任务个数 + */ + public function run(Closure $closure, string $group, string $consumer, $count = 1) + { + $this->group('create', $group, '0'); + + while (true) { + $tasks = $this->redis()->xReadGroup($group, $consumer, [$this->getKeyName() => '>'], $count); + if (empty($tasks)) { + sleep(1);// 获取不到任务,延时一秒 + continue; + } + + foreach ($tasks[$this->getKeyName()] as $id => $task) { + if ($closure($id, $task)) { + $this->ack($group, $id); + } + } + } + } +} diff --git a/app/Cache/Repository/StringRedis.php b/app/Cache/Repository/StringRedis.php new file mode 100644 index 0000000..5b60e39 --- /dev/null +++ b/app/Cache/Repository/StringRedis.php @@ -0,0 +1,74 @@ +redis()->set($this->getCacheKey($key), $value, $expires); + } + + /** + * 获取缓存数据 + * + * @param string $key 缓存标识 + * @return false|mixed|string + */ + public function get(string $key) + { + return $this->redis()->get($this->getCacheKey($key)); + } + + /** + * 删除 String 缓存 + * + * @param string $key 缓存标识 + * @return bool + */ + public function delete(string $key) + { + return (bool)$this->redis()->del($key); + } + + /** + * 判断缓存是否存在 + * + * @param string $key 缓存标识 + * @return bool + */ + public function isExist(string $key) + { + return (bool)$this->get($key); + } + + /** + * 获取缓存过期时间 + * + * @param string $key 缓存标识 + * @return bool|int + */ + public function ttl(string $key) + { + return $this->redis()->ttl($this->getCacheKey($key)); + } +} diff --git a/app/Cache/Repository/ZSetRedis.php b/app/Cache/Repository/ZSetRedis.php new file mode 100644 index 0000000..4957256 --- /dev/null +++ b/app/Cache/Repository/ZSetRedis.php @@ -0,0 +1,169 @@ +redis()->zAdd($this->getKeyName(), $score, $member); + } + + /** + * 删除有序集合元素 + * + * @param string ...$member + * @return int + */ + public function rem(string ...$member) + { + return $this->redis()->zRem($this->getKeyName(), ...$member); + } + + /** + * 给指定元素累加分数 + * + * @param string $member 元素 + * @param float $score + * @return float + */ + public function incr(string $member, float $score) + { + return $this->redis()->zIncrBy($this->getKeyName(), $score, $member); + } + + /** + * 获取有序集合元素总数 + * + * @return int + */ + public function count() + { + return $this->redis()->zCard($this->getKeyName()); + } + + /** + * 获取有序集合所有元素 + * + * @param bool $asc [true:从高到低排序,false:从低到高排序] + * @param bool $is_score 是否需要分数值 + * @return array + */ + public function all($asc = true, $is_score = true) + { + return $this->redis()->{$asc ? 'zRevRange' : 'zRange'}($this->getKeyName(), 0, -1, $is_score); + } + + /** + * 获取排行榜单 + * + * @param int $page 分页 + * @param int $size 分页大小 + * @param bool $asc [true:从高到低排序,false:从低到高排序] + * @return array + */ + public function rank($page = 1, $size = 10, $asc = true) + { + $count = $this->count(); + + [$start, $end] = $asc ? ['+inf', '-inf'] : ['-inf', '+inf']; + + $rows = $this->redis()->{$asc ? 'zRevRangeByScore' : 'zRangeByScore'}($this->getKeyName(), $start, $end, [ + 'withscores' => true, + 'limit' => [($page - 1) * $size, $size] + ]); + + $ranks = []; + foreach ($rows as $node => $score) { + $ranks[] = [ + 'rank' => $this->getMemberRank($node, $asc), + 'node' => $node, + 'score' => $score + ]; + } + + return [ + 'count' => $count, + 'page' => $page, + 'size' => $size, + 'ranks' => $ranks + ]; + } + + /** + * 获取指定区间分数 + * + * @param string $start 最低分值 + * @param string $end 最高分值 + * @param array $options + * @return array + */ + public function range(string $start, string $end, array $options = []) + { + return $this->redis()->zRangeByScore($this->getKeyName(), $start, $end, $options); + } + + /** + * 获取指定元素的排名 + * + * @param string $member 元素 + * @param bool $asc [true:从高到低排序,false:从低到高排序] + * @return false|int + */ + public function getMemberRank(string $member, $asc = true) + { + return $this->redis()->{$asc ? 'zRevRank' : 'zRank'}($this->getKeyName(), $member) + 1; + } + + /** + * 获取指定元素的分数 + * + * @param string $member 元素 + * @return bool|float + */ + public function getMemberScore(string $member) + { + return $this->redis()->zScore($this->getKeyName(), $member); + } + + /** + * 判断是否是集合元素 + * + * @param string $member + * @return bool + */ + public function isMember(string $member) + { + return $this->redis()->zScore($this->getCacheKey($this->name), $member); + } + + /** + * 删除 ZSet 有序集合表 + * + * @return bool + */ + public function delete() + { + return (bool)$this->redis()->del($this->getKeyName()); + } +} diff --git a/app/Command/TestCommand.php b/app/Command/TestCommand.php new file mode 100644 index 0000000..e104e5f --- /dev/null +++ b/app/Command/TestCommand.php @@ -0,0 +1,103 @@ +container = $container; + + parent::__construct('test:command'); + } + + public function configure() + { + parent::configure(); + $this->setDescription('Hyperf Demo Command'); + } + + public function handle() + { + //$lock = LockRedis::getInstance(); + //var_dump($lock->delete('ttt')); + //var_dump($lock->lock('ttt', 180)); + + //$string = StringRedis::getInstance(); + //var_dump($string->set('yuandong', 'dong', 30)); + //var_dump($string->ttl('yuandong')); + //var_dump($string->isExist('yuandong')); + + //$hash = HashRedis::getInstance(); + //for ($i = 0; $i < 10; $i++) { + // $hash->add('user:' . $i, (string)rand(0, 100)); + //} + //var_dump($hash->count()); + //var_dump($hash->all()); + //var_dump($hash->isMember('user:1')); + //var_dump($hash->rem('user:3')); + //var_dump($hash->get('user:6')); + //$hash->incr('user:6',11); + //var_dump($hash->get('user:6')); + + //$list = ListRedis::getInstance(); + //$list->push('1','2','3','4','5'); + //var_dump($list->all()); + //var_dump($list->clear()); + //var_dump($list->count()); + + //$set = SetRedis::getInstance(); + //$set->add('user1','user:2','user:3'); + //var_dump($set->all()); + //var_dump($set->count()); + //var_dump($set->isMember('user:3')); + //var_dump($set->randMember(2)); + + //$zset = ZSetRedis::getInstance(); + //for ($i = 0; $i < 10; $i++) { + // $zset->add('user:' . $i, rand(0, 100)); + //} + //var_dump($zset->count()); + //var_dump($zset->all()); + //var_dump($zset->getMemberScore('user:2')); + //var_dump($zset->getMemberRank('user:2')); + //var_dump($zset->rank()); + //var_dump($zset->range('20','60')); + + //$stream = StreamRedis::getInstance(); + //var_dump($stream->info()); + //for ($i = 0; $i < 10; $i++) { + // $stream->add([ + // 'user_id' => $i, + // 'time' => time() + // ]); + //} + // + //$stream->run(function (string $id, array $data): bool { + // echo PHP_EOL . " 消息ID: {$id} , 任务数据: " . json_encode($data); + // + // return true; + //}, 'default', 'default'); + } +} diff --git a/app/Controller/Api/V1/ContactsController.php b/app/Controller/Api/V1/ContactsController.php index dc2f52c..7568a73 100644 --- a/app/Controller/Api/V1/ContactsController.php +++ b/app/Controller/Api/V1/ContactsController.php @@ -226,7 +226,7 @@ class ContactsController extends CController { $num = ApplyNumCache::get($this->uid()); return $this->response->success([ - 'unread_num' => $num ? $num : 0 + 'unread_num' => $num ?: 0 ]); }