private async Task FillBuffer(PipeWriter writer, CancellationToken cancellationToken) { long offset = 0; try { while (offset < fileEntry.Size) { var pipeBuffer = writer.GetMemory(maxMessageSize); try { using var readSegmentCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); readSegmentCts.CancelAfter(segmentFetchTimeout); var length = (int)Math.Min(maxMessageSize, fileEntry.Size - offset); var base64 = await jsModule.ReadDataAsync(elementRef, fileEntry.Id, offset, length, cancellationToken); var bytes = Convert.FromBase64String(base64); if (bytes is null || bytes.Length != length) { throw new InvalidOperationException( $"A segment with size {bytes?.Length ?? 0} bytes was received, but {length} bytes were expected."); } bytes.CopyTo(pipeBuffer); writer.Advance(length); offset += length; var result = await writer.FlushAsync(cancellationToken); await Task.WhenAll( fileEntryNotifier.UpdateFileWrittenAsync(fileEntry, offset, bytes), fileEntryNotifier.UpdateFileProgressAsync(fileEntry, bytes.Length)); if (result.IsCompleted) { break; } } catch (Exception e) { await writer.CompleteAsync(e); return; } } } finally { await fileEntryNotifier.UpdateFileEndedAsync(fileEntry, offset == fileEntry.Size); } await writer.CompleteAsync(); }
private async Task FillBuffer(PipeWriter writer, CancellationToken cancellationToken) { if (maxFileSize < fileEntry.Size) { await fileEntryNotifier.UpdateFileEndedAsync(fileEntry, false, FileInvalidReason.MaxLengthExceeded); return; } long position = 0; try { while (position < fileEntry.Size) { var pipeBuffer = writer.GetMemory(maxMessageSize); try { using var readSegmentCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); readSegmentCts.CancelAfter(segmentFetchTimeout); var length = (int)Math.Min(maxMessageSize, fileEntry.Size - position); var base64 = await jsModule.ReadDataAsync(elementRef, fileEntry.Id, position, length, cancellationToken); var bytes = Convert.FromBase64String(base64); if (bytes is null || bytes.Length != length) { await fileEntryNotifier.UpdateFileEndedAsync(fileEntry, false, FileInvalidReason.UnexpectedBufferChunkLength); await writer.CompleteAsync(); return; } bytes.CopyTo(pipeBuffer); writer.Advance(length); position += length; var result = await writer.FlushAsync(cancellationToken); await Task.WhenAll( fileEntryNotifier.UpdateFileWrittenAsync(fileEntry, position, bytes), fileEntryNotifier.UpdateFileProgressAsync(fileEntry, bytes.Length)); if (result.IsCompleted) { break; } } catch (OperationCanceledException oce) { await writer.CompleteAsync(oce); await fileEntryNotifier.UpdateFileEndedAsync(fileEntry, false, FileInvalidReason.TaskCancelled); return; } catch (Exception e) { await writer.CompleteAsync(e); } } } finally { if (!cancellationToken.IsCancellationRequested) { var success = position == fileEntry.Size; var overMaxBufferChunkLength = position > fileEntry.Size; var fileInvalidReason = success ? FileInvalidReason.None : overMaxBufferChunkLength ? FileInvalidReason.UnexpectedBufferChunkLength : FileInvalidReason.UnexpectedError; await fileEntryNotifier.UpdateFileEndedAsync(fileEntry, success, fileInvalidReason); } } await writer.CompleteAsync(); }