Пример #1
0
        /// <summary>
        /// Applies the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        private void applyString(byte[] value)
        {
            if (operations.Count == 0)
            {
                receivedData.Enqueue(value);
                return;
            }

            object nextOp = operations.Peek();

            if (nextOp is AwaitString && !((AwaitString)nextOp).readSize)
            {
                AwaitString op   = (AwaitString)nextOp;
                int         size = Convert.ToInt32(Encoding.ASCII.GetString(value));
                op.readSize = true;
                op.size     = size;
                op.data     = new byte[] {};
                if (op.size < 0)
                {
                    operations.Pop();
                    applyString(null);
                }
            }
            else if (nextOp is AwaitList && !((AwaitList)nextOp).readLength)
            {
                AwaitList op     = (AwaitList)nextOp;
                int       length = Convert.ToInt32(Encoding.ASCII.GetString(value));
                op.readLength = true;
                op.length     = length;
                if (op.length < 0)
                {
                    operations.Pop();
                    applyString(null);
                }
                op.data = new object[length];
            }
            else
            {
                if (!applyToList(value))
                {
                    receivedData.Enqueue(value);
                    operations.Push(new AwaitCrLf());
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Updates the internal states based on the latest bytes read.
        /// </summary>
        /// <param name="bytesRead">The number of bytes read.</param>
        /// <exception cref="System.NotImplementedException">
        /// Operation not implemented for  + encoding.GetString(buffer, bufferIndex, 1)
        /// or
        /// Don't know what to do.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// Protocol Violation. Expected CR-LF.
        /// or
        /// Protocol Violation. Expected CR.
        /// or
        /// Protocol Violation. Expected LF.
        /// </exception>
        public void update(int bytesRead)
        {
            int bufferIndex = 0;

            while (bufferIndex < buffer.Length && bufferIndex < bytesRead)
            {
                if (operations.Count == 0)
                {
                    operations.Push(new AwaitCommand());
                }
                object nextOp = operations.Peek();
                if (nextOp is AwaitCommand)
                {
                    switch (buffer[bufferIndex])
                    {
                    case PLUS:
                        operations.Pop();
                        operations.Push(new AwaitSimpleString());
                        ++bufferIndex;
                        continue;

                    case DOLLAR:
                        operations.Pop();
                        operations.Push(new AwaitString {
                            readSize = false
                        });
                        operations.Push(new AwaitSimpleString());
                        ++bufferIndex;
                        continue;

                    case COLON:
                        operations.Pop();
                        operations.Push(new AwaitInt());
                        ++bufferIndex;
                        continue;

                    case ASTERISK:
                        operations.Pop();
                        operations.Push(new AwaitList {
                            readLength = false
                        });
                        operations.Push(new AwaitSimpleString());
                        ++bufferIndex;
                        continue;

                    case MINUS:
                        operations.Pop();
                        operations.Push(new AwaitError());
                        operations.Push(new AwaitSimpleString());
                        ++bufferIndex;
                        continue;

                    default:
                        throw new NotImplementedException("Operation not implemented for " + encoding.GetString(buffer, bufferIndex, 1));
                    }
                }
                else if (nextOp is AwaitCrLf)
                {
                    AwaitCrLf op = (AwaitCrLf)nextOp;
                    int       availableLength = buffer.Length - bufferIndex;
                    if (availableLength < 1)
                    {
                        continue;
                    }
                    if (!op.cr)
                    {
                        if (availableLength >= 2)
                        {
                            if (buffer[bufferIndex] == CR && buffer[bufferIndex + 1] == LF)
                            {
                                operations.Pop();
                                bufferIndex += 2;
                            }
                            else
                            {
                                throw new InvalidOperationException("Protocol Violation. Expected CR-LF.");
                            }
                        }
                        else
                        {
                            if (buffer[bufferIndex] == CR)
                            {
                                op.cr = true;
                                ++bufferIndex;
                            }
                            else
                            {
                                throw new InvalidOperationException("Protocol Violation. Expected CR.");
                            }
                        }
                    }
                    else
                    {
                        if (buffer[bufferIndex] == LF)
                        {
                            operations.Pop();
                            ++bufferIndex;
                        }
                        else
                        {
                            throw new InvalidOperationException("Protocol Violation. Expected LF.");
                        }
                    }
                }
                else if (nextOp is AwaitSimpleString)
                {
                    AwaitSimpleString  op            = (AwaitSimpleString)nextOp;
                    IEnumerable <byte> partialBuffer = buffer.Skip(bufferIndex).Take(bytesRead - bufferIndex);
                    byte[]             potential     = op.data == null?partialBuffer.ToArray() : op.data.Concat(partialBuffer).ToArray();

                    int indexCrLf = potential.indexOf(CrLf);
                    if (indexCrLf == -1)
                    {
                        op.data     = potential;
                        bufferIndex = buffer.Length;
                    }
                    else
                    {
                        byte[] stringData = potential.Take(indexCrLf).ToArray();
                        operations.Pop();
                        if (operations.Count > 0 && operations.Peek() is AwaitError)
                        {
                            operations.Pop();
                            apply(new RedisErrorException(encoding.GetString(stringData)));
                        }
                        else
                        {
                            applyString(stringData);
                        }
                        bufferIndex += indexCrLf + CrLf.Length - (op.data == null ? 0 : op.data.Length);
                    }
                }
                else if (nextOp is AwaitInt)
                {
                    AwaitInt           op            = (AwaitInt)nextOp;
                    IEnumerable <byte> partialBuffer = buffer.Skip(bufferIndex).Take(bytesRead - bufferIndex);
                    byte[]             potential     = op.data == null?partialBuffer.ToArray() : op.data.Concat(partialBuffer).ToArray();

                    int indexCrLf = potential.indexOf(CrLf);
                    if (indexCrLf == -1)
                    {
                        op.data     = potential;
                        bufferIndex = buffer.Length;
                    }
                    else
                    {
                        byte[] stringData   = potential.Take(indexCrLf).ToArray();
                        string valueLiteral = _encoding.GetString(stringData);
                        operations.Pop();
                        long value;
                        if (long.TryParse(valueLiteral, out value))
                        {
                            apply(value);
                        }
                        else
                        {
                            apply(new Exception(string.Format("Failed to parse {0} as an integer", valueLiteral)));
                        }
                        bufferIndex += indexCrLf + CrLf.Length - (op.data == null ? 0 : op.data.Length);
                    }
                }
                else if (nextOp is AwaitString)
                {
                    AwaitString op              = (AwaitString)nextOp;
                    int         currentSize     = op.data.Length;
                    int         availableLength = buffer.Length - bufferIndex;
                    if (currentSize + availableLength >= op.size)
                    {
                        int    count      = op.size - op.data.Length;
                        byte[] stringData = op.data.Concat(buffer.Skip(bufferIndex).Take(count)).ToArray();
                        operations.Pop();
                        applyString(stringData);
                        bufferIndex = bufferIndex + count;
                        operations.Push(new AwaitCrLf());
                        continue;
                    }
                    else
                    {
                        op.data     = op.data.Concat(buffer.Skip(bufferIndex).Take(availableLength)).ToArray();
                        bufferIndex = bufferIndex + availableLength;
                    }
                }
                else if (nextOp is AwaitList)
                {
                    AwaitList op = (AwaitList)nextOp;
                    if (op.objectsRead < op.length)
                    {
                        operations.Push(new AwaitCommand());
                    }
                }
                else
                {
                    throw new NotImplementedException("Don't know what to do.");
                }


                nextOp = operations.Count > 0 ? operations.Peek() : null;
                while (nextOp is AwaitList && ((AwaitList)nextOp).objectsRead >= ((AwaitList)nextOp).length)
                {
                    operations.Pop();
                    apply(((AwaitList)nextOp).data);
                    nextOp = operations.Count > 0 ? operations.Peek() : null;
                }

                if (operations.Count == 0)
                {
                    // Opportunity here to convert from "internal" state to "external" state.
                    Queue receivedObject = new Queue(receivedData.Count);
                    while (receivedData.Count > 0)
                    {
                        receivedObject.Enqueue(receivedData.Dequeue());
                    }
                    _onObjectReceived(new ObjectReceivedEventArgs(receivedObject));
                }
            }
        }