From d597b119d6af261b46d55d19b87185f13b31f9dc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Wed, 28 Sep 2016 17:14:38 +0200 Subject: [PATCH] Allow plugins to leverage the Redis connection of the RedisCacheSource This removes the need to manually parse the Redis DSN specified by the administrator and saves socket connections by multiplexing the commands over a single connection, without being able to break the connection used by cache. --- .../cache/source/RedisCacheSource.class.php | 50 +++------ .../files/lib/system/database/Redis.class.php | 101 ++++++++++++++++++ 2 files changed, 116 insertions(+), 35 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/database/Redis.class.php diff --git a/wcfsetup/install/files/lib/system/cache/source/RedisCacheSource.class.php b/wcfsetup/install/files/lib/system/cache/source/RedisCacheSource.class.php index 960c0b217f..92cdb763bd 100644 --- a/wcfsetup/install/files/lib/system/cache/source/RedisCacheSource.class.php +++ b/wcfsetup/install/files/lib/system/cache/source/RedisCacheSource.class.php @@ -1,8 +1,7 @@ redis = new Redis(CACHE_SOURCE_REDIS_HOST); } - - $this->redis = new \Redis(); - - $regex = new Regex('^\[([a-z0-9\:\.]+)\](?::([0-9]{1,5}))?$', Regex::CASE_INSENSITIVE); - $host = StringUtil::trim(CACHE_SOURCE_REDIS_HOST); - $port = 6379; // default Redis port - - // check for IPv6 - if ($regex->match($host)) { - $matches = $regex->getMatches(); - $host = $matches[1]; - - if (isset($matches[2])) { - $port = $matches[2]; - } - } - else { - // IPv4 or host, try to get port - if (strpos($host, ':')) { - $parsedHost = explode(':', $host); - $host = $parsedHost[0]; - $port = $parsedHost[1]; - } + catch (\Exception $e) { + throw new SystemException('Unable to create a Redis instance', 0, '', $e); } - - if (!$this->redis->connect($host, $port)) { - throw new SystemException('Unable to connect to Redis server'); - } - - // automatically prefix key names with the WCF UUID - $this->redis->setOption(\Redis::OPT_PREFIX, WCF_UUID.':'); } /** @@ -193,4 +164,13 @@ class RedisCacheSource implements ICacheSource { return $info['redis_version']; } + + /** + * Returns the underlying Redis instance. + * + * @return Redis + */ + public function getRedis() { + return $this->redis; + } } diff --git a/wcfsetup/install/files/lib/system/database/Redis.class.php b/wcfsetup/install/files/lib/system/database/Redis.class.php new file mode 100644 index 0000000000..73fd8851e4 --- /dev/null +++ b/wcfsetup/install/files/lib/system/database/Redis.class.php @@ -0,0 +1,101 @@ + + * @package WoltLabSuite\Core\System\Database + */ +class Redis { + /** + * wrapped redis connection + * @var \Redis + */ + protected $redis = null; + + /** + * DSN string used to connect. + * @var string + */ + protected $dsn = ''; + + /** + * Connects to the redis server given by the DSN. + */ + public function __construct($dsn) { + if (!class_exists('Redis')) { + throw new \BadMethodCallException('Redis support is not enabled.'); + } + + $this->dsn = $dsn; + + $this->redis = new \Redis(); + + $regex = new Regex('^\[([a-z0-9\:\.]+)\](?::([0-9]{1,5}))?$', Regex::CASE_INSENSITIVE); + $host = StringUtil::trim($this->dsn); + $port = 6379; // default Redis port + + // check for IPv6 + if ($regex->match($host)) { + $matches = $regex->getMatches(); + $host = $matches[1]; + + if (isset($matches[2])) { + $port = $matches[2]; + } + } + else { + // IPv4 or host, try to get port + if (strpos($host, ':')) { + $parsedHost = explode(':', $host); + $host = $parsedHost[0]; + $port = $parsedHost[1]; + } + } + + if (!$this->redis->connect($host, $port)) { + throw new \RuntimeException('Unable to connect to Redis server'); + } + + // automatically prefix key names with the WCF UUID + $this->redis->setOption(\Redis::OPT_PREFIX, WCF_UUID.':'); + } + + /** + * Passes all method calls down to the underlying Redis connection. + */ + public function __call($name, array $arguments) { + switch ($name) { + case 'setOption': + case 'getOption': + + case 'open': + case 'connect': + + case 'popen': + case 'pconnect': + + case 'auth': + + case 'select': + + case 'close': + throw new \BadMethodCallException('You must not use '.$name); + } + return call_user_func_array([$this->redis, $name], $arguments); + } + + /** + * Returns a new, raw, redis instance to the same server. + * + * @return \Redis + */ + public function unwrap() { + return (new self($this->dsn))->redis; + } +} -- 2.20.1