Exemple #1
0
        public ReusableTask <int> ReadAsync(ITorrentManagerFile file, long offset, Memory <byte> buffer)
        {
            if (DoNotReadFrom.Contains(file))
            {
                return(ReusableTask.FromResult(0));
            }

            if (!Paths.Contains(file.FullPath))
            {
                Paths.Add(file.FullPath);
            }

            if ((offset + buffer.Length) > file.Length)
            {
                throw new ArgumentOutOfRangeException("Tried to read past the end of the file");
            }
            if (!DontWrite)
            {
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer.Span[i] = (byte)i;
                }
            }
            return(ReusableTask.FromResult(buffer.Length));
        }
Exemple #2
0
        public async ReusableTask WriteAsync(ITorrentManagerFile file, long offset, ReadOnlyMemory <byte> buffer)
        {
            if (file is null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            if (offset < 0 || offset + buffer.Length > file.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            using (await Limiter.EnterAsync()) {
                using var rented = await StreamCache.GetOrCreateStreamAsync(file, FileAccess.ReadWrite).ConfigureAwait(false);

                // FileStream.WriteAsync does some work synchronously, according to the profiler.
                // It looks like if the file is too small it is expanded (SetLength is called)
                // synchronously before the asynchronous Write is performed.
                //
                // We also want the Seek operation to execute on the threadpool.
                await SwitchToThreadpool();

                rented.Stream !.Seek(offset, SeekOrigin.Begin);
                rented.Stream.Write(buffer);
            }
        }
Exemple #3
0
        public async ReusableTask <int> ReadAsync(ITorrentManagerFile file, long offset, Memory <byte> buffer)
        {
            if (file is null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            if (offset < 0 || offset + buffer.Length > file.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            using (await Limiter.EnterAsync()) {
                using var rented = await StreamCache.GetOrCreateStreamAsync(file, FileAccess.Read).ConfigureAwait(false);

                await SwitchToThreadpool();

                if (rented.Stream !.Length < offset + buffer.Length)
                {
                    return(0);
                }

                if (rented.Stream.Position != offset)
                {
                    rented.Stream.Seek(offset, SeekOrigin.Begin);
                }
                return(rented.Stream.Read(buffer));
            }
        }
        public override async ReusableTask WriteAsync(ITorrentManagerFile file, long offset, ReadOnlyMemory <byte> buffer)
        {
            var tcs = new ReusableTaskCompletionSource <object> ();

            Writes.Add(tcs);
            await tcs.Task;
        }
Exemple #5
0
 public ReusableTask <int> ReadAsync(ITorrentManagerFile file, long offset, Memory <byte> buffer)
 {
     if (read)
     {
         throw new Exception("read");
     }
     return(ReusableTask.FromResult(buffer.Length));
 }
Exemple #6
0
 public ReusableTask MoveAsync(ITorrentManagerFile file, string newPath, bool overwrite)
 {
     if (move)
     {
         throw new Exception("move");
     }
     return(ReusableTask.CompletedTask);
 }
Exemple #7
0
 public ReusableTask <bool> ExistsAsync(ITorrentManagerFile file)
 {
     if (exist)
     {
         throw new Exception("exists");
     }
     return(ReusableTask.FromResult(true));
 }
Exemple #8
0
 public ReusableTask WriteAsync(ITorrentManagerFile file, long offset, ReadOnlyMemory <byte> buffer)
 {
     if (write)
     {
         throw new Exception("write");
     }
     return(ReusableTask.CompletedTask);
 }
Exemple #9
0
 public ReusableTask CloseAsync(ITorrentManagerFile file)
 {
     if (close)
     {
         throw new Exception("close");
     }
     return(ReusableTask.CompletedTask);
 }
            public ReusableTask WriteAsync(ITorrentManagerFile file, long offset, ReadOnlyMemory <byte> buffer)
            {
                var result = new byte[buffer.Length];

                buffer.CopyTo(result.AsMemory());
                WrittenData.Add(Tuple.Create(file, offset, result));
                return(ReusableTask.CompletedTask);
            }
        /// <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. 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 <IUriStream> CreateHttpStreamAsync(ITorrentManagerFile file, bool prebuffer, CancellationToken token)
        {
            var stream = await CreateStreamAsync(file, prebuffer, token);

            var httpStreamer = new HttpStream(stream);

            return(httpStreamer);
        }
Exemple #12
0
 public ReusableTask FlushAsync(ITorrentManagerFile file)
 {
     if (flush)
     {
         throw new Exception("flush");
     }
     FlushedFiles.Add(file);
     return(ReusableTask.CompletedTask);
 }
        internal async ReusableTask FlushAsync(ITorrentManagerFile file)
        {
            using var rented = await GetStream(file);

            if (rented.Stream != null)
            {
                await rented.Stream.FlushAsync();
            }
        }
Exemple #14
0
        public async ReusableTask MoveAsync(ITorrentManagerFile file, string newPath, bool overwrite)
        {
            await StreamCache.CloseStreamAsync(file);

            if (overwrite)
            {
                File.Delete(newPath);
            }
            if (File.Exists(file.FullPath))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(newPath) !);
                File.Move(file.FullPath, newPath);
            }
        }
        internal async ReusableTask <RentedStream> GetOrCreateStreamAsync(ITorrentManagerFile file, FileAccess access)
        {
            if (!Streams.TryGetValue(file, out StreamData? data))
            {
                data = Streams[file] = new StreamData();
            }

            var releaser = await data.Locker.EnterAsync();

            if (data.Stream != null)
            {
                // If we are requesting write access and the current stream does not have it
                if (((access & FileAccess.Write) == FileAccess.Write) && !data.Stream.CanWrite)
                {
                    data.Stream.Dispose();
                    data.Stream = null;
                    Count--;
                }
            }

            if (data.Stream == null)
            {
                if (!File.Exists(file.FullPath))
                {
                    if (Path.GetDirectoryName(file.FullPath) is string parentDirectory)
                    {
                        Directory.CreateDirectory(parentDirectory);
                    }
                    NtfsSparseFile.CreateSparse(file.FullPath, file.Length);
                }
                data.Stream = StreamCreator(file, access);
                Count++;

                // Ensure that we truncate existing files which are too large
                if (data.Stream.Length > file.Length)
                {
                    if (!data.Stream.CanWrite)
                    {
                        data.Stream.Dispose();
                        data.Stream = StreamCreator(file, FileAccess.ReadWrite);
                    }
                    data.Stream.SetLength(file.Length);
                }
            }

            data.LastUsedStamp = Stopwatch.GetTimestamp();
            MaybeRemoveOldestStream();

            return(new RentedStream(data.Stream, releaser));
        }
        public void Setup()
        {
            var pieceLength = Constants.BlockSize * 2;

            Temp = Path.GetTempPath() + "monotorrent_tests";

            var files = TorrentFileInfo.Create(pieceLength,
                                               ("test1.file", 12345, Path.Combine(Temp, "test1.file")),
                                               ("test2.file", 12345, Path.Combine(Temp, "test2.file")),
                                               ("test3.file", 12345, Path.Combine(Temp, "test3.file")),
                                               ("test4.file", 12345, Path.Combine(Temp, "test4.file"))
                                               );

            TorrentFile = files.First();
            Others      = files.Skip(1).ToArray();
        }
        internal async ReusableTask <bool> CloseStreamAsync(ITorrentManagerFile file)
        {
            if (Streams.TryGetValue(file, out StreamData? data))
            {
                using var releaser = await data.Locker.EnterAsync();

                if (data.Stream != null)
                {
                    data.Stream.Dispose();
                    data.Stream = null;
                    Count--;
                    return(true);
                }
            }

            return(false);
        }
        internal async ReusableTask <RentedStream> GetStream(ITorrentManagerFile file)
        {
            if (Streams.TryGetValue(file, out StreamData? data))
            {
                var releaser = await data.Locker.EnterAsync();

                if (data.Stream == null)
                {
                    releaser.Dispose();
                }
                else
                {
                    data.LastUsedStamp = Stopwatch.GetTimestamp();
                    return(new RentedStream(data.Stream, releaser));
                }
            }
            return(new RentedStream(null, default));
        }
            public ReusableTask <int> ReadAsync(ITorrentManagerFile file, long offset, Memory <byte> buffer)
            {
                ReadData.Add(Tuple.Create(file, offset, buffer.Length));

                if (Data == null)
                {
                    var fileData = WrittenData
                                   .Where(t => t.Item1 == file)
                                   .OrderBy(t => t.Item2)
                                   .SelectMany(t => t.Item3)
                                   .ToArray();
                    fileData.AsSpan((int)offset, buffer.Length).CopyTo(buffer.Span);
                }
                else
                {
                    var data = Data[file];
                    data.AsSpan((int)offset, buffer.Length).CopyTo(buffer.Span);
                }
                return(ReusableTask.FromResult(buffer.Length));
            }
        public async Task SetFilePriorityAsync(ITorrentManagerFile file, Priority priority)
        {
            if (!Files.Contains(file))
            {
                throw new ArgumentNullException(nameof(file), "The file is not part of this torrent");
            }

            // No change
            if (priority == file.Priority)
            {
                return;
            }

            await ClientEngine.MainLoop;

            // If the old priority, or new priority, is 'DoNotDownload' then the selector needs to be refreshed
            bool needsToUpdateSelector = file.Priority == Priority.DoNotDownload || priority == Priority.DoNotDownload;

            ((TorrentFileInfo)file).Priority = priority;

            if (needsToUpdateSelector)
            {
                // If we change the priority of a file we need to figure out which files are marked
                // as 'DoNotDownload' and which ones are downloadable.
                PartialProgressSelector.SetAll(false);
                if (Files.All(t => t.Priority != Priority.DoNotDownload))
                {
                    PartialProgressSelector.SetAll(true);
                }
                else
                {
                    PartialProgressSelector.SetAll(false);
                    foreach (var f in Files.Where(t => t.Priority != Priority.DoNotDownload))
                    {
                        PartialProgressSelector.SetTrue((f.StartPieceIndex, f.EndPieceIndex));
                    }
                }
            }
        }
        /// <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(ITorrentManagerFile 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.Torrent !.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);
        }
Exemple #22
0
 public void Set(ITorrentManagerFile file, Priority priority)
 => ((TorrentFileInfo)file).Priority = priority;
 public static long BytesDownloaded(this ITorrentManagerFile info)
 => (long)(info.BitField.PercentComplete * info.Length / 100.0);
        internal async Task <bool> CheckFileExistsAsync(ITorrentManagerFile file)
        {
            await IOLoop;

            return(await Cache.Writer.ExistsAsync(file).ConfigureAwait(false));
        }
Exemple #25
0
 public ReusableTask CloseAsync(ITorrentManagerFile file)
 {
     return(ReusableTask.CompletedTask);
 }
Exemple #26
0
 public ReusableTask WriteAsync(ITorrentManagerFile file, long offset, ReadOnlyMemory <byte> buffer)
 {
     return(ReusableTask.CompletedTask);
 }
Exemple #27
0
 public ReusableTask MoveAsync(ITorrentManagerFile file, string newPath, bool overwrite)
 {
     return(ReusableTask.CompletedTask);
 }
Exemple #28
0
 public ReusableTask <bool> ExistsAsync(ITorrentManagerFile file)
 {
     return(ReusableTask.FromResult(FilesThatExist.Contains(file)));
 }
 public ReusableTask <int> ReadAsync(ITorrentManagerFile file, long offset, Memory <byte> buffer)
 {
     return(ReusableTask.FromResult(0));
 }
 public Files(ITorrentManagerFile file)
 {
     Priority = file.Priority;
     File     = file;
 }