public static int Write <T>( this PipeWriter writer, T writable) where T : IWritable { int size = writable.Size; var buffer = writer.GetSpan(size); writable.WriteTo(buffer); writer.Advance(size); return(size); }
protected virtual async Task FillPipeAsync(PipeWriter writer) { var options = Options; var cts = _cts; while (!cts.IsCancellationRequested) { try { var bufferSize = options.ReceiveBufferSize; var maxPackageLength = options.MaxPackageLength; if (bufferSize <= 0) { bufferSize = 1024 * 4; //4k } var memory = writer.GetMemory(bufferSize); var bytesRead = await FillPipeWithDataAsync(memory, cts.Token); if (bytesRead == 0) { break; } LastActiveTime = DateTimeOffset.Now; // Tell the PipeWriter how much was read writer.Advance(bytesRead); } catch (Exception e) { if (!IsIgnorableException(e)) { OnError("Exception happened in ReceiveAsync", e); } break; } // Make the data available to the PipeReader var result = await writer.FlushAsync(); if (result.IsCompleted) { break; } } // Signal to the reader that we're done writing writer.Complete(); Out.Writer.Complete();// TODO: should complete the output right now? }
private async Task FillPipeAsync(PipeWriter writer) { while (!IsClosed) { try { var bufferSize = options.ReceiveBufferSize; var maxPackageLength = options.MaxPackageLength; if (maxPackageLength > 0) { bufferSize = Math.Min(bufferSize, maxPackageLength); } var memory = writer.GetMemory(bufferSize); var read = await ReceiveAsync(memory); if (read == 0) { //continue; break; } writer.Advance(read); } catch (SocketException socketException) { if (socketException.ErrorCode == 10054 || socketException.ErrorCode == 995) { logger.LogDebug("channel close"); } else { logger.LogError(socketException, "Exception happened in ReceiveAsync"); } break; } catch (Exception e) { logger.LogError(e, "Exception happened in ReceiveAsync"); break; } var result = await writer.FlushAsync(); if (result.IsCompleted) { logger.LogWarning($"completed:{result.IsCompleted}"); break; } } writer.Complete(); output.Writer.Complete(); }
private static void WriteHeader(PipeWriter pipeWriter, int length, bool compress) { var headerData = pipeWriter.GetSpan(HeaderSize); // Compression flag headerData[0] = compress ? (byte)1 : (byte)0; // Message length EncodeMessageLength(length, headerData.Slice(1)); pipeWriter.Advance(HeaderSize); }
/// <summary> /// Write to the PipeWriter /// </summary> /// <param name="writer"></param> /// <param name="frame"></param> /// <returns></returns> protected override ValueTask <FlushResult> Write(PipeWriter writer, TFrame frame) { var headerLen = GetHeaderLength(frame); var headerSpan = writer.GetSpan(headerLen); WriteHeader(headerSpan, frame); writer.Advance(headerLen); var payload = frame.Payload; return(payload.Memory.IsEmpty ? writer.FlushAsync() : writer.WriteAsync(payload.Memory)); }
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); } } }
/// <summary> /// Copies a sequence of bytes to a <see cref="PipeWriter"/>. /// </summary> /// <param name="writer">The writer to use.</param> /// <param name="sequence">The sequence to read.</param> private static void Write(this PipeWriter writer, ReadOnlySequence <byte> sequence) { Requires.NotNull(writer, nameof(writer)); foreach (ReadOnlyMemory <byte> sourceMemory in sequence) { var sourceSpan = sourceMemory.Span; var targetSpan = writer.GetSpan(sourceSpan.Length); sourceSpan.CopyTo(targetSpan); writer.Advance(sourceSpan.Length); } }
private async Task FillPipeAsync(PipeWriter writer, CancellationToken token) { const int minimumBufferSize = 1024 * 4; try { while (!token.IsCancellationRequested) { token.ThrowIfCancellationRequested(); var memory = writer.GetMemory(minimumBufferSize); try { var receiveResult = await _userSocket.ReceiveAsync(memory, token).ConfigureAwait(false); if (_userSocket.CloseStatus.HasValue) { break; } writer.Advance(receiveResult.Count); if (receiveResult.EndOfMessage) { var result = await writer.FlushAsync(token).ConfigureAwait(false); if (result.IsCompleted) { break; } } } catch (Exception ex) { _logger.LogError(ex, "Failed to get data stream"); await _userSocket.CloseAsync(WebSocketCloseStatus.InternalServerError, "Internal server error, contact administrator", _cancellationTokenSource.Token).ConfigureAwait(false); break; } } await _userSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Socket was closed", _cancellationTokenSource.Token).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "Internal sever error"); await _userSocket.CloseAsync(WebSocketCloseStatus.InternalServerError, "Internal server error, contact administrator", _cancellationTokenSource.Token).ConfigureAwait(false); } finally { writer.Complete(); } }
public void NothingWrittenToStreamUnlessFlushed() { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); var stream = new MemoryStream(); PipeWriter writer = PipeWriter.Create(stream); bytes.AsSpan().CopyTo(writer.GetSpan(bytes.Length)); writer.Advance(bytes.Length); Assert.Equal(0, stream.Length); writer.Complete(); }
private static async Task WriteUrlAsync(PipeWriter pipeWriter, InputModel model, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { throw new InvalidOperationException("Cannot write message after request is complete."); } var bytesWritten = BuildUrl(pipeWriter.GetMemory().Span, model); pipeWriter.Advance(bytesWritten); await pipeWriter.FlushAsync(cancellationToken); }
// Reverted. Recommend formatting for table -------------------------------------- #region snippet async Task WriteHelloAsync(PipeWriter writer, CancellationToken cancellationToken = default) { // Request at least 5 bytes from the PipeWriter. Memory <byte> memory = writer.GetMemory(5); // Write directly into the buffer. int written = Encoding.ASCII.GetBytes("Hello".AsSpan(), memory.Span); // Tell the writer how many bytes were written. writer.Advance(written); await writer.FlushAsync(cancellationToken); }
public static int Write <T, Options>( this PipeWriter writer, T writable, Options options) where T : IWritable <Options> { int size = writable.Size(options); var buffer = writer.GetSpan(size); writable.WriteTo(buffer, options); writer.Advance(size); return(size); }
private async Task WriteMessageDelimiterAsync( CancellationToken cancellationToken) { Memory <byte> memory = _writer.GetMemory(1); memory.Span[0] = Subscription._delimiter; _writer.Advance(1); await _writer .FlushAsync(cancellationToken) .ConfigureAwait(false); }
public async Task ReceiveAsync( PipeWriter writer, CancellationToken cancellationToken = default) { if (IsClosed) { return; } try { WebSocketReceiveResult?socketResult = null; do { Memory <byte> memory = writer.GetMemory(_maxMessageSize); if (MemoryMarshal.TryGetArray(memory, out ArraySegment <byte> buffer)) { try { socketResult = await _socketClient.Socket .ReceiveAsync(buffer, cancellationToken) .ConfigureAwait(false); if (socketResult.Count == 0) { break; } writer.Advance(socketResult.Count); } catch { break; } FlushResult result = await writer .FlushAsync(cancellationToken) .ConfigureAwait(false); if (result.IsCompleted) { break; } } } while (socketResult == null || !socketResult.EndOfMessage); } catch (ObjectDisposedException) { // we will just stop receiving } }
private async void FillPipeAsync(Stream stream, PipeWriter writer, CancellationToken token) { const int bufferSize = 512; #if NETSTANDARD2_0 var buffer = ArrayPool <byte> .Shared.Rent(bufferSize); #endif try { while (true) { #if NETSTANDARD2_0 int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token).ConfigureAwait(false); if (bytesRead == 0) { break; } var result = await writer.WriteAsync(new ReadOnlyMemory <byte>(buffer, 0, bytesRead), token).ConfigureAwait(false); #else var buffer = writer.GetMemory(bufferSize); int bytesRead = await stream.ReadAsync(buffer, token).ConfigureAwait(false); if (bytesRead == 0) { break; } writer.Advance(bytesRead); var result = await writer.FlushAsync(token).ConfigureAwait(false); #endif if (result.IsCompleted) { break; } } writer.Complete(); } catch (Exception ex) { writer.Complete(ex); } #if NETSTANDARD2_0 finally { ArrayPool <byte> .Shared.Return(buffer); } #endif }
public async Task ReceiveAsync( PipeWriter writer, CancellationToken cancellationToken) { WebSocket?webSocket = _webSocket; if (_disposed || webSocket == null) { return; } try { WebSocketReceiveResult?socketResult = null; do { Memory <byte> memory = writer.GetMemory(_maxMessageSize); bool success = MemoryMarshal.TryGetArray(memory, out ArraySegment <byte> buffer); if (success) { try { socketResult = await webSocket.ReceiveAsync(buffer, cancellationToken); if (socketResult.Count == 0) { break; } writer.Advance(socketResult.Count); } catch { break; } FlushResult result = await writer.FlushAsync(cancellationToken); if (result.IsCompleted) { break; } } } while (socketResult == null || !socketResult.EndOfMessage); } catch (ObjectDisposedException) { // we will just stop receiving } }
protected virtual async Task FillPipeAsync(PipeWriter writer) { var options = Options; while (true) { try { var bufferSize = options.ReceiveBufferSize; var maxPackageLength = options.MaxPackageLength; if (maxPackageLength > 0) { bufferSize = Math.Min(bufferSize, maxPackageLength); } var memory = writer.GetMemory(bufferSize); var bytesRead = await FillPipeWithDataAsync(memory); if (bytesRead == 0) { break; } // Tell the PipeWriter how much was read writer.Advance(bytesRead); } catch (Exception e) { if (!IsIgnorableException(e)) { Logger.LogError(e, "Exception happened in ReceiveAsync"); } break; } // Make the data available to the PipeReader var result = await writer.FlushAsync(); if (result.IsCompleted) { break; } } // Signal to the reader that we're done writing writer.Complete(); Out.Writer.Complete();// TODO: should complete the output right now? }
private int EncodeFragment(PipeWriter writer, OpCode opCode, int expectedHeadLength, ReadOnlySpan <char> text, bool isFinal) { var head = writer.GetSpan(expectedHeadLength); var opCodeFlag = (byte)opCode; if (isFinal) { opCodeFlag = (byte)(opCodeFlag | 0x80); } head[0] = opCodeFlag; writer.Advance(expectedHeadLength); var encoder = _textEncoding.GetEncoder(); var completed = false; var totalBytes = 0; while (!completed) { var span = writer.GetSpan(); encoder.Convert(text, span, false, out int charsUsed, out int bytesUsed, out completed); if (charsUsed > 0) { text = text.Slice(charsUsed); } totalBytes += bytesUsed; writer.Advance(bytesUsed); } WriteLength(ref head, totalBytes); writer.FlushAsync().GetAwaiter().GetResult(); return(totalBytes + expectedHeadLength); }
private static async Task WriteMessageDelimiterAsync( this PipeWriter writer, CancellationToken cancellationToken) { Memory <byte> memory = writer.GetMemory(1); memory.Span[0] = MessageProcessor.Delimiter; writer.Advance(1); await writer .FlushAsync(cancellationToken) .ConfigureAwait(false); }
async ValueTask WriteSomeDataAsync(PipeWriter writer) { // use an oversized size guess Memory <byte> workspace = writer.GetMemory(20); // write the data to the workspace int bytes = Encoding.ASCII.GetBytes( "hello, world!", workspace.Span); // tell the pipe how much of the workspace // we actually want to commit writer.Advance(bytes); // this is **not** the same as Stream.Flush! await writer.FlushAsync(); }
/// <inheritdoc/> protected override void EncodeObject(PipeWriter writer) { var size = GetSizeInBytes(); var buffer = writer.GetSpan(size).Slice(0, size); buffer[0] = (byte)'i'; buffer = buffer.Slice(1); Encoding.ASCII.GetBytes(Value.ToString().AsSpan(), buffer); buffer[buffer.Length - 1] = (byte)'e'; writer.Advance(size); }
private async Task WriteToConnection( PipeWriter output, CancellationToken token) { try { var reader = _writeChannel.Reader; while (true) { if (!await reader.WaitToReadAsync(token)) { break; } if (!reader.TryRead(out var message)) { continue; } var count = WriteOperationMessage(message, output); output.Advance(count); // apply back-pressure etc var flush = await output.FlushAsync(token); if (flush.IsCanceled || flush.IsCompleted) { break; } } // Manifest any errors in the completion task await reader.Completion; } catch (Exception ex) { if (token.IsCancellationRequested) { return; } output.Complete(ex); throw; } finally { // This will safely no-op if the catch block above ran. output.Complete(); } }
private async Task FillPipeAsync(Stream stream, PipeWriter writer, CancellationToken cancellationToken = default) { const Int32 minimumBufferSize = 512; while (true) { if (cancellationToken.IsCancellationRequested) { _exitReason = ExitReason.CancellationRequested; break; } try { // Allocate at least 512 bytes from the PipeWriter. NOTE: NMEA sentences must be less than 80 bytes. var memory = writer.GetMemory(minimumBufferSize); var bytesRead = await stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false); BytesReceived += bytesRead; if (bytesRead == 0) { _logger.LogTrace("FillPipeAsync: Stream Ended"); _exitReason = ExitReason.StreamEnded; break; } // Tell the PipeWriter how much was read from the Stream writer.Advance(bytesRead); // Make the data available to the PipeReader var result = await writer.FlushAsync(cancellationToken).ConfigureAwait(false); if (result.IsCompleted) { _logger.LogTrace("FillPipeAsync: Reader is Completed"); break; } } catch (OperationCanceledException) { _exitReason = ExitReason.CancellationRequested; break; } } // Tell the PipeReader that there's no more data coming writer.Complete(); }
private async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken) { const int minimumBufferSize = 512; while (true) { // 从PipeWriter至少分配512字节 var memory = writer.GetMemory(minimumBufferSize); try { var reads = await Socket.ReceiveAsync(memory, SocketFlags.None, cancellationToken); if (reads == 0) { break; } Actived = DateTimeOffset.Now; // 告诉PipeWriter从套接字读取了多少 writer.Advance(reads); } catch (SocketException exception) { LogError("[{2}] 套接字读取出现错误:{1}({0})", exception.Message, exception.SocketErrorCode, Name); if (!Socket.Connected) { await CloseAsync(); return; } } catch (Exception ex) { LogError("[{0}] {1}", Name, ex.Message); break; } // 标记数据可用,让PipeReader读取 var result = await writer.FlushAsync(cancellationToken); if (result.IsCompleted) { break; } } // 告诉PipeReader没有更多的数据 await writer.CompleteAsync(); }
internal async ValueTask OnContentAsync(FrameHeader header, ReadOnlySequence <byte> payload, CancellationToken cancellationToken) { PipeWriter writer = this.GetReceivedMessagePipeWriter(); foreach (var segment in payload) { try { var memory = writer.GetMemory(segment.Length); segment.CopyTo(memory); writer.Advance(segment.Length); } catch (InvalidOperationException) { // Someone completed the writer. return; } } if (!payload.IsEmpty && this.MultiplexingStream.TraceSource.Switch.ShouldTrace(TraceEventType.Verbose)) { this.MultiplexingStream.TraceSource.TraceData(TraceEventType.Verbose, (int)TraceEventId.FrameReceivedPayload, payload); } ValueTask <FlushResult> flushResult = writer.FlushAsync(cancellationToken); if (this.BackpressureSupportEnabled) { if (!flushResult.IsCompleted) { // The incoming data has overrun the size of the write buffer inside the PipeWriter. // This should never happen if we created the Pipe because we specify the Pause threshold to exceed the window size. // If it happens, it should be because someone specified an ExistingPipe with an inappropriately sized buffer in its PipeWriter. Assumes.True(this.existingPipeGiven == true); // Make sure this isn't an internal error this.Fault(new InvalidOperationException(Strings.ExistingPipeOutputHasPauseThresholdSetTooLow)); } } else { await flushResult.ConfigureAwait(false); } if (flushResult.IsCanceled) { // This happens when the channel is disposed (while or before flushing). Assumes.True(this.IsDisposed); writer.Complete(); } }
private async Task FillBuffer(PipeWriter writer, CancellationToken cancellationToken) { long offset = 0; while (offset < File.Size) { var pipeBuffer = writer.GetMemory(_maxSegmentSize); var segmentSize = (int)Math.Min(_maxSegmentSize, File.Size - offset); try { using var readSegmentCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); readSegmentCts.CancelAfter(_segmentFetchTimeout); var bytes = await _jsRuntime.InvokeAsync <byte[]>( InputFileInterop.ReadFileData, readSegmentCts.Token, _inputFileElement, File.Id, offset, segmentSize); if (bytes is null || bytes.Length != segmentSize) { throw new InvalidOperationException( $"A segment with size {bytes?.Length ?? 0} bytes was received, but {segmentSize} bytes were expected."); } bytes.CopyTo(pipeBuffer); writer.Advance(segmentSize); offset += segmentSize; var result = await writer.FlushAsync(cancellationToken); if (result.IsCompleted) { break; } } catch (Exception e) { await writer.CompleteAsync(e); return; } } await writer.CompleteAsync(); }
/* https://tools.ietf.org/html/rfc7540#section-4.1 +-----------------------------------------------+ | Length (24) | +---------------+---------------+---------------+ | Type (8) | Flags (8) | +-+-------------+---------------+-------------------------------+ |R| Stream Identifier (31) | +=+=============================================================+ | Frame Payload (0...) ... +---------------------------------------------------------------+ */ internal static void WriteHeader(Http2Frame frame, PipeWriter output) { var buffer = output.GetSpan(Http2FrameReader.HeaderLength); Bitshifter.WriteUInt24BigEndian(buffer, (uint)frame.PayloadLength); buffer = buffer.Slice(3); buffer[0] = (byte)frame.Type; buffer[1] = frame.Flags; buffer = buffer.Slice(2); Bitshifter.WriteUInt31BigEndian(buffer, (uint)frame.StreamId); output.Advance(Http2FrameReader.HeaderLength); }
public async Task DataWrittenOnFlushAsync() { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); var stream = new MemoryStream(); PipeWriter writer = PipeWriter.Create(stream); bytes.AsSpan().CopyTo(writer.GetSpan(bytes.Length)); writer.Advance(bytes.Length); await writer.FlushAsync(); Assert.Equal(bytes.Length, stream.Length); Assert.Equal("Hello World", Encoding.ASCII.GetString(stream.ToArray())); writer.Complete(); }
private static void WriteHeader(PipeWriter pipeWriter, int length, bool compress) { const int MessageDelimiterSize = 4; // how many bytes it takes to encode "Message-Length" const int HeaderSize = MessageDelimiterSize + 1; // message length + compression flag var headerData = pipeWriter.GetSpan(HeaderSize); // Compression flag headerData[0] = compress ? (byte)1 : (byte)0; // Message length BinaryPrimitives.WriteUInt32BigEndian(headerData.Slice(1), (uint)length); pipeWriter.Advance(HeaderSize); }
private static async Task <byte[]> Write(PipeWriter output) { var count = Random.Next(1, 1024); var input = new byte[count]; Random.NextBytes(input); var memory = output.GetMemory(count); input.CopyTo(memory); output.Advance(count); await output.FlushAsync(); return(input); }