This commit is contained in:
2026-05-01 23:40:14 +08:00
commit b8f599a617
3867 changed files with 478663 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 webman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+2
View File
@@ -0,0 +1,2 @@
# Webman redis
This is Webman's redis library, which includes redis client and connection pool.
+18
View File
@@ -0,0 +1,18 @@
{
"name": "webman/redis",
"type": "library",
"license": "MIT",
"description": "Webman redis",
"require": {
"workerman/webman-framework": "^2.1 || dev-master",
"illuminate/redis": "^10.0 || ^11.0 || ^12.0 || ^13.0"
},
"autoload": {
"psr-4": {
"Webman\\Redis\\": "src",
"support\\": "src/support"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace Webman\Redis;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static array $pathRelation = [];
/**
* Install
* @return void
*/
public static function install(): void
{
$redis_file = config_path('redis.php');
if (!is_file($redis_file)) {
echo 'Create config/redis.php' . PHP_EOL;
copy(__DIR__ . '/config/redis.php', $redis_file);
}
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall(): void
{
$redis_file = config_path('redis.php');
if (is_file($redis_file)) {
echo 'Remove config/redis.php' . PHP_EOL;
unlink($redis_file);
}
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation(): void
{
foreach (static::$pathRelation as $source => $dest) {
if ($pos = strrpos($dest, '/')) {
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
if (!is_dir($parent_dir)) {
mkdir($parent_dir, 0777, true);
}
}
copy_dir(__DIR__ . "/$source", base_path()."/$dest");
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation(): void
{
foreach (static::$pathRelation as $source => $dest) {
$path = base_path()."/$dest";
if (!is_dir($path) && !is_file($path)) {
continue;
}
remove_dir($path);
}
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace Webman\Redis;
use Illuminate\Events\Dispatcher;
use Illuminate\Redis\Connections\Connection;
use StdClass;
use Throwable;
use WeakMap;
use Webman\Context;
use Workerman\Coroutine\Pool;
class RedisManager extends \Illuminate\Redis\RedisManager
{
/**
* @var Pool[]
*/
protected static array $pools = [];
/**
* @var WeakMap
*/
protected WeakMap $allConnections;
/**
* Get connection.
*
* @param $name
* @return Connection|mixed|StdClass|null
* @throws Throwable
*/
public function connection($name = null)
{
$name = $name ?: 'default';
$key = "redis.connections.$name";
$connection = Context::get($key);
if (!$connection) {
if (!isset(static::$pools[$name])) {
$poolConfig = $this->config[$name]['pool'] ?? [];
$pool = new Pool($poolConfig['max_connections'] ?? 10, $poolConfig);
$pool->setConnectionCreator(function () use ($name) {
$connection = $this->configure($this->resolve($name), $name);
if (class_exists(Dispatcher::class)) {
$connection->setEventDispatcher(new Dispatcher());
}
$this->allConnections ??= new WeakMap();
$this->allConnections[$connection] = true;
return $connection;
});
$pool->setConnectionCloser(function ($connection) {
$connection->client()->close();
});
$pool->setHeartbeatChecker(function ($connection) {
$connection->get('PING');
});
static::$pools[$name] = $pool;
}
try {
$connection = static::$pools[$name]->get();
Context::set($key, $connection);
} finally {
Context::onDestroy(function () use ($connection, $name) {
try {
$connection && static::$pools[$name]->put($connection);
} catch (Throwable) {
// ignore
}
});
}
}
return $connection;
}
/**
* Return all the created connections.
*
* @return array
*/
public function connections()
{
if (empty($this->allConnections)) {
return [];
}
$connections = [];
foreach ($this->allConnections as $connection => $_) {
$connections[] = $connection;
}
return $connections;
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'default' => [
'password' => '',
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
'pool' => [
'max_connections' => 5,
'min_connections' => 1,
'wait_timeout' => 3,
'idle_timeout' => 60,
'heartbeat_interval' => 50,
],
]
];
+284
View File
@@ -0,0 +1,284 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support;
use Illuminate\Redis\Connections\Connection;
use Throwable;
use Webman\Redis\RedisManager;
use Redis as RedisClient;
use function config;
use function in_array;
/**
* Class Redis
* @package support
*
* Strings methods
* @method static int append($key, $value)
* @method static int bitCount($key)
* @method static int decr($key, $value = 1)
* @method static int decrBy($key, $value)
* @method static string|bool get($key)
* @method static int getBit($key, $offset)
* @method static string getRange($key, $start, $end)
* @method static string getSet($key, $value)
* @method static int incr($key, $value = 1)
* @method static int incrBy($key, $value)
* @method static float incrByFloat($key, $value)
* @method static array mGet(array $keys)
* @method static array getMultiple(array $keys)
* @method static bool mSet($pairs)
* @method static bool mSetNx($pairs)
* @method static bool set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method static bool setBit($key, $offset, $value)
* @method static bool setEx($key, $ttl, $value)
* @method static bool pSetEx($key, $ttl, $value)
* @method static bool setNx($key, $value)
* @method static string setRange($key, $offset, $value)
* @method static int strLen($key)
* Keys methods
* @method static int del(...$keys)
* @method static int unlink(...$keys)
* @method static false|string dump($key)
* @method static int exists(...$keys)
* @method static bool expire($key, $ttl)
* @method static bool pexpire($key, $ttl)
* @method static bool expireAt($key, $timestamp)
* @method static bool pexpireAt($key, $timestamp)
* @method static array keys($pattern)
* @method static bool|array scan($it)
* @method static void migrate($host, $port, $keys, $dbIndex, $timeout, $copy = false, $replace = false)
* @method static bool select($dbIndex)
* @method static bool move($key, $dbIndex)
* @method static string|int|bool object($information, $key)
* @method static bool persist($key)
* @method static string randomKey()
* @method static bool rename($srcKey, $dstKey)
* @method static bool renameNx($srcKey, $dstKey)
* @method static string type($key)
* @method static int|array sort($key, $options = [])
* @method static int ttl($key)
* @method static int pttl($key)
* @method static void restore($key, $ttl, $value)
* Hashes methods
* @method static false|int hSet($key, $hashKey, $value)
* @method static bool hSetNx($key, $hashKey, $value)
* @method static false|string hGet($key, $hashKey)
* @method static false|int hLen($key)
* @method static false|int hDel($key, ...$hashKeys)
* @method static array hKeys($key)
* @method static array hVals($key)
* @method static array hGetAll($key)
* @method static bool hExists($key, $hashKey)
* @method static int hIncrBy($key, $hashKey, $value)
* @method static float hIncrByFloat($key, $hashKey, $value)
* @method static bool hMSet($key, $members)
* @method static array hMGet($key, $memberKeys)
* @method static array hScan($key, $iterator, $pattern = '', $count = 0)
* @method static int hStrLen($key, $hashKey)
* Lists methods
* @method static array blPop($keys, $timeout)
* @method static array brPop($keys, $timeout)
* @method static false|string bRPopLPush($srcKey, $dstKey, $timeout)
* @method static false|string lIndex($key, $index)
* @method static int lInsert($key, $position, $pivot, $value)
* @method static false|string lPop($key)
* @method static false|int lPush($key, ...$entries)
* @method static false|int lPushx($key, $value)
* @method static array lRange($key, $start, $end)
* @method static false|int lRem($key, $count, $value)
* @method static bool lSet($key, $index, $value)
* @method static false|array lTrim($key, $start, $end)
* @method static false|string rPop($key)
* @method static false|string rPopLPush($srcKey, $dstKey)
* @method static false|int rPush($key, ...$entries)
* @method static false|int rPushX($key, $value)
* @method static false|int lLen($key)
* Sets methods
* @method static int sAdd($key, $value)
* @method static int sCard($key)
* @method static array sDiff($keys)
* @method static false|int sDiffStore($dst, $keys)
* @method static false|array sInter($keys)
* @method static false|int sInterStore($dst, $keys)
* @method static bool sIsMember($key, $member)
* @method static array sMembers($key)
* @method static bool sMove($src, $dst, $member)
* @method static false|string|array sPop($key, $count = 0)
* @method static false|string|array sRandMember($key, $count = 0)
* @method static int sRem($key, ...$members)
* @method static array sUnion(...$keys)
* @method static false|int sUnionStore($dst, ...$keys)
* @method static false|array sScan($key, $iterator, $pattern = '', $count = 0)
* Sorted sets methods
* @method static array bzPopMin($keys, $timeout)
* @method static array bzPopMax($keys, $timeout)
* @method static int zAdd($key, $score, $value)
* @method static int zCard($key)
* @method static int zCount($key, $start, $end)
* @method static double zIncrBy($key, $value, $member)
* @method static int zinterstore($keyOutput, $arrayZSetKeys, $arrayWeights = [], $aggregateFunction = '')
* @method static array zPopMin($key, $count)
* @method static array zPopMax($key, $count)
* @method static array zRange($key, $start, $end, $withScores = false)
* @method static array zRangeByScore($key, $start, $end, $options = [])
* @method static array zRevRangeByScore($key, $start, $end, $options = [])
* @method static array zRangeByLex($key, $min, $max, $offset = 0, $limit = 0)
* @method static int zRank($key, $member)
* @method static int zRevRank($key, $member)
* @method static int zRem($key, ...$members)
* @method static int zRemRangeByRank($key, $start, $end)
* @method static int zRemRangeByScore($key, $start, $end)
* @method static array zRevRange($key, $start, $end, $withScores = false)
* @method static double zScore($key, $member)
* @method static int zunionstore($keyOutput, $arrayZSetKeys, $arrayWeights = [], $aggregateFunction = '')
* @method static false|array zScan($key, $iterator, $pattern = '', $count = 0)
* HyperLogLogs methods
* @method static int pfAdd($key, $values)
* @method static int pfCount($keys)
* @method static bool pfMerge($dstKey, $srcKeys)
* Geocoding methods
* @method static int geoAdd($key, $longitude, $latitude, $member, ...$items)
* @method static array geoHash($key, ...$members)
* @method static array geoPos($key, ...$members)
* @method static double geoDist($key, $members, $unit = '')
* @method static int|array geoRadius($key, $longitude, $latitude, $radius, $unit, $options = [])
* @method static array geoRadiusByMember($key, $member, $radius, $units, $options = [])
* Streams methods
* @method static int xAck($stream, $group, $arrMessages)
* @method static string xAdd($strKey, $strId, $arrMessage, $iMaxLen = 0, $booApproximate = false)
* @method static array xClaim($strKey, $strGroup, $strConsumer, $minIdleTime, $arrIds, $arrOptions = [])
* @method static int xDel($strKey, $arrIds)
* @method static mixed xGroup($command, $strKey, $strGroup, $strMsgId, $booMKStream = null)
* @method static mixed xInfo($command, $strStream, $strGroup = null)
* @method static int xLen($stream)
* @method static array xPending($strStream, $strGroup, $strStart = 0, $strEnd = 0, $iCount = 0, $strConsumer = null)
* @method static array xRange($strStream, $strStart, $strEnd, $iCount = 0)
* @method static array xRead($arrStreams, $iCount = 0, $iBlock = null)
* @method static array xReadGroup($strGroup, $strConsumer, $arrStreams, $iCount = 0, $iBlock = null)
* @method static array xRevRange($strStream, $strEnd, $strStart, $iCount = 0)
* @method static int xTrim($strStream, $iMaxLen, $booApproximate = null)
* Pub/sub methods
* @method static mixed pSubscribe($patterns, $callback)
* @method static mixed publish($channel, $message)
* @method static mixed subscribe($channels, $callback)
* @method static mixed pubSub($keyword, $argument = null)
* Generic methods
* @method static mixed rawCommand(...$commandAndArgs)
* Pipeline methods
* @method static RedisClient|array pipeline(callable|null $callback = null)
* Transactions methods
* @method static RedisClient multi()
* @method static mixed exec()
* @method static mixed discard()
* @method static mixed watch($keys)
* @method static mixed unwatch($keys)
* Scripting methods
* @method static mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method static mixed evalSha($scriptSha, $numkeys, ...$arguments)
* @method static mixed script($command, ...$scripts)
* @method static mixed client(...$args)
* @method static null|string getLastError()
* @method static bool clearLastError()
* @method static mixed _prefix($value)
* @method static mixed _serialize($value)
* @method static mixed _unserialize($value)
* Introspection methods
* @method static bool isConnected()
* @method static mixed getHost()
* @method static mixed getPort()
* @method static false|int getDbNum()
* @method static false|double getTimeout()
* @method static mixed getReadTimeout()
* @method static mixed getPersistentID()
* @method static mixed getAuth()
*/
class Redis
{
/**
* @var RedisManager|null
*/
protected static ?RedisManager $instance = null;
/**
* need to install phpredis extension
*/
const PHPREDIS_CLIENT = 'phpredis';
/**
* need to install the 'predis/predis' packgage.
* cmd: composer install predis/predis
*/
const PREDIS_CLIENT = 'predis';
/**
* Support client collection
*/
static array $allowClient = [
self::PHPREDIS_CLIENT,
self::PREDIS_CLIENT
];
/**
* The Redis server configurations.
*
* @var array
*/
protected static array $config = [];
/**
* @return RedisManager|null
*/
public static function instance(): ?RedisManager
{
if (!static::$instance) {
$config = config('redis');
$client = $config['client'] ?? self::PHPREDIS_CLIENT;
if (!in_array($client, static::$allowClient)) {
$client = self::PHPREDIS_CLIENT;
}
static::$config = $config;
static::$instance = new RedisManager('', $client, $config);
}
return static::$instance;
}
/**
* Connection.
* @param string $name
* @return Connection|RedisClient
* @throws Throwable
*/
public static function connection(string $name = 'default'): Connection
{
return static::instance()->connection($name);
}
/**
* @param string $name
* @param array $arguments
* @return mixed
* @throws Throwable
*/
public static function __callStatic(string $name, array $arguments)
{
return static::connection()->{$name}(... $arguments);
}
}