ProgressiveFileCopier.cs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using MediaBrowser.Controller.Library;
  7. using MediaBrowser.Model.IO;
  8. using MediaBrowser.Model.Services;
  9. using Microsoft.Extensions.Logging;
  10. namespace MediaBrowser.Api.LiveTv
  11. {
  12. public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders
  13. {
  14. private readonly ILogger _logger;
  15. private readonly string _path;
  16. private readonly Dictionary<string, string> _outputHeaders;
  17. public bool AllowEndOfFile = true;
  18. private readonly IDirectStreamProvider _directStreamProvider;
  19. private IStreamHelper _streamHelper;
  20. public ProgressiveFileCopier(IStreamHelper streamHelper, string path, Dictionary<string, string> outputHeaders, ILogger logger)
  21. {
  22. _path = path;
  23. _outputHeaders = outputHeaders;
  24. _logger = logger;
  25. _streamHelper = streamHelper;
  26. }
  27. public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary<string, string> outputHeaders, ILogger logger)
  28. {
  29. _directStreamProvider = directStreamProvider;
  30. _outputHeaders = outputHeaders;
  31. _logger = logger;
  32. _streamHelper = streamHelper;
  33. }
  34. public IDictionary<string, string> Headers => _outputHeaders;
  35. public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
  36. {
  37. if (_directStreamProvider != null)
  38. {
  39. await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
  40. return;
  41. }
  42. var fileOptions = FileOptions.SequentialScan;
  43. // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
  44. if (Environment.OSVersion.Platform != PlatformID.Win32NT)
  45. {
  46. fileOptions |= FileOptions.Asynchronous;
  47. }
  48. using (var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions))
  49. {
  50. var emptyReadLimit = AllowEndOfFile ? 20 : 100;
  51. var eofCount = 0;
  52. while (eofCount < emptyReadLimit)
  53. {
  54. int bytesRead;
  55. bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
  56. if (bytesRead == 0)
  57. {
  58. eofCount++;
  59. await Task.Delay(100, cancellationToken).ConfigureAwait(false);
  60. }
  61. else
  62. {
  63. eofCount = 0;
  64. }
  65. }
  66. }
  67. }
  68. }
  69. }