public static async Task CopyToUntilCanceledOrCompletedAsync(this PipeReader reader, PipeWriter writer, CancellationToken cancel) { using var cancelRegistration = cancel.Register(delegate { // If we get canceled, indicate operation cancellation on both pipes to break out of the loop. // The purpose of this here is to avoid throwing exceptions for cancellation, instead using the graceful signal. // Just because exceptions cost extra CPU time that we want to avoid when handling load spikes (such as mass disconnects). reader.CancelPendingRead(); writer.CancelPendingFlush(); }); // We copy until we encounter either a read cancellation (upstream reached end of stream) or a write // completion (downstream reached end of stream) or a write cancellation (downstream requested graceful stop). while (true) { var readResult = await reader.ReadAsync(CancellationToken.None); if (readResult.IsCanceled) { break; } try { if (!readResult.Buffer.IsEmpty) { foreach (var segment in readResult.Buffer) { var memory = writer.GetMemory(segment.Length); segment.CopyTo(memory); writer.Advance(segment.Length); } var flushResult = await writer.FlushAsync(CancellationToken.None); if (flushResult.IsCanceled || flushResult.IsCompleted) { break; } } if (readResult.IsCompleted) { break; } } finally { reader.AdvanceTo(readResult.Buffer.End); } } }
public async Task SyncReadAsyncWithCancellationToken() { PipeWriter writer = _pipe.Writer; PipeReader reader = _pipe.Reader; for (int i = 0; i < InnerIterationCount; i++) { ReadResult result = await reader.ReadAsync(_cts.Token); reader.AdvanceTo(result.Buffer.Start); } }
private static async ValueTask <TResult> ReadAsync <TResult, TParser>(this PipeReader reader, TParser parser, CancellationToken token) where TParser : struct, IBufferReader <TResult> { for (SequencePosition consumed; parser.RemainingBytes > 0; reader.AdvanceTo(consumed)) { var readResult = await reader.ReadAsync(token).ConfigureAwait(false); readResult.ThrowIfCancellationRequested(token); parser.Append <TResult, TParser>(readResult.Buffer, out consumed); } return(parser.Complete()); }
public static async Task <byte[]> ReadAsync(this PipeReader pipeReader, int numBytes) { while (true) { var result = await pipeReader.ReadAsync(); if (result.Buffer.Length < numBytes) { pipeReader.AdvanceTo(result.Buffer.Start, result.Buffer.End); continue; } var buffer = result.Buffer.Slice(0, numBytes); var bytes = buffer.ToArray(); pipeReader.AdvanceTo(buffer.End); return(bytes); } }
protected async ValueTask <JsonTokenType> ReadNextTokenAsync(PipeReader pipe, JsonReaderState state, CancellationToken cancellationToken) { bool ForwardException(PipeReader pipe, Exception e) { pipe.Complete(e); return(false); } if (pipe == null) { throw new ArgumentNullException(nameof(pipe)); } try { while (true) { if (!pipe.TryRead(out ReadResult readResult)) { readResult = await pipe.ReadAsync(cancellationToken); } if (readResult.IsCanceled) { throw new OperationCanceledException(); } JsonTokenType IsReaderReady(ReadResult readResult, JsonReaderState state) { var reader = new Utf8JsonReader(readResult.Buffer, readResult.IsCompleted, state); var readerReady = reader.Read(); return(readerReady ? reader.TokenType : JsonTokenType.None); } var token = IsReaderReady(readResult, state); if (token == JsonTokenType.None && readResult.IsCompleted) { pipe.Complete(); return(EndOfDocument); } pipe.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End); if (token != JsonTokenType.None) { return(token); } } } catch (Exception e) when(ForwardException(pipe, e)) { throw; } }
/// <inheritdoc/> public async Task RunAsync( CancellationToken cancellationToken = default) { try { FlushResult flushResult = default; ReadResult readResult = default; while (!flushResult.IsCompleted) { readResult = await _input.ReadAsync(cancellationToken); var buffer = readResult.Buffer; if (buffer.IsEmpty && readResult.IsCompleted) { return; } while (TryHandleElement(ref buffer, out var status)) { if (status == EbmlHandleStatus.NewBlock && !TryWriteBlock(_bestAudioTrack, _outputPipe.Writer, _state.BlockData)) { return; } if (status == EbmlHandleStatus.UnsupportedFile || status == EbmlHandleStatus.NoMoreData) { return; } if (status == EbmlHandleStatus.MissingData) { break; } } flushResult = await _outputPipe.Writer.FlushAsync( cancellationToken); _input.AdvanceTo(buffer.Start, buffer.End); } } finally { _ = await _outputPipe.Writer.FlushAsync(cancellationToken); await _input.CompleteAsync(); await _outputPipe.Writer.CompleteAsync(); }
private async Task <bool> ReceiveHandshakeResponseAsync(PipeReader input, CancellationToken token) { while (true) { var result = await input.ReadAsync(token); var buffer = result.Buffer; var consumed = buffer.Start; var examined = buffer.End; try { if (result.IsCanceled) { throw new InvalidOperationException("Connection cancelled before handshake complete."); } if (!buffer.IsEmpty) { if (ServiceProtocol.TryParseMessage(ref buffer, out var message)) { consumed = buffer.Start; examined = consumed; if (!(message is HandshakeResponseMessage handshakeResponse)) { throw new InvalidDataException( $"{message.GetType().Name} received when waiting for handshake response."); } if (string.IsNullOrEmpty(handshakeResponse.ErrorMessage)) { return(true); } // Handshake error. Will stop reconnect. Log.HandshakeError(_logger, handshakeResponse.ErrorMessage); return(false); } } if (result.IsCompleted) { // Not enough data, and we won't be getting any more data. throw new InvalidOperationException("Service disconnected before sending a handshake response."); } } finally { input.AdvanceTo(consumed, examined); } } }
private async Task ReceiveLoop() { try { while (!_cancelTokenSource.IsCancellationRequested) { var result = await _pipeReader.ReadAsync(_cancelTokenSource.Token); var buffer = result.Buffer; var readLength = 0L; try { if (0 < buffer.Length) { readLength = onReceived?.Invoke(ref buffer) ?? buffer.Length; } if (result.IsCanceled) { readLength = buffer.Length; break; } if (result.IsCompleted) { readLength = buffer.Length; break; } } catch (Exception ex) { readLength = buffer.Length; onError?.Invoke(ex); break; } finally { _pipeReader.AdvanceTo(buffer.GetPosition(readLength)); } } } catch (OperationCanceledException) { // cancel~ } finally { await _pipeReader.CompleteAsync(); } }
public async Task <Handshake> GetHandshakeMessage(PipeReader input) { ReadResult readAsync = await input.ReadAsync().ConfigureAwait(false); if (readAsync.Buffer.Length >= FrameHeaderSize) { ReadOnlySequence <byte> handshakeBytes = readAsync.Buffer.Slice(0, FrameHeaderSize); ArraySegment <byte> arraySegment = handshakeBytes.ToArraySegment(); if (Handshake.TryParse(arraySegment, out Handshake result)) { input.AdvanceTo(readAsync.Buffer.GetPosition(FrameHeaderSize)); return(result); } } input.AdvanceTo(readAsync.Buffer.GetPosition(0)); return(null); }
public async ValueTask <byte[]> ReadAsync(CancellationToken cancellationToken = default) { var result = await _reader.ReadAsync(cancellationToken).ConfigureAwait(false); var buffer = result.Buffer; try { return(buffer.ToArray()); } finally { _reader.AdvanceTo(buffer.End); } }
// fast path - attempt to consume metadata synchronously private bool TryConsume() { if (!reader.TryReadBlock(LogEntryMetadata.Size, out var result) || result.IsCanceled) { return(false); } metadata = new(result.Buffer, out var metadataEnd); reader.AdvanceTo(metadataEnd); consumed = false; return(true); }
protected async Task ReadPipeAsync(PipeReader reader) { var cts = _cts; while (!cts.IsCancellationRequested) { var result = await reader.ReadAsync(cts.Token); var buffer = result.Buffer; SequencePosition consumed = buffer.Start; SequencePosition examined = buffer.End; try { if (result.IsCanceled) { break; } var completed = result.IsCompleted; if (buffer.Length > 0) { if (!ReaderBuffer(ref buffer, out consumed, out examined)) { completed = true; break; } } if (completed) { break; } } catch (Exception e) { OnError("Protocol error", e); // close the connection if get a protocol error Close(); break; } finally { reader.AdvanceTo(consumed, examined); } } reader.Complete(); WriteEOFPackage(); }
/// <summary> /// Read a single message from the pipe reader. Ensure the reader completes without additional data. /// </summary> /// <param name="input">The request pipe reader.</param> /// <returns>Complete message data.</returns> public static async ValueTask <byte[]> ReadSingleMessageAsync(this PipeReader input) { byte[] completeMessageData = null; while (true) { var result = await input.ReadAsync(); var buffer = result.Buffer; try { if (result.IsCanceled) { throw new InvalidDataException("Incoming message cancelled."); } if (!buffer.IsEmpty) { if (completeMessageData != null) { throw new InvalidDataException("Additional data after the message received."); } if (TryReadMessage(ref buffer, out var data)) { // Store the message data // Need to verify the request completes with no additional data completeMessageData = data; } } if (result.IsCompleted) { if (completeMessageData != null) { // Finished and the complete message has arrived return(completeMessageData); } throw new InvalidDataException("Incomplete message."); } } finally { // The buffer was sliced up to where it was consumed, so we can just advance to the start. // We mark examined as buffer.End so that if we didn't receive a full frame, we'll wait for more data // before yielding the read again. input.AdvanceTo(buffer.Start, buffer.End); } } }
public static async Task WriteFromBase64Urlsafe( this Stream stream, PipeReader base64Pipe, CancellationToken cancelToken = default) { if (stream is null) { throw new ArgumentNullException(nameof(stream)); } if (base64Pipe is null) { throw new ArgumentNullException(nameof(base64Pipe)); } try { using (var base64Buffer = bytesPool.Rent()) { Memory <byte> base64Memory = base64Buffer.Memory; int base64Remaining = 0; while (true) { ReadResult readResult = await base64Pipe .ReadAsync(cancelToken) .ConfigureAwait(false); (base64Remaining, _) = await stream .WritePartialFromBase64Urlsafe(readResult.Buffer, base64Memory, base64Remaining, cancelToken) .ConfigureAwait(false); base64Pipe.AdvanceTo(readResult.Buffer.End); if (readResult.IsCompleted) { break; } } base64Memory = base64Memory.Slice(0, base64Remaining); await stream.WriteFinalFromBase64Urlsafe(base64Memory, cancelToken) .ConfigureAwait(false); } await stream.FlushAsync(cancelToken).ConfigureAwait(false); base64Pipe.Complete(); } catch (Exception e) { base64Pipe.Complete(e); throw; } }
private async Task ConsumeLoop(PipeReader audioData) { Debug.Assert(_cts is not null); SpinWait spinner = new(); while (!_cts.IsCancellationRequested) { spinner.SpinOnce(); ReadResult readResult = await audioData.ReadAsync(); audioData.AdvanceTo(readResult.Buffer.End); } }
private async Task ProcessLogs(PipeReader reader, CancellationToken cancellationToken, bool stdOut = true) { while (true) { var result = await reader.ReadAsync(cancellationToken); try { var position = result.Buffer.PositionOf((byte)'\r'); if (position != null) { var line = GetString(result.Buffer.Slice(0, position.Value)); if (stdOut) { _logger.LogDebug("Ffmpeg out: {0}", line); } else { _logger.LogError("Ffmpeg err: {0}", line); } reader.AdvanceTo(position.Value); } else { reader.AdvanceTo(result.Buffer.GetPosition(0)); } } catch (Exception ex) { _logger.LogError(ex, "Failed to read from pipe"); break; } if (result.IsCompleted) { break; } } }
public async Task DrainReaderTillCompletedAsync(PipeReader reader) { while (true) { var readResult = await reader.ReadAsync(this.TimeoutToken); reader.AdvanceTo(readResult.Buffer.End); if (readResult.IsCompleted) { break; } } }
/// <summary> /// Parses an HTTP form body. /// </summary> /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param> /// <returns>The collection containing the parsed HTTP form body.</returns> public async Task <Dictionary <string, StringValues> > ReadFormAsync(CancellationToken cancellationToken = default) { KeyValueAccumulator accumulator = default; while (true) { var readResult = await _pipeReader.ReadAsync(cancellationToken); var buffer = readResult.Buffer; if (!buffer.IsEmpty) { try { ParseFormValues(ref buffer, ref accumulator, readResult.IsCompleted); } catch { _pipeReader.AdvanceTo(buffer.Start); throw; } } if (readResult.IsCompleted) { _pipeReader.AdvanceTo(buffer.End); if (!buffer.IsEmpty) { throw new InvalidOperationException("End of body before form was fully parsed."); } break; } _pipeReader.AdvanceTo(buffer.Start, buffer.End); } return(accumulator.GetResults()); }
/// <summary> /// Asynchronously reads to the end of the current System.IO.Pipelines.PipeReader. /// Requires a call to BodyReader.Advance after use ReadResult.Buffer /// </summary> /// <param name="pipeReader"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static async ValueTask <Memory <byte> > ReadToEndAsync(this PipeReader pipeReader, CancellationToken cancellationToken = default) { while (true) { // Calling PipeReader.ReadAsync() Does not mean it reads the entire stream: //// 1、It Start reading the stream from PipeReader.InnerStream.Position //// 2. Length of First buffer to read = PipeReader._readHead'length = PipeReader.InnerStream.Length - PipeReader.InnerStream.Position. ////// If PipeReader._readHead'length is zero, it will read the stream until it ends var readResult = await pipeReader.ReadAsync(cancellationToken); var buffer = readResult.Buffer; if (readResult.IsCompleted) { var newbuffer = new byte[buffer.Length]; buffer.CopyTo(newbuffer); pipeReader.AdvanceTo(buffer.Start); return(newbuffer.AsMemory()); } pipeReader.AdvanceTo(buffer.Start, buffer.End); } }
// Reverted. Recommend formatting for table -------------------------------------- #region snippet async ValueTask <Message?> ReadSingleMessageAsync(PipeReader reader, CancellationToken cancellationToken = default) { while (true) { ReadResult result = await reader.ReadAsync(cancellationToken); ReadOnlySequence <byte> buffer = result.Buffer; // In the event that no message is parsed successfully, mark consumed // as nothing and examined as the entire buffer. SequencePosition consumed = buffer.Start; SequencePosition examined = buffer.End; try { if (TryParseLines(ref buffer, out Message message)) { // A single message was successfully parsed so mark the start of the // parsed buffer as consumed. TryParseLines trims the buffer to // point to the data after the message was parsed. consumed = buffer.Start; // Examined is marked the same as consumed here, so the next call // to ReadSingleMessageAsync will process the next message if there's // one. examined = consumed; return(message); } // There's no more data to be processed. if (result.IsCompleted) { if (buffer.Length > 0) { // The message is incomplete and there's no more data to process. throw new InvalidDataException("Incomplete message."); } break; } } finally { reader.AdvanceTo(consumed, examined); } } return(null); }
/// <inheritdoc /> protected override async Task ExecuteAsync(CancellationToken cancellationToken) { while (true) { Logger?.LogTrace("Start reading from pipe"); var readResult = await _reader.ReadAsync(cancellationToken) .ConfigureAwait(false); var buffer = readResult.Buffer; var position = buffer.Start; while (buffer.TryGet(ref position, out var memory)) { Logger?.LogTrace("Pass through of {numBytes} bytes", memory.Length); // Don't use the cancellation token source from above. Otherwise // data might be lost. await _writer.WriteAsync(memory, CancellationToken.None) .ConfigureAwait(false); if (readResult.IsCanceled || readResult.IsCompleted) { break; } } _reader.AdvanceTo(buffer.End); await _writer.FlushAsync(CancellationToken.None) .ConfigureAwait(false); if (readResult.IsCanceled || readResult.IsCompleted) { Logger?.LogTrace("Cancelled={cancelled} or completed={completed}", readResult.IsCanceled, readResult.IsCompleted); break; } } }
internal static async ValueTask <(bool isCancelled, bool isCompleted)> ParseLineAsync(PipeReader reader, Memory <string?> lineBuffer, bool isHeader = false, byte fieldDelimiter = 44) { int index = 0; var readResult = await reader.ReadAsync(); while (true) { if (readResult.IsCanceled) { break; } var buffer = readResult.Buffer; var(isEol, eolPosition) = CsvParser.FindEol(buffer); if (readResult.IsCompleted && !isEol) { isEol = true; } var recordBuffer = buffer.Slice(buffer.Start, eolPosition ?? buffer.End); ParseLine(ref recordBuffer, lineBuffer.Span, ref index, isEol, isHeader, fieldDelimiter); if (isEol && recordBuffer.IsEmpty) { var advance = eolPosition is null ? buffer.End : buffer.GetPosition(1, eolPosition.Value); reader.AdvanceTo(advance); break; } reader.AdvanceTo(recordBuffer.Start, recordBuffer.End); readResult = await reader.ReadAsync(); } return(readResult.IsCanceled, readResult.IsCompleted); }
private async Task SendingPipeSendAsync(PipeReader reader) { var senderSocketLock = new AsyncLock(); while (_active) { try { var result = await reader.ReadAsync(_linkedToken); if (result.IsCanceled) { break; } var sequence = result.Buffer; if (!sequence.IsEmpty) { using (await senderSocketLock.LockAsync()) { var bytesCount = await _socket.SendBuffersAsync(sequence, _linkedToken); reader.AdvanceTo(sequence.End); if (bytesCount < 0) { _localSource.Cancel(false); } } } if (_stopping) { _localSource.Cancel(false); } if (result.IsCompleted) { break; } } catch (OperationCanceledException oce) { reader.Complete(oce); return; } catch (SocketException se) when(se.ErrorCode.In(10054, 104)) { _localSource.Cancel(false); reader.Complete(se); return; } catch (Exception e) { _logger.LogError(e, "While sending bytes in the socket"); reader.Complete(e); return; } } reader.Complete(); }
bool TryReadLine(ref ReadOnlySequence <byte> buffer, out ReadOnlySequence <byte> line) { SequencePosition?position = buffer.PositionOf((byte)'\n'); if (position == null) { line = default; return(false); } line = buffer.Slice(0, position.Value); _reader.AdvanceTo(position.Value); buffer = buffer.Slice(buffer.GetPosition(1, position.Value)); return(true); }
async Task SendAsync() { PipeReader reader = _requestPipe.Reader; try { while (true) { ReadResult result = await reader.ReadAsync(); ReadOnlySequence <byte> buffer = result.Buffer; try { if (!buffer.IsEmpty) { for (SequencePosition position = buffer.Start; buffer.TryGet(ref position, out ReadOnlyMemory <byte> segment);) { if (Log != null && Log.Switch.ShouldTrace(TraceEventType.Verbose)) { string data = Encodings.Utf8.ToString(segment.Span); if (!string.IsNullOrWhiteSpace(data)) { Log.TraceInformation(data); } } await WriteToSocketAsync(segment).ConfigureAwait(false); } } else if (result.IsCompleted) { break; } } finally { reader.AdvanceTo(buffer.End); } } } catch (Exception e) { Log.TraceEvent(TraceEventType.Error, 0, e.ToString()); } finally { reader.Complete(); } }
protected async Task ReadPipeAsync(PipeReader reader) { while (true) { var result = await reader.ReadAsync(); var buffer = result.Buffer; SequencePosition consumed = buffer.Start; SequencePosition examined = buffer.End; try { if (result.IsCanceled) { break; } var completed = result.IsCompleted; while (true) { var package = ReaderBuffer(buffer, out consumed, out examined); if (package != null) { await OnPackageReceived(package); } if (examined.Equals(buffer.End)) { break; } buffer = buffer.Slice(examined); } if (completed) { break; } } finally { reader.AdvanceTo(consumed, examined); } } reader.Complete(); }
public static async Task ReceiveHandshakeRequestAsync(PipeReader input) { using (var cts = new CancellationTokenSource(DefaultHandshakeTimeout)) { while (true) { var result = await input.ReadAsync(cts.Token); var buffer = result.Buffer; var consumed = buffer.Start; var examined = buffer.End; try { if (!buffer.IsEmpty) { if (ServiceProtocol.TryParseMessage(ref buffer, out var message)) { consumed = buffer.Start; examined = consumed; if (!(message is HandshakeRequestMessage handshakeRequest)) { throw new InvalidDataException( $"{message.GetType().Name} received when waiting for handshake request."); } if (handshakeRequest.Version != ServiceProtocol.Version) { throw new InvalidDataException("Protocol version not supported."); } break; } } if (result.IsCompleted) { // Not enough data, and we won't be getting any more data. throw new InvalidOperationException( "Service connectioned disconnected before sending a handshake request"); } } finally { input.AdvanceTo(consumed, examined); } } } }
static async Task ReadBlockHashPipeAsync(PipeReader reader) { // Read Bitcoin block ids from a PipeReader while (_zmqRunning) { var rr = await reader.ReadAsync(); var buf = rr.Buffer; var blockId = new KzUInt256(); buf.ToSpan().CopyTo(blockId.Span); reader.AdvanceTo(buf.GetPosition(32)); KzH.WriteLine($"BlockId parsed id={blockId.ToHex()}"); } }
/// <summary> /// Receive multiple messages from a pipe /// </summary> public static async IAsyncEnumerable <T> ReceiveAsync <T>(PipeReader source, MessagePipeOptions options = default) { if (source == null) { throw new ArgumentNullException(nameof(source)); } options = options.Normalize(); while (true) { // obtain the next buffer options.OnLog("ReceiveAsync obtaining buffer..."); if (!source.TryRead(out var result)) { result = await source.ReadAsync(options.CancellationToken).ConfigureAwait(false); } if (result.IsCanceled) { ThrowCancelled(); } // consume the buffer var buffer = result.Buffer; options.OnLog($"ReceiveAsync got {buffer.Length} bytes"); int processed = 0; while (options.TryRead <T>(ref buffer, out var item)) { processed++; yield return(item); } if (processed == 0 && result.IsCompleted) // check for termination { // we have everything, and there will never be any more; was it clean? if (!buffer.IsEmpty) { ThrowInputCompletedWithPartialPayload(); } break; } // mark what we consumed (the "ref buffer" means we've sliced it already) source.AdvanceTo(buffer.Start, buffer.End); } if (options.MarkComplete) { await source.CompleteAsync().ConfigureAwait(false); } options.OnLog("ReceiveAsync completed successfully"); }
internal override async ValueTask <RawResult> Process() { var firstChar = await ReadByte(); PipeReader.AdvanceTo(ReadResult.Buffer.Start, ReadResult.Buffer.Slice(1).Start); if (firstChar == ByteConstants.Dash) { var line = await ReadLine(); var redisResponse = line.AsString(); PipeReader.AdvanceTo(line.End); throw new RedisFailedCommandException(redisResponse, RedisClient.LastCommand); } object result; if (firstChar == ByteConstants.Asterix) { var processor = RedisClient.ArrayResultProcessor; processor.SetMembers(RedisClient, PipeReader, ReadResult, CancellationToken); result = await processor.Process(); } else if (firstChar == ByteConstants.Plus) { var processor = RedisClient.WordResultProcessor; processor.SetMembers(RedisClient, PipeReader, ReadResult, CancellationToken); result = await processor.Process(); } else if (firstChar == ByteConstants.Colon) { var processor = RedisClient.IntegerResultProcessor; processor.SetMembers(RedisClient, PipeReader, ReadResult, CancellationToken); result = await processor.Process(); } else if (firstChar == ByteConstants.Dollar) { var processor = RedisClient.DataResultProcessor; processor.SetMembers(RedisClient, PipeReader, ReadResult, CancellationToken); result = await processor.Process(); } else { var processor = RedisClient.EmptyResultProcessor; processor.SetMembers(RedisClient, PipeReader, ReadResult, CancellationToken); result = await processor.Process(); } return(new RawResult(result)); }