Skip to content

Commit 774b2af

Browse files
authored
Streaming Interop Followup Items (#33916)
* Streaming Interop Followup Items * Streaming CI Debugging (#33917) * CI Debugging * CiData message * CiData message * Update RemoteJSDataStream.cs * Remove Task.Delay * Update RemoteJSDataStream.cs * Update RemoteJSDataStream.cs * PR Feedback (Including PipeReader Property) * Improve documentation on safe defaults * Task Completion Source & DefaultTimeout * InvalidateLastDataReceivedTimeForTimeout
1 parent 87b761d commit 774b2af

File tree

9 files changed

+208
-42
lines changed

9 files changed

+208
-42
lines changed

src/Components/Server/src/Circuits/RemoteJSDataStream.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ public static async ValueTask<RemoteJSDataStream> CreateRemoteJSDataStreamAsync(
4040
RemoteJSRuntime runtime,
4141
IJSStreamReference jsStreamReference,
4242
long totalLength,
43-
long maxBufferSize,
4443
long maximumIncomingBytes,
4544
TimeSpan jsInteropDefaultCallTimeout,
45+
long pauseIncomingBytesThreshold = -1,
46+
long resumeIncomingBytesThreshold = -1,
4647
CancellationToken cancellationToken = default)
4748
{
4849
// Enforce minimum 1 kb, maximum 50 kb, SignalR message size.
@@ -54,7 +55,7 @@ public static async ValueTask<RemoteJSDataStream> CreateRemoteJSDataStreamAsync(
5455
throw new ArgumentException($"SignalR MaximumIncomingBytes must be at least 1 kb.");
5556

5657
var streamId = runtime.RemoteJSDataStreamNextInstanceId++;
57-
var remoteJSDataStream = new RemoteJSDataStream(runtime, streamId, totalLength, maxBufferSize, jsInteropDefaultCallTimeout, cancellationToken);
58+
var remoteJSDataStream = new RemoteJSDataStream(runtime, streamId, totalLength, jsInteropDefaultCallTimeout, pauseIncomingBytesThreshold, resumeIncomingBytesThreshold, cancellationToken);
5859
await runtime.InvokeVoidAsync("Blazor._internal.sendJSDataStream", jsStreamReference, streamId, chunkSize);
5960
return remoteJSDataStream;
6061
}
@@ -63,8 +64,9 @@ private RemoteJSDataStream(
6364
RemoteJSRuntime runtime,
6465
long streamId,
6566
long totalLength,
66-
long maxBufferSize,
6767
TimeSpan jsInteropDefaultCallTimeout,
68+
long pauseIncomingBytesThreshold,
69+
long resumeIncomingBytesThreshold,
6870
CancellationToken cancellationToken)
6971
{
7072
_runtime = runtime;
@@ -78,10 +80,16 @@ private RemoteJSDataStream(
7880

7981
_runtime.RemoteJSDataStreamInstances.Add(_streamId, this);
8082

81-
_pipe = new Pipe(new PipeOptions(pauseWriterThreshold: maxBufferSize, resumeWriterThreshold: maxBufferSize / 2));
83+
_pipe = new Pipe(new PipeOptions(pauseWriterThreshold: pauseIncomingBytesThreshold, resumeWriterThreshold: resumeIncomingBytesThreshold));
8284
_pipeReaderStream = _pipe.Reader.AsStream();
85+
PipeReader = _pipe.Reader;
8386
}
8487

88+
/// <summary>
89+
/// Gets a <see cref="PipeReader"/> to directly read data sent by the JavaScript client.
90+
/// </summary>
91+
public PipeReader PipeReader { get; }
92+
8593
private async Task<bool> ReceiveData(long chunkId, byte[] chunk, string error)
8694
{
8795
try
@@ -199,13 +207,23 @@ private async Task ThrowOnTimeout()
199207
if (!_disposed && (DateTimeOffset.UtcNow >= _lastDataReceivedTime.Add(_jsInteropDefaultCallTimeout)))
200208
{
201209
// Dispose of the stream if a chunk isn't received within the jsInteropDefaultCallTimeout.
202-
var timeoutException = new TimeoutException("Did not receive any data in the alloted time.");
210+
var timeoutException = new TimeoutException("Did not receive any data in the allotted time.");
203211
await CompletePipeAndDisposeStream(timeoutException);
204212
_runtime.RaiseUnhandledException(timeoutException);
205213
}
206214
}
207215

208-
internal async Task CompletePipeAndDisposeStream(Exception? ex = null)
216+
/// <summary>
217+
/// For testing purposes only.
218+
///
219+
/// Triggers the timeout on the next check.
220+
/// </summary>
221+
internal void InvalidateLastDataReceivedTimeForTimeout()
222+
{
223+
_lastDataReceivedTime = _lastDataReceivedTime.Subtract(_jsInteropDefaultCallTimeout);
224+
}
225+
226+
private async Task CompletePipeAndDisposeStream(Exception? ex = null)
209227
{
210228
await _pipe.Writer.CompleteAsync(ex);
211229
Dispose(true);

src/Components/Server/src/Circuits/RemoteJSRuntime.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ public void MarkPermanentlyDisconnected()
157157
_clientProxy = null;
158158
}
159159

160-
protected override async Task<Stream> ReadJSDataAsStreamAsync(IJSStreamReference jsStreamReference, long totalLength, long maxBufferSize, CancellationToken cancellationToken)
161-
=> await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(this, jsStreamReference, totalLength, maxBufferSize, _maximumIncomingBytes, _options.JSInteropDefaultCallTimeout, cancellationToken);
160+
protected override async Task<Stream> ReadJSDataAsStreamAsync(IJSStreamReference jsStreamReference, long totalLength, long pauseIncomingBytesThreshold = -1, long resumeIncomingBytesThreshold = -1, CancellationToken cancellationToken = default)
161+
=> await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(this, jsStreamReference, totalLength, _maximumIncomingBytes, _options.JSInteropDefaultCallTimeout, pauseIncomingBytesThreshold, resumeIncomingBytesThreshold, cancellationToken);
162162

163163
public static class Log
164164
{

0 commit comments

Comments
 (0)