Esempio n. 1
0
        public virtual async ValueTask <MessageReadResult <T> > ReadAsync()
        {
            DateTime timeReceived = DateTime.UtcNow;

            bool partialMessage = false;

            // Try to read one full message.
            try
            {
                T message             = default;
                SequencePosition read = default;

                var        closeToken = closeCts?.Token ?? default;
                ReadResult result     = await duplexMessageStream.ReadAsync(closeToken).ConfigureAwait(false);

                var buffer = result.Buffer;
                while (!Deserializer.Deserialize(in buffer, out read, out message))
                {
                    // This case means we read a partial message, so try to read the rest
                    if (!result.IsCompleted)
                    {
                        duplexMessageStream.AdvanceReaderTo(read, result.Buffer.End);
                        ReadStats.IncrBytesRead(result.Buffer.Length);
                        result = await duplexMessageStream.ReadAsync(closeToken).ConfigureAwait(false);

                        buffer = result.Buffer;
                    }
                    // We didn't have enough data in the buffer, and the reader is closed so we can't read anymore, so mark it as a partial message.
                    else
                    {
                        partialMessage = true;
                        break;
                    }
                }

                // Track the time it took to parse
                DateTime parsedTimeUtc = DateTime.UtcNow;

                if (!partialMessage)
                {
                    // not sure how expensive this is
                    var slicedBuffer = result.Buffer.Slice(result.Buffer.Start, read);

                    ReadStats.IncMessagesRead();
                    ReadStats.IncrBytesRead(slicedBuffer.Length);

                    try
                    {
                        ReadStats.IncMessagesIncomingBufferProcessing(1);
                        await ProcessIncomingBufferAsync(message, slicedBuffer).ConfigureAwait(false);

                        ReadStats.DecMessagesIncomingBufferProcessing(1);
                    }
                    catch (Exception ex)
                    {
                        ReadStats.DecMessagesIncomingBufferProcessing(1);
                        Logger?.LogError(ex, "Error processing incoming message buffer.");
                    }
                }

                if (!partialMessage)
                {
                    duplexMessageStream.AdvanceReaderTo(read);
                }

                DateTime parsedTime = DateTime.UtcNow;
                return(new MessageReadResult <T>
                {
                    // if the stream is completed, we can still try to read more messages, so we use the partialMessage field to indicate that.
                    IsCompleted = result.IsCompleted && partialMessage,
                    Error = false,
                    Exception = null,
                    Result = message,
                    ReadResult = !partialMessage,
                    ReceivedTimeUtc = timeReceived,
                    ParsedTimeUtc = parsedTimeUtc
                });
            }
            catch (Exception ex)
            {
                Logger?.LogError(ex, "Error reading message from duplex message stream.");

                return(new MessageReadResult <T>
                {
                    IsCompleted = duplexMessageStream.ReadCompleted,
                    Error = true,
                    Exception = ex,
                    Result = default,