ProgressiveFileCopier.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using MediaBrowser.Controller.Library;
  6. using MediaBrowser.Model.IO;
  7. using MediaBrowser.Model.Services;
  8. using Microsoft.Extensions.Logging;
  9. namespace MediaBrowser.Api.LiveTv
  10. {
  11. public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders
  12. {
  13. private readonly IFileSystem _fileSystem;
  14. private readonly ILogger _logger;
  15. private readonly string _path;
  16. private readonly Dictionary<string, string> _outputHeaders;
  17. const int StreamCopyToBufferSize = 81920;
  18. public long StartPosition { get; set; }
  19. public bool AllowEndOfFile = true;
  20. private readonly IDirectStreamProvider _directStreamProvider;
  21. private IStreamHelper _streamHelper;
  22. public ProgressiveFileCopier(IFileSystem fileSystem, IStreamHelper streamHelper, string path, Dictionary<string, string> outputHeaders, ILogger logger)
  23. {
  24. _fileSystem = fileSystem;
  25. _path = path;
  26. _outputHeaders = outputHeaders;
  27. _logger = logger;
  28. _streamHelper = streamHelper;
  29. }
  30. public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary<string, string> outputHeaders, ILogger logger)
  31. {
  32. _directStreamProvider = directStreamProvider;
  33. _outputHeaders = outputHeaders;
  34. _logger = logger;
  35. _streamHelper = streamHelper;
  36. }
  37. public IDictionary<string, string> Headers => _outputHeaders;
  38. private Stream GetInputStream(bool allowAsyncFileRead)
  39. {
  40. var fileOpenOptions = FileOpenOptions.SequentialScan;
  41. if (allowAsyncFileRead)
  42. {
  43. fileOpenOptions |= FileOpenOptions.Asynchronous;
  44. }
  45. return _fileSystem.GetFileStream(_path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions);
  46. }
  47. public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
  48. {
  49. if (_directStreamProvider != null)
  50. {
  51. await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
  52. return;
  53. }
  54. var eofCount = 0;
  55. // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
  56. var allowAsyncFileRead = true;
  57. using (var inputStream = GetInputStream(allowAsyncFileRead))
  58. {
  59. if (StartPosition > 0)
  60. {
  61. inputStream.Position = StartPosition;
  62. }
  63. var emptyReadLimit = AllowEndOfFile ? 20 : 100;
  64. while (eofCount < emptyReadLimit)
  65. {
  66. int bytesRead;
  67. bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
  68. //var position = fs.Position;
  69. //_logger.LogDebug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
  70. if (bytesRead == 0)
  71. {
  72. eofCount++;
  73. await Task.Delay(100, cancellationToken).ConfigureAwait(false);
  74. }
  75. else
  76. {
  77. eofCount = 0;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. }