ProgressiveFileCopier.cs 3.9 KB

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