Skip to content

Commit

Permalink
added xml docs to some classes
Browse files Browse the repository at this point in the history
  • Loading branch information
bezzad committed Sep 18, 2024
1 parent 7786951 commit 1e7591a
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 97 deletions.
4 changes: 2 additions & 2 deletions src/Downloader.Test/UnitTests/DownloadPackageTestOnFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public override async Task DisposeAsync()
[Theory]
[InlineData(true)] // BuildStorageWithReserveSpaceTest
[InlineData(false)] // BuildStorageTest
public void BuildStorageTest(bool reserveSpace)
public async Task BuildStorageTest(bool reserveSpace)
{
// arrange
_path = Path.GetTempFileName();
Expand All @@ -43,7 +43,7 @@ public void BuildStorageTest(bool reserveSpace)

// act
Package.BuildStorage(reserveSpace, 1024 * 1024);
using var stream = Package.Storage.OpenRead();
await using var stream = Package.Storage.OpenRead();

// assert
Assert.IsType<FileStream>(stream);
Expand Down
43 changes: 19 additions & 24 deletions src/Downloader/ConcurrentPacketBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,36 @@ namespace Downloader;
/// Represents a thread-safe, ordered collection of objects.
/// With thread-safe multi-thread adding and single-thread consuming methodology (N producers - 1 consumer)
/// </summary>
/// <typeparam name="T">Specifies the type of elements in the ConcurrentDictionary.</typeparam>
/// <remarks>
/// <typeparam name="T">Specifies the type of elements in the ConcurrentDictionary.</typeparam>
/// </remarks>
[DebuggerTypeProxy(typeof(IReadOnlyCollection<>))]
[DebuggerDisplay("Count = {Count}")]
internal class ConcurrentPacketBuffer<T> : IReadOnlyCollection<T>, IDisposable where T : class, ISizeableObject
internal class ConcurrentPacketBuffer<T>(ILogger logger = null) : IReadOnlyCollection<T>, IDisposable
where T : class, ISizeableObject
{
private volatile bool _disposed = false;
private volatile bool _disposed;
private long _bufferSize = long.MaxValue;
protected readonly ILogger Logger;
protected readonly ILogger Logger = logger;
protected readonly SemaphoreSlim QueueConsumeLocker = new SemaphoreSlim(0);
protected readonly PauseTokenSource AddingBlocker = new PauseTokenSource();
protected readonly PauseTokenSource FlushBlocker = new PauseTokenSource();
protected readonly ConcurrentQueue<T> Queue;
protected readonly ConcurrentQueue<T> Queue = new();

public long BufferSize
{
get => _bufferSize;
set
{
_bufferSize = (value <= 0) ? long.MaxValue : value;
}
set => _bufferSize = (value <= 0) ? long.MaxValue : value;
}

public ConcurrentPacketBuffer(long size, ILogger logger = null) : this(logger)
{
BufferSize = size;
}

public ConcurrentPacketBuffer(ILogger logger = null)
{
Queue = new ConcurrentQueue<T>();
Logger = logger;
}

public IEnumerator<T> GetEnumerator()
{
// ReSharper disable once NotDisposedResourceIsReturned
return Queue.GetEnumerator();
}

Expand Down Expand Up @@ -103,7 +97,8 @@ private void StopAddingIfLimitationExceeded(long packetSize)
{
if (BufferSize < packetSize * Count)
{
Logger?.LogDebug($"ConcurrentPacketBuffer: Stop writing packets to the queue on size {packetSize * Count}bytes until the memory is free");
Logger?.LogDebug($"ConcurrentPacketBuffer: Stop writing packets to the queue on " +
$"size {packetSize * Count}bytes until the memory is free");
StopAdding();
}
}
Expand Down Expand Up @@ -136,12 +131,12 @@ public void ResumeAdding()

public void Dispose()
{
if (_disposed)
return;

_disposed = true;
StopAdding();
QueueConsumeLocker.Dispose();
AddingBlocker.Resume();
if (!_disposed)
{
_disposed = true;
StopAdding();
QueueConsumeLocker.Dispose();
AddingBlocker.Resume();
}
}
}
}
80 changes: 79 additions & 1 deletion src/Downloader/DownloadBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,51 @@

namespace Downloader;

/// <summary>
/// A builder class for configuring and creating download instances.
/// </summary>
public class DownloadBuilder
{
private string _url;
private string _directoryPath;
private string _filename;
private DownloadConfiguration _downloadConfiguration;

/// <summary>
/// Creates a new instance of the <see cref="DownloadBuilder"/> class.
/// </summary>
/// <returns>A new instance of the <see cref="DownloadBuilder"/> class.</returns>
public static DownloadBuilder New()
{
return new DownloadBuilder();
}

/// <summary>
/// Sets the URL for the download.
/// </summary>
/// <param name="url">The URL to download from.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithUrl(string url)
{
this._url = url;
return this;
}

/// <summary>
/// Sets the URL for the download using a <see cref="Uri"/> object.
/// </summary>
/// <param name="url">The URL to download from.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithUrl(Uri url)
{
return WithUrl(url.AbsoluteUri);
}

/// <summary>
/// Sets the file location for the download.
/// </summary>
/// <param name="fullPath">The full path where the file will be saved.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithFileLocation(string fullPath)
{
fullPath = Path.GetFullPath(fullPath);
Expand All @@ -34,51 +56,96 @@ public DownloadBuilder WithFileLocation(string fullPath)
return this;
}

/// <summary>
/// Sets the file location for the download using a <see cref="Uri"/> object.
/// </summary>
/// <param name="uri">The URI representing the file location.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithFileLocation(Uri uri)
{
return WithFileLocation(uri.LocalPath);
}

/// <summary>
/// Sets the file location for the download using a <see cref="FileInfo"/> object.
/// </summary>
/// <param name="fileInfo">The file information representing the file location.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithFileLocation(FileInfo fileInfo)
{
return WithFileLocation(fileInfo.FullName);
}

/// <summary>
/// Sets the directory path for the download.
/// </summary>
/// <param name="directoryPath">The directory path where the file will be saved.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithDirectory(string directoryPath)
{
this._directoryPath = directoryPath;
return this;
}

/// <summary>
/// Sets the directory path for the download using a <see cref="Uri"/> object.
/// </summary>
/// <param name="folderUri">The URI representing the directory path.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithFolder(Uri folderUri)
{
return WithDirectory(folderUri.LocalPath);
}

/// <summary>
/// Sets the directory path for the download using a <see cref="DirectoryInfo"/> object.
/// </summary>
/// <param name="folder">The directory information representing the directory path.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithFolder(DirectoryInfo folder)
{
return WithDirectory(folder.FullName);
}

/// <summary>
/// Sets the file name for the download.
/// </summary>
/// <param name="name">The name of the file to be saved.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithFileName(string name)
{
this._filename = name;
return this;
}

/// <summary>
/// Sets the configuration for the download.
/// </summary>
/// <param name="configuration">The download configuration.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder WithConfiguration(DownloadConfiguration configuration)
{
_downloadConfiguration = configuration;
return this;
}

/// <summary>
/// Configures the download with the specified configuration action.
/// </summary>
/// <param name="configure">The action to configure the download.</param>
/// <returns>The current <see cref="DownloadBuilder"/> instance.</returns>
public DownloadBuilder Configure(Action<DownloadConfiguration> configure)
{
var configuration = new DownloadConfiguration();
configure(configuration);
return WithConfiguration(configuration);
}

/// <summary>
/// Builds and returns a new <see cref="IDownload"/> instance with the configured settings.
/// </summary>
/// <returns>A new <see cref="IDownload"/> instance.</returns>
/// <exception cref="ArgumentNullException">Thrown when the URL has not been declared.</exception>
public IDownload Build()
{
if (string.IsNullOrWhiteSpace(_url))
Expand All @@ -89,13 +156,24 @@ public IDownload Build()
return new Download(_url, _directoryPath, _filename, _downloadConfiguration);
}

/// <summary>
/// Builds and returns a new <see cref="IDownload"/> instance with the specified package.
/// </summary>
/// <param name="package">The download package.</param>
/// <returns>A new <see cref="IDownload"/> instance.</returns>
public IDownload Build(DownloadPackage package)
{
return new Download(package, _url, _downloadConfiguration);
}

/// <summary>
/// Builds and returns a new <see cref="IDownload"/> instance with the specified package and configuration.
/// </summary>
/// <param name="package">The download package.</param>
/// <param name="downloadConfiguration">The download configuration.</param>
/// <returns>A new <see cref="IDownload"/> instance.</returns>
public IDownload Build(DownloadPackage package, DownloadConfiguration downloadConfiguration)
{
return new Download(package, _url, downloadConfiguration);
}
}
}
Loading

0 comments on commit 1e7591a

Please sign in to comment.