diff options
| author | crobibero <cody@robibe.ro> | 2020-07-06 10:00:23 -0600 |
|---|---|---|
| committer | crobibero <cody@robibe.ro> | 2020-07-06 10:00:23 -0600 |
| commit | b2e7a4a1cb335e7281f7857cc88fadd6b671dcb4 (patch) | |
| tree | f5f8769b907cf183b1309acec891641e0ec954cb /Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | |
| parent | 068725cdedecc88bcde9f18c68b9b1e5c0f6e569 (diff) | |
| parent | 613444a152ecede061d229cbd0d528d88915db7b (diff) | |
Merge remote-tracking branch 'upstream/api-migration' into api-channel
Diffstat (limited to 'Jellyfin.Api/Helpers/ProgressiveFileCopier.cs')
| -rw-r--r-- | Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs new file mode 100644 index 000000000..e8e6966f4 --- /dev/null +++ b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.IO; + +namespace Jellyfin.Api.Helpers +{ + /// <summary> + /// Progressive file copier. + /// </summary> + public class ProgressiveFileCopier + { + private readonly string? _path; + private readonly IDirectStreamProvider? _directStreamProvider; + private readonly IStreamHelper _streamHelper; + + /// <summary> + /// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class. + /// </summary> + /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param> + /// <param name="path">Filepath to stream from.</param> + public ProgressiveFileCopier(IStreamHelper streamHelper, string path) + { + _path = path; + _streamHelper = streamHelper; + _directStreamProvider = null; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class. + /// </summary> + /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param> + /// <param name="directStreamProvider">Instance of the <see cref="IDirectStreamProvider"/> interface.</param> + public ProgressiveFileCopier(IStreamHelper streamHelper, IDirectStreamProvider directStreamProvider) + { + _directStreamProvider = directStreamProvider; + _streamHelper = streamHelper; + _path = null; + } + + /// <summary> + /// Write source stream to output. + /// </summary> + /// <param name="outputStream">Output stream.</param> + /// <param name="cancellationToken">Cancellation token.</param> + /// <returns>A <see cref="Task"/>.</returns> + public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) + { + if (_directStreamProvider != null) + { + await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); + return; + } + + var fileOptions = FileOptions.SequentialScan; + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + { + fileOptions |= FileOptions.Asynchronous; + } + + await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions); + const int emptyReadLimit = 100; + var eofCount = 0; + while (eofCount < emptyReadLimit) + { + var bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); + + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + } + } + } + } +} |
