/// <summary> /// Creates a <see cref="Stream"/> which can be used to access the given <see cref="TorrentFile"/> /// while it is downloading. This stream is seekable and readable. The first and last pieces of /// this file will be buffered before the stream is created if <paramref name="prebuffer"/> is /// set to true. Finally, this stream must be disposed before another stream can be created. /// </summary> /// <param name="file">The file to open</param> /// <param name="prebuffer">True if the first and last piece should be downloaded before the Stream is created.</param> /// <param name="token">The cancellation token.</param> /// <returns></returns> public async Task <Stream> CreateStreamAsync(TorrentFile file, bool prebuffer, CancellationToken token) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (!Manager.Torrent.Files.Contains(file)) { throw new ArgumentException("The TorrentFile is not from this TorrentManager", nameof(file)); } if (!Active) { throw new InvalidOperationException("You must call StartAsync before creating a stream."); } if (ActiveStream != null && !ActiveStream.Disposed) { throw new InvalidOperationException("You must Dispose the previous stream before creating a new one."); } Picker.SeekToPosition(file, 0); ActiveStream = new LocalStream(Manager, file, Picker); var tcs = CancellationTokenSource.CreateLinkedTokenSource(Cancellation.Token, token); if (prebuffer) { ActiveStream.Seek(ActiveStream.Length - 1, SeekOrigin.Begin); await ActiveStream.ReadAsync(new byte[1], 0, 1, tcs.Token); ActiveStream.Seek(0, SeekOrigin.Begin); await ActiveStream.ReadAsync(new byte[1], 0, 1, tcs.Token); } return(ActiveStream); }
/// <summary> /// Creates a <see cref="Stream"/> which can be used to access the given <see cref="TorrentFile"/> /// while it is downloading. This stream is seekable and readable. The first and last pieces of /// this file will be buffered before the stream is created if <paramref name="prebuffer"/> is /// set to true. Finally, this stream must be disposed before another stream can be created. /// </summary> /// <param name="file">The file to open</param> /// <param name="prebuffer">True if the first and last piece should be downloaded before the Stream is created.</param> /// <param name="token">The cancellation token.</param> /// <returns></returns> public async Task <Stream> CreateStreamAsync(ITorrentFileInfo file, bool prebuffer, CancellationToken token) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (Manager.Files == null) { throw new InvalidOperationException("The metadata for this torrent has not been downloaded. You must call WaitForMetadataAsync before creating a stream."); } if (Manager.State == TorrentState.Stopped || Manager.State == TorrentState.Stopping || Manager.State == TorrentState.Error) { throw new InvalidOperationException($"The torrent state was {Manager.State}. StreamProvider cannot be used unless the torrent manager has been successfully started."); } if (!Manager.Files.Contains(file)) { throw new ArgumentException("The TorrentFile is not from this TorrentManager", nameof(file)); } if (ActiveStream != null && !ActiveStream.Disposed) { throw new InvalidOperationException("You must Dispose the previous stream before creating a new one."); } ActiveStream = new LocalStream(Manager, file, PieceRequester); var tcs = CancellationTokenSource.CreateLinkedTokenSource(Cancellation.Token, token); if (prebuffer) { ActiveStream.Seek(ActiveStream.Length - Manager.PieceLength * 2, SeekOrigin.Begin); await ActiveStream.ReadAsync(new byte[1], 0, 1, tcs.Token); ActiveStream.Seek(0, SeekOrigin.Begin); await ActiveStream.ReadAsync(new byte[1], 0, 1, tcs.Token); } ActiveStream.Seek(0, SeekOrigin.Begin); return(ActiveStream); }