Esempio n. 1
0
        /// <inheritdoc />
        public AsyncWireReaderBytesReadableAdapter([NotNull] IBytesReadable bytesReadableSource)
        {
            if (bytesReadableSource == null)
            {
                throw new ArgumentNullException(nameof(bytesReadableSource));
            }

            BytesReadableSource = bytesReadableSource;
        }
Esempio n. 2
0
        /// <summary>
        /// Reads <see cref="count"/> many bytes from the reader.
        /// </summary>
        /// <param name="readable"></param>
        /// <param name="count">How many bytes to read.</param>
        /// <returns>The read bytes.</returns>
        public static byte[] Read(this IBytesReadable readable, int count)
        {
            if (readable == null)
            {
                throw new ArgumentNullException(nameof(readable));
            }

            return(readable.ReadAsync(count, 0).WaitAndUnwrapException());
        }
Esempio n. 3
0
        /// <summary>
        /// Reads asyncronously <see cref="count"/> many bytes from the reader.
        /// </summary>
        /// <param name="buffer">The buffer to store the bytes into.</param>
        /// <param name="start">The start position in the buffer to start reading into.</param>
        /// <param name="count">How many bytes to read.</param>
        /// <param name="timeoutInMilliseconds">How many milliseconds to wait before canceling the operation.</param>
        /// <returns>A future for the read bytes.</returns>
        public static Task <int> ReadAsync(this IBytesReadable readable, byte[] buffer, int start, int count, int timeoutInMilliseconds)
        {
            if (readable == null)
            {
                throw new ArgumentNullException(nameof(readable));
            }

            //TODO: DO we need to check the timeout?
            return(readable.ReadAsync(buffer, 0, count, timeoutInMilliseconds > 0 ? new CancellationTokenSource(timeoutInMilliseconds).Token : CancellationToken.None));
        }
        //From: https://github.com/mgravell/protobuf-net/blob/38a2d0b6095dad08c57ef5bd7dc821643a86a4a1/src/protobuf-net/ProtoReader.cs
        /// <summary>
        /// Reads the length-prefix of a message from a stream without buffering additional data, allowing a fixed-length
        /// reader to be created.
        /// </summary>
        public static async Task <long> ReadLongLengthPrefix(IBytesReadable bytesReadable, PrefixStyle style, CancellationToken token)
        {
            switch (style)
            {
            case PrefixStyle.Base128:
                // check for a length
                return((long) await TryReadUInt64Variant(bytesReadable, token));

            case PrefixStyle.Fixed32:
            {
                //TODO: Figure out a way to reduce allocations
                byte[] bytes = await ReadFixed4Byte(bytesReadable, style, token)
                               .ConfigureAwait(false);

                //Means the socket disconnected
                if (bytes == null)
                {
                    return(0);
                }

                if (BitConverter.IsLittleEndian)
                {
                    return(bytes.Reinterpret <int>());
                }
                else
                {
                    throw new NotSupportedException("TODO: Implement big endian prefix handling.");
                }
            }

            case PrefixStyle.Fixed32BigEndian:
            {
                //TODO: Figure out a way to reduce allocations
                byte[] bytes = await ReadFixed4Byte(bytesReadable, style, token)
                               .ConfigureAwait(false);

                //Means the socket disconnected
                if (bytes == null)
                {
                    return(0);
                }

                //TODO: Improve efficiency
                return((bytes[0] << 24)
                       | (bytes[1] << 16)
                       | (bytes[2] << 8)
                       | bytes[3]);
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(style));
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Reads asyncronously <see cref="count"/> many bytes from the reader.
        /// </summary>
        /// <param name="readable"></param>
        /// <param name="count">How many bytes to read.</param>
        /// <param name="timeoutInMilliseconds">How many milliseconds to wait before canceling the operation.</param>
        /// <returns>A future for the read bytes.</returns>
        public static async Task <byte[]> ReadAsync(this IBytesReadable readable, int count, int timeoutInMilliseconds)
        {
            if (readable == null)
            {
                throw new ArgumentNullException(nameof(readable));
            }

            byte[] bytes = new byte[count];

            int resultCount = await readable.ReadAsync(bytes, 0, count, timeoutInMilliseconds)
                              .ConfigureAwait(false);

            if (resultCount != count)
            {
                throw new InvalidOperationException($"Failed to read {count} many bytes form {nameof(IBytesReadable)}. Read {resultCount} many bytes.");
            }

            return(bytes);
        }
        //TODO: Doc
        /// <summary>
        /// Asyncly reads a byte chunk from the <see cref="bytesReadable"/>
        /// or throws if unable.
        /// </summary>
        /// <param name="bytesReadable"></param>
        /// <param name="style"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private static async Task <byte[]> ReadFixed4Byte(IBytesReadable bytesReadable, PrefixStyle style, CancellationToken token)
        {
            byte[] bytes = new byte[4];
            int    count = await bytesReadable.ReadAsync(bytes, 0, 4, token)
                           .ConfigureAwait(false);

            //0 means the socket disconnected
            if (count == 0)
            {
                return(null);
            }

            if (count < 4)
            {
                throw new InvalidOperationException($"Protobuf-Net could not read length prefix: {style}");
            }

            return(bytes);
        }
        /// <inheritdoc />
        public async Task <TTypeToDeserializeTo> DeserializeAsync <TTypeToDeserializeTo>(IBytesReadable bytesReadable, CancellationToken token)
        {
            //TODO: Implement no prefixing support
            if (PrefixStyle == PrefixStyle.None)
            {
                throw new NotSupportedException("Protobuf-Net deserialization without length prefixing is not yet supported.");
            }

            //To do the async read operation with Protobuf-Net we need to do some manual buffering
            int prefixSize = checked ((int)await ReadLongLengthPrefix(bytesReadable, PrefixStyle, token).ConfigureAwait(false));

            //TODO: Reduce allocations somehow
            byte[] bytes = new byte[prefixSize];

            int count = await bytesReadable.ReadAsync(bytes, 0, prefixSize, token)
                        .ConfigureAwait(false);

            //0 means that the socket disconnected
            if (count == 0)
            {
                return(default(TTypeToDeserializeTo));
            }

            return(Serializer.Deserialize <TTypeToDeserializeTo>(new MemoryStream(bytes)));
        }
        /// <returns>The number of bytes consumed; 0 if no data available</returns>
        private static async Task <ulong> TryReadUInt64Variant(IBytesReadable bytesReadable, CancellationToken token)
        {
            //TODO: Reuse-share buffer to reduce allocations
            byte[] tempBuffer = new byte[9];

            ulong value = 0;
            int   count = await bytesReadable.ReadAsync(tempBuffer, 0, 1, token)
                          .ConfigureAwait(false);

            //0 means that the socket disconnected
            if (count == 0)
            {
                return(0);
            }

            int b = tempBuffer[0];

            if (b < 0)
            {
                return(0);
            }

            value = (uint)b;

            if ((value & 0x80) == 0)
            {
                return(1);
            }

            value &= 0x7F;

            int bytesRead = 1, shift = 7;

            while (bytesRead < 9)
            {
                count = await bytesReadable.ReadAsync(tempBuffer, bytesRead, 1, token)
                        .ConfigureAwait(false);

                //0 means the underlying socket disconnected
                if (count == 0)
                {
                    return(0);
                }

                b = tempBuffer[bytesRead];

                if (b < 0)
                {
                    throw EoF(null);
                }

                value |= ((ulong)b & 0x7F) << shift;
                shift += 7;

                if ((b & 0x80) == 0)
                {
                    return(value);
                }

                bytesRead++;
            }

            count = await bytesReadable.ReadAsync(tempBuffer, bytesRead, 1, token)
                    .ConfigureAwait(false);

            if (count == 0)
            {
                return(0);
            }

            b = tempBuffer[bytesRead];

            if (b < 0)
            {
                throw EoF(null);
            }

            if ((b & 1) == 0)            // only use 1 bit from the last byte
            {
                value |= ((ulong)b & 0x7F) << shift;
            }

            return(value);
        }
Esempio n. 9
0
 /// <inheritdoc />
 public Task <TTypeToDeserializeTo> DeserializeAsync <TTypeToDeserializeTo>(IBytesReadable bytesReadable, CancellationToken token)
 {
     //We have to manually add peek buffering
     return(Serializer.DeserializeAsync <TTypeToDeserializeTo>(new AsyncWireReaderBytesReadableAdapter(bytesReadable)
                                                               .PeekWithBufferingAsync()));
 }