-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
247 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
Pipelines.Extensions/WebSocketPipe/WebSocketPipeReader.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
using Microsoft; | ||
using Microsoft.VisualStudio.Threading; | ||
using System; | ||
using System.IO.Pipelines; | ||
using System.Net.WebSockets; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Pipelines.Extensions.WebSocketPipe | ||
{ | ||
internal sealed class WebSocketPipeReader : PipeReader | ||
{ | ||
public WebSocket InternalWebSocket { get; } | ||
|
||
private readonly WebSocketPipeReaderOptions _options; | ||
private readonly Pipe _pipe; | ||
private PipeWriter Writer => _pipe.Writer; | ||
private PipeReader Reader => _pipe.Reader; | ||
|
||
private readonly CancellationTokenSource _cancellationTokenSource; | ||
|
||
public WebSocketPipeReader(WebSocket webSocket, WebSocketPipeReaderOptions options) | ||
{ | ||
Requires.NotNull(webSocket, nameof(webSocket)); | ||
Requires.NotNull(options, nameof(options)); | ||
|
||
InternalWebSocket = webSocket; | ||
_options = options; | ||
_pipe = new Pipe(options.PipeOptions); | ||
_cancellationTokenSource = new CancellationTokenSource(); | ||
|
||
WrapWriterAsync(_cancellationTokenSource.Token).Forget(); | ||
} | ||
|
||
private Task WrapWriterAsync(CancellationToken cancellationToken) | ||
{ | ||
return Task.Run(async () => | ||
{ | ||
try | ||
{ | ||
while (true) | ||
{ | ||
var memory = Writer.GetMemory(_options.SizeHint); | ||
|
||
var readResult = await InternalWebSocket.ReceiveAsync(memory, cancellationToken); | ||
|
||
if (readResult.Count is 0) | ||
{ | ||
break; | ||
} | ||
|
||
Writer.Advance(readResult.Count); | ||
|
||
var flushResult = await Writer.FlushAsync(cancellationToken); | ||
if (flushResult.IsCompleted) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
await Writer.CompleteAsync(); | ||
} | ||
catch (Exception ex) | ||
{ | ||
await Writer.CompleteAsync(ex); | ||
} | ||
}, cancellationToken); | ||
} | ||
|
||
public override void AdvanceTo(SequencePosition consumed) | ||
{ | ||
Reader.AdvanceTo(consumed); | ||
} | ||
|
||
public override void AdvanceTo(SequencePosition consumed, SequencePosition examined) | ||
{ | ||
Reader.AdvanceTo(consumed, examined); | ||
} | ||
|
||
public override void CancelPendingRead() | ||
{ | ||
Reader.CancelPendingRead(); | ||
} | ||
|
||
public override void Complete(Exception? exception = null) | ||
{ | ||
_cancellationTokenSource.Cancel(); | ||
Reader.Complete(exception); | ||
} | ||
|
||
public override ValueTask<ReadResult> ReadAsync(CancellationToken cancellationToken = default) | ||
{ | ||
return Reader.ReadAsync(cancellationToken); | ||
} | ||
|
||
public override bool TryRead(out ReadResult result) | ||
{ | ||
return Reader.TryRead(out result); | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
Pipelines.Extensions/WebSocketPipe/WebSocketPipeReaderOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.IO.Pipelines; | ||
|
||
namespace Pipelines.Extensions.WebSocketPipe | ||
{ | ||
public class WebSocketPipeReaderOptions | ||
{ | ||
public PipeOptions PipeOptions { get; } | ||
|
||
public int SizeHint { get; } | ||
|
||
internal static readonly WebSocketPipeReaderOptions Default = new(); | ||
|
||
public WebSocketPipeReaderOptions(PipeOptions? pipeOptions = null, int sizeHint = 0) | ||
{ | ||
PipeOptions = pipeOptions ?? PipeOptions.Default; | ||
SizeHint = sizeHint; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
using Microsoft; | ||
using System; | ||
using System.IO.Pipelines; | ||
using System.Net.WebSockets; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Pipelines.Extensions.WebSocketPipe | ||
{ | ||
internal sealed class WebSocketPipeWriter : PipeWriter | ||
{ | ||
public WebSocket InternalWebSocket { get; } | ||
|
||
private readonly Pipe _pipe; | ||
private PipeWriter Writer => _pipe.Writer; | ||
private PipeReader Reader => _pipe.Reader; | ||
|
||
public WebSocketPipeWriter(WebSocket webSocket, WebSocketPipeWriterOptions options) | ||
{ | ||
Requires.NotNull(webSocket, nameof(webSocket)); | ||
Requires.NotNull(options, nameof(options)); | ||
|
||
InternalWebSocket = webSocket; | ||
_pipe = new Pipe(options.PipeOptions); | ||
} | ||
|
||
public override void Advance(int bytes) | ||
{ | ||
Writer.Advance(bytes); | ||
} | ||
|
||
public override Memory<byte> GetMemory(int sizeHint = 0) | ||
{ | ||
return Writer.GetMemory(sizeHint); | ||
} | ||
|
||
public override Span<byte> GetSpan(int sizeHint = 0) | ||
{ | ||
return Writer.GetSpan(sizeHint); | ||
} | ||
|
||
public override void CancelPendingFlush() | ||
{ | ||
Writer.CancelPendingFlush(); | ||
} | ||
|
||
public override void Complete(Exception? exception = null) | ||
{ | ||
Writer.Complete(exception); | ||
} | ||
|
||
public override async ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken = default) | ||
{ | ||
var flushResult = await Writer.FlushAsync(cancellationToken); | ||
|
||
try | ||
{ | ||
var result = await Reader.ReadAsync(cancellationToken); | ||
var buffer = result.Buffer; | ||
|
||
foreach (var memory in buffer) | ||
{ | ||
await InternalWebSocket.SendAsync(memory, WebSocketMessageType.Binary, true, cancellationToken); | ||
} | ||
|
||
Reader.AdvanceTo(buffer.End); | ||
|
||
if (result.IsCompleted) | ||
{ | ||
await Reader.CompleteAsync(); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
await Reader.CompleteAsync(ex); | ||
throw; | ||
} | ||
|
||
return flushResult; | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
Pipelines.Extensions/WebSocketPipe/WebSocketPipeWriterOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System.IO.Pipelines; | ||
|
||
namespace Pipelines.Extensions.WebSocketPipe | ||
{ | ||
public class WebSocketPipeWriterOptions | ||
{ | ||
public PipeOptions PipeOptions { get; } | ||
|
||
internal static readonly WebSocketPipeWriterOptions Default = new(); | ||
|
||
public WebSocketPipeWriterOptions(PipeOptions? pipeOptions = null) | ||
{ | ||
PipeOptions = pipeOptions ?? PipeOptions.Default; | ||
} | ||
} | ||
} |