summaryrefslogtreecommitdiffstats
path: root/vendor/clue/redis-protocol
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/clue/redis-protocol/composer.json19
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php51
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php31
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php23
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php100
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php53
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php40
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php10
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php28
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php125
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php151
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php111
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php83
16 files changed, 927 insertions, 0 deletions
diff --git a/vendor/clue/redis-protocol/composer.json b/vendor/clue/redis-protocol/composer.json
new file mode 100644
index 0000000..d99e2ee
--- /dev/null
+++ b/vendor/clue/redis-protocol/composer.json
@@ -0,0 +1,19 @@
+{
+ "name": "clue/redis-protocol",
+ "description": "A streaming redis wire protocol parser and serializer implementation in PHP",
+ "keywords": ["streaming", "redis", "protocol", "parser", "serializer"],
+ "homepage": "https://github.com/clue/php-redis-protocol",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "require": {
+ "php": ">=5.3"
+ },
+ "autoload": {
+ "psr-0": { "Clue\\Redis\\Protocol": "src" }
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php
new file mode 100644
index 0000000..3997f04
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Clue\Redis\Protocol;
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Parser\ResponseParser;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+use Clue\Redis\Protocol\Serializer\RecursiveSerializer;
+use Clue\Redis\Protocol\Parser\RequestParser;
+
+/**
+ * Provides factory methods used to instantiate the best available protocol implementation
+ */
+class Factory
+{
+ /**
+ * instantiate the best available protocol response parser implementation
+ *
+ * This is the parser every redis client implementation should use in order
+ * to parse incoming response messages from a redis server.
+ *
+ * @return ParserInterface
+ */
+ public function createResponseParser()
+ {
+ return new ResponseParser();
+ }
+
+ /**
+ * instantiate the best available protocol request parser implementation
+ *
+ * This is most useful for a redis server implementation which needs to
+ * process client requests.
+ *
+ * @return ParserInterface
+ */
+ public function createRequestParser()
+ {
+ return new RequestParser();
+ }
+
+ /**
+ * instantiate the best available protocol serializer implementation
+ *
+ * @return SerializerInterface
+ */
+ public function createSerializer()
+ {
+ return new RecursiveSerializer();
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php
new file mode 100644
index 0000000..e069fda
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class BulkReply implements ModelInterface
+{
+ private $value;
+
+ /**
+ * create bulk reply (string reply)
+ *
+ * @param string|null $data
+ */
+ public function __construct($value)
+ {
+ if ($value !== null) {
+ $value = (string)$value;
+ }
+ $this->value = $value;
+ }
+
+ public function getValueNative()
+ {
+ return $this->value;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getBulkMessage($this->value);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php
new file mode 100644
index 0000000..556e93b
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Exception;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+/**
+ *
+ * @link http://redis.io/topics/protocol#status-reply
+ */
+class ErrorReply extends Exception implements ModelInterface
+{
+ /**
+ * create error status reply (single line error message)
+ *
+ * @param string|ErrorReplyException $message
+ * @return string
+ */
+ public function __construct($message, $code = 0, $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
+
+ public function getValueNative()
+ {
+ return $this->getMessage();
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getErrorMessage($this->getMessage());
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php
new file mode 100644
index 0000000..ba1ff05
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class IntegerReply implements ModelInterface
+{
+ private $value;
+
+ /**
+ * create integer reply
+ *
+ * @param int $data
+ */
+ public function __construct($value)
+ {
+ $this->value = (int)$value;
+ }
+
+ public function getValueNative()
+ {
+ return $this->value;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getIntegerMessage($this->value);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php
new file mode 100644
index 0000000..b97939e
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+interface ModelInterface
+{
+ /**
+ * Returns value of this model as a native representation for PHP
+ *
+ * @return mixed
+ */
+ public function getValueNative();
+
+ /**
+ * Returns the serialized representation of this protocol message
+ *
+ * @param SerializerInterface $serializer;
+ * @return string
+ */
+ public function getMessageSerialized(SerializerInterface $serializer);
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php
new file mode 100644
index 0000000..7198dc6
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use InvalidArgumentException;
+use UnexpectedValueException;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class MultiBulkReply implements ModelInterface
+{
+ /**
+ * @var array|null
+ */
+ private $data;
+
+ /**
+ * create multi bulk reply (an array of other replies, usually bulk replies)
+ *
+ * @param array|null $data
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $data = null)
+ {
+ $this->data = $data;
+ }
+
+ public function getValueNative()
+ {
+ if ($this->data === null) {
+ return null;
+ }
+
+ $ret = array();
+ foreach ($this->data as $one) {
+ if ($one instanceof ModelInterface) {
+ $ret []= $one->getValueNative();
+ } else {
+ $ret []= $one;
+ }
+ }
+ return $ret;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getMultiBulkMessage($this->data);
+ }
+
+ /**
+ * Checks whether this model represents a valid unified request protocol message
+ *
+ * The new unified protocol was introduced in Redis 1.2, but it became the
+ * standard way for talking with the Redis server in Redis 2.0. The unified
+ * request protocol is what Redis already uses in replies in order to send
+ * list of items to clients, and is called a Multi Bulk Reply.
+ *
+ * @return boolean
+ * @link http://redis.io/topics/protocol
+ */
+ public function isRequest()
+ {
+ if (!$this->data) {
+ return false;
+ }
+
+ foreach ($this->data as $one) {
+ if (!($one instanceof BulkReply) && !is_string($one)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function getRequestModel()
+ {
+ if (!$this->data) {
+ throw new UnexpectedValueException('Null-multi-bulk message can not be represented as a request, must contain string/bulk values');
+ }
+
+ $command = null;
+ $args = array();
+
+ foreach ($this->data as $one) {
+ if ($one instanceof BulkReply) {
+ $one = $one->getValueNative();
+ } elseif (!is_string($one)) {
+ throw new UnexpectedValueException('Message can not be represented as a request, must only contain string/bulk values');
+ }
+
+ if ($command === null) {
+ $command = $one;
+ } else {
+ $args []= $one;
+ }
+ }
+
+ return new Request($command, $args);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php
new file mode 100644
index 0000000..f5881e9
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class Request implements ModelInterface
+{
+ private $command;
+ private $args;
+
+ public function __construct($command, array $args = array())
+ {
+ $this->command = $command;
+ $this->args = $args;
+ }
+
+ public function getCommand()
+ {
+ return $this->command;
+ }
+
+ public function getArgs()
+ {
+ return $this->args;
+ }
+
+ public function getReplyModel()
+ {
+ $models = array(new BulkReply($this->command));
+ foreach ($this->args as $arg) {
+ $models []= new BulkReply($arg);
+ }
+
+ return new MultiBulkReply($models);
+ }
+
+ public function getValueNative()
+ {
+ $ret = $this->args;
+ array_unshift($ret, $this->command);
+
+ return $ret;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getRequestMessage($this->command, $this->args);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php
new file mode 100644
index 0000000..4ea2fcd
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+/**
+ *
+ * @link http://redis.io/topics/protocol#status-reply
+ */
+class StatusReply implements ModelInterface
+{
+ private $message;
+
+ /**
+ * create status reply (single line message)
+ *
+ * @param string|Status $message
+ * @return string
+ */
+ public function __construct($message)
+ {
+ $this->message = $message;
+ }
+
+ public function getValueNative()
+ {
+ return $this->message;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getStatusMessage($this->message);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php
new file mode 100644
index 0000000..c1e3001
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use UnderflowException;
+
+class MessageBuffer implements ParserInterface
+{
+ private $parser;
+ private $incomingQueue = array();
+
+ public function __construct(ParserInterface $parser)
+ {
+ $this->parser = $parser;
+ }
+
+ public function popIncomingModel()
+ {
+ if (!$this->incomingQueue) {
+ throw new UnderflowException('Incoming message queue is empty');
+ }
+ return array_shift($this->incomingQueue);
+ }
+
+ public function hasIncomingModel()
+ {
+ return ($this->incomingQueue) ? true : false;
+ }
+
+ public function pushIncoming($data)
+ {
+ $ret = $this->parser->pushIncoming($data);
+
+ foreach ($ret as $one) {
+ $this->incomingQueue []= $one;
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php
new file mode 100644
index 0000000..e57c5bc
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use UnexpectedValueException;
+
+class ParserException extends UnexpectedValueException
+{
+
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php
new file mode 100644
index 0000000..a322719
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Parser\ParserException;
+
+interface ParserInterface
+{
+ /**
+ * push a chunk of the redis protocol message into the buffer and parse
+ *
+ * You can push any number of bytes of a redis protocol message into the
+ * parser and it will try to parse messages from its data stream. So you can
+ * pass data directly from your socket stream and the parser will return the
+ * right amount of message model objects for you.
+ *
+ * If you pass an incomplete message, expect it to return an empty array. If
+ * your incomplete message is split to across multiple chunks, the parsed
+ * message model will be returned once the parser has sufficient data.
+ *
+ * @param string $dataChunk
+ * @return ModelInterface[] 0+ message models
+ * @throws ParserException if the message can not be parsed
+ * @see self::popIncomingModel()
+ */
+ public function pushIncoming($dataChunk);
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php
new file mode 100644
index 0000000..a47d137
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Parser\ParserException;
+use Clue\Redis\Protocol\Model\Request;
+
+class RequestParser implements ParserInterface
+{
+ const CRLF = "\r\n";
+
+ private $incomingBuffer = '';
+ private $incomingOffset = 0;
+
+ public function pushIncoming($dataChunk)
+ {
+ $this->incomingBuffer .= $dataChunk;
+
+ $parsed = array();
+
+ do {
+ $saved = $this->incomingOffset;
+ $message = $this->readRequest();
+ if ($message === null) {
+ // restore previous position for next parsing attempt
+ $this->incomingOffset = $saved;
+ break;
+ }
+
+ if ($message !== false) {
+ $parsed []= $message;
+ }
+ } while($this->incomingBuffer !== '');
+
+ if ($this->incomingOffset !== 0) {
+ $this->incomingBuffer = (string)substr($this->incomingBuffer, $this->incomingOffset);
+ $this->incomingOffset = 0;
+ }
+
+ return $parsed;
+ }
+
+ /**
+ * try to parse request from incoming buffer
+ *
+ * @throws ParserException if the incoming buffer is invalid
+ * @return Request|null
+ */
+ private function readRequest()
+ {
+ $crlf = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+ if ($crlf === false) {
+ return null;
+ }
+
+ // line starts with a multi-bulk header "*"
+ if (isset($this->incomingBuffer[$this->incomingOffset]) && $this->incomingBuffer[$this->incomingOffset] === '*') {
+ $line = substr($this->incomingBuffer, $this->incomingOffset + 1, $crlf - $this->incomingOffset + 1);
+ $this->incomingOffset = $crlf + 2;
+ $count = (int)$line;
+
+ if ($count <= 0) {
+ return false;
+ }
+ $command = null;
+ $args = array();
+ for ($i = 0; $i < $count; ++$i) {
+ $sub = $this->readBulk();
+ if ($sub === null) {
+ return null;
+ }
+ if ($command === null) {
+ $command = $sub;
+ } else {
+ $args []= $sub;
+ }
+ }
+ return new Request($command, $args);
+ }
+
+ // parse an old inline request instead
+ $line = substr($this->incomingBuffer, $this->incomingOffset, $crlf - $this->incomingOffset);
+ $this->incomingOffset = $crlf + 2;
+
+ $args = preg_split('/ +/', trim($line, ' '));
+ $command = array_shift($args);
+
+ if ($command === '') {
+ return false;
+ }
+
+ return new Request($command, $args);
+ }
+
+ private function readBulk()
+ {
+ $crlf = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+ if ($crlf === false) {
+ return null;
+ }
+
+ // line has to start with a bulk header "$"
+ if (!isset($this->incomingBuffer[$this->incomingOffset]) || $this->incomingBuffer[$this->incomingOffset] !== '$') {
+ throw new ParserException('ERR Protocol error: expected \'$\', got \'' . substr($this->incomingBuffer, $this->incomingOffset, 1) . '\'');
+ }
+
+ $line = substr($this->incomingBuffer, $this->incomingOffset + 1, $crlf - $this->incomingOffset + 1);
+ $this->incomingOffset = $crlf + 2;
+ $size = (int)$line;
+
+ if ($size < 0) {
+ throw new ParserException('ERR Protocol error: invalid bulk length');
+ }
+
+ if (!isset($this->incomingBuffer[$this->incomingOffset + $size + 1])) {
+ // check enough bytes + crlf are buffered
+ return null;
+ }
+
+ $ret = substr($this->incomingBuffer, $this->incomingOffset, $size);
+ $this->incomingOffset += $size + 2;
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php
new file mode 100644
index 0000000..19ac90c
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\StatusReply;
+use Clue\Redis\Protocol\Parser\ParserException;
+
+/**
+ * Simple recursive redis wire protocol parser
+ *
+ * Heavily influenced by blocking parser implementation from jpd/redisent.
+ *
+ * @link https://github.com/jdp/redisent
+ * @link http://redis.io/topics/protocol
+ */
+class ResponseParser implements ParserInterface
+{
+ const CRLF = "\r\n";
+
+ private $incomingBuffer = '';
+ private $incomingOffset = 0;
+
+ public function pushIncoming($dataChunk)
+ {
+ $this->incomingBuffer .= $dataChunk;
+
+ return $this->tryParsingIncomingMessages();
+ }
+
+ private function tryParsingIncomingMessages()
+ {
+ $messages = array();
+
+ do {
+ $message = $this->readResponse();
+ if ($message === null) {
+ // restore previous position for next parsing attempt
+ $this->incomingOffset = 0;
+ break;
+ }
+
+ $messages []= $message;
+
+ $this->incomingBuffer = (string)substr($this->incomingBuffer, $this->incomingOffset);
+ $this->incomingOffset = 0;
+ } while($this->incomingBuffer !== '');
+
+ return $messages;
+ }
+
+ private function readLine()
+ {
+ $pos = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+
+ if ($pos === false) {
+ return null;
+ }
+
+ $ret = (string)substr($this->incomingBuffer, $this->incomingOffset, $pos - $this->incomingOffset);
+ $this->incomingOffset = $pos + 2;
+
+ return $ret;
+ }
+
+ private function readLength($len)
+ {
+ $ret = substr($this->incomingBuffer, $this->incomingOffset, $len);
+ if (strlen($ret) !== $len) {
+ return null;
+ }
+
+ $this->incomingOffset += $len;
+
+ return $ret;
+ }
+
+ /**
+ * try to parse response from incoming buffer
+ *
+ * ripped from jdp/redisent, with some minor modifications to read from
+ * the incoming buffer instead of issuing a blocking fread on a stream
+ *
+ * @throws ParserException if the incoming buffer is invalid
+ * @return ModelInterface|null
+ * @link https://github.com/jdp/redisent
+ */
+ private function readResponse()
+ {
+ /* Parse the response based on the reply identifier */
+ $reply = $this->readLine();
+ if ($reply === null) {
+ return null;
+ }
+ switch (substr($reply, 0, 1)) {
+ /* Error reply */
+ case '-':
+ $response = new ErrorReply(substr($reply, 1));
+ break;
+ /* Inline reply */
+ case '+':
+ $response = new StatusReply(substr($reply, 1));
+ break;
+ /* Bulk reply */
+ case '$':
+ $size = (int)substr($reply, 1);
+ if ($size === -1) {
+ return new BulkReply(null);
+ }
+ $data = $this->readLength($size);
+ if ($data === null) {
+ return null;
+ }
+ if ($this->readLength(2) === null) { /* discard crlf */
+ return null;
+ }
+ $response = new BulkReply($data);
+ break;
+ /* Multi-bulk reply */
+ case '*':
+ $count = (int)substr($reply, 1);
+ if ($count === -1) {
+ return new MultiBulkReply(null);
+ }
+ $response = array();
+ for ($i = 0; $i < $count; $i++) {
+ $sub = $this->readResponse();
+ if ($sub === null) {
+ return null;
+ }
+ $response []= $sub;
+ }
+ $response = new MultiBulkReply($response);
+ break;
+ /* Integer reply */
+ case ':':
+ $response = new IntegerReply(substr($reply, 1));
+ break;
+ default:
+ throw new ParserException('Invalid message can not be parsed: "' . $reply . '"');
+ break;
+ }
+ /* Party on */
+ return $response;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php
new file mode 100644
index 0000000..6e25125
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace Clue\Redis\Protocol\Serializer;
+
+use Clue\Redis\Protocol\Model\StatusReply;
+use InvalidArgumentException;
+use Exception;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\Request;
+
+class RecursiveSerializer implements SerializerInterface
+{
+ const CRLF = "\r\n";
+
+ public function getRequestMessage($command, array $args = array())
+ {
+ $data = '*' . (count($args) + 1) . "\r\n$" . strlen($command) . "\r\n" . $command . "\r\n";
+ foreach ($args as $arg) {
+ $data .= '$' . strlen($arg) . "\r\n" . $arg . "\r\n";
+ }
+ return $data;
+ }
+
+ public function createRequestModel($command, array $args = array())
+ {
+ return new Request($command, $args);
+ }
+
+ public function getReplyMessage($data)
+ {
+ if (is_string($data) || $data === null) {
+ return $this->getBulkMessage($data);
+ } else if (is_int($data) || is_float($data) || is_bool($data)) {
+ return $this->getIntegerMessage($data);
+ } else if ($data instanceof Exception) {
+ return $this->getErrorMessage($data->getMessage());
+ } else if (is_array($data)) {
+ return $this->getMultiBulkMessage($data);
+ } else {
+ throw new InvalidArgumentException('Invalid data type passed for serialization');
+ }
+ }
+
+ public function createReplyModel($data)
+ {
+ if (is_string($data) || $data === null) {
+ return new BulkReply($data);
+ } else if (is_int($data) || is_float($data) || is_bool($data)) {
+ return new IntegerReply($data);
+ } else if ($data instanceof Exception) {
+ return new ErrorReply($data->getMessage());
+ } else if (is_array($data)) {
+ $models = array();
+ foreach ($data as $one) {
+ $models []= $this->createReplyModel($one);
+ }
+ return new MultiBulkReply($models);
+ } else {
+ throw new InvalidArgumentException('Invalid data type passed for serialization');
+ }
+ }
+
+ public function getBulkMessage($data)
+ {
+ if ($data === null) {
+ /* null bulk reply */
+ return '$-1' . self::CRLF;
+ }
+ /* bulk reply */
+ return '$' . strlen($data) . self::CRLF . $data . self::CRLF;
+ }
+
+ public function getErrorMessage($data)
+ {
+ /* error status reply */
+ return '-' . $data . self::CRLF;
+ }
+
+ public function getIntegerMessage($data)
+ {
+ return ':' . (int)$data . self::CRLF;
+ }
+
+ public function getMultiBulkMessage($data)
+ {
+ if ($data === null) {
+ /* null multi bulk reply */
+ return '*-1' . self::CRLF;
+ }
+ /* multi bulk reply */
+ $ret = '*' . count($data) . self::CRLF;
+ foreach ($data as $one) {
+ if ($one instanceof ModelInterface) {
+ $ret .= $one->getMessageSerialized($this);
+ } else {
+ $ret .= $this->getReplyMessage($one);
+ }
+ }
+ return $ret;
+ }
+
+ public function getStatusMessage($data)
+ {
+ /* status reply */
+ return '+' . $data . self::CRLF;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php
new file mode 100644
index 0000000..bb7cb3e
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Clue\Redis\Protocol\Serializer;
+
+use Clue\Redis\Protocol\Model\ErrorReplyException;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+
+interface SerializerInterface
+{
+ /**
+ * create a serialized unified request protocol message
+ *
+ * This is the *one* method most redis client libraries will likely want to
+ * use in order to send a serialized message (a request) over the* wire to
+ * your redis server instance.
+ *
+ * This method should be used in favor of constructing a request model and
+ * then serializing it. While its effect might be equivalent, this method
+ * is likely to (i.e. it /could/) provide a faster implementation.
+ *
+ * @param string $command
+ * @param array $args
+ * @return string
+ * @see self::createRequestMessage()
+ */
+ public function getRequestMessage($command, array $args = array());
+
+ /**
+ * create a unified request protocol message model
+ *
+ * @param string $command
+ * @param array $args
+ * @return MultiBulkReply
+ */
+ public function createRequestModel($command, array $args = array());
+
+ /**
+ * create a serialized unified protocol reply message
+ *
+ * This is most useful for a redis server implementation which needs to
+ * process client requests and send resulting reply messages.
+ *
+ * This method does its best to guess to right reply type and then returns
+ * a serialized version of the message. It follows the "redis to lua
+ * conversion table" (see link) which means most basic types can be mapped
+ * as is.
+ *
+ * This method should be used in favor of constructing a reply model and
+ * then serializing it. While its effect might be equivalent, this method
+ * is likely to (i.e. it /could/) provide a faster implementation.
+ *
+ * Note however, you may still want to explicitly create a nested reply
+ * model hierarchy if you need more control over the serialized message. For
+ * instance, a null value will always be returned as a Null-Bulk-Reply, so
+ * there's no way to express a Null-Multi-Bulk-Reply, unless you construct
+ * it explicitly.
+ *
+ * @param mixed $data
+ * @return string
+ * @see self::createReplyModel()
+ * @link http://redis.io/commands/eval
+ */
+ public function getReplyMessage($data);
+
+ /**
+ * create response message by determining datatype from given argument
+ *
+ * @param mixed $data
+ * @return ModelInterface
+ */
+ public function createReplyModel($data);
+
+ public function getBulkMessage($data);
+
+ public function getErrorMessage($data);
+
+ public function getIntegerMessage($data);
+
+ public function getMultiBulkMessage($data);
+
+ public function getStatusMessage($data);
+}