Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions generator/.DevConfigs/7f23582e-3225-487b-83e7-167cf17cb234.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"services": [
{
"serviceName": "S3",
"type": "minor",
"changeLogMessages": [
"Added DownloadDirectoryInitiatedEvent, DownloadDirectoryCompletedEvent, and DownloadDirectoryFailedEvent for Amazon.S3.Transfer.TransferUtility.DownloadDirectory."
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,39 @@ internal partial class DownloadDirectoryCommand : BaseCommand<TransferUtilityDow
long _transferredBytes;
string _currentFile;

#region Event Firing Methods

private void FireTransferInitiatedEvent()
{
var transferInitiatedEventArgs = new DownloadDirectoryInitiatedEventArgs(_request);
_request.OnRaiseDownloadDirectoryInitiatedEvent(transferInitiatedEventArgs);
}

private void FireTransferCompletedEvent(TransferUtilityDownloadDirectoryResponse response)
{
var transferCompletedEventArgs = new DownloadDirectoryCompletedEventArgs(
_request,
response,
Interlocked.Read(ref _transferredBytes),
_totalBytes,
_numberOfFilesDownloaded,
_totalNumberOfFilesToDownload);
_request.OnRaiseDownloadDirectoryCompletedEvent(transferCompletedEventArgs);
}

private void FireTransferFailedEvent()
{
var eventArgs = new DownloadDirectoryFailedEventArgs(
_request,
Interlocked.Read(ref _transferredBytes),
_totalBytes,
_numberOfFilesDownloaded,
_totalNumberOfFilesToDownload);
_request.OnRaiseDownloadDirectoryFailedEvent(eventArgs);
}

#endregion

internal DownloadDirectoryCommand(IAmazonS3 s3Client, TransferUtilityDownloadDirectoryRequest request, TransferUtilityConfig config, bool useMultipartDownload)
{
if (s3Client == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ internal partial class DownloadCommand : BaseCommand<TransferUtilityDownloadResp
{
public override async Task<TransferUtilityDownloadResponse> ExecuteAsync(CancellationToken cancellationToken)
{
ValidateRequest();

FireTransferInitiatedEvent();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved this to the top just to be consistent



ValidateRequest();

GetObjectRequest getRequest = ConvertToGetObjectRequest(this._request);

var maxRetries = _s3Client.Config.MaxErrorRetry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ public override async Task<TransferUtilityUploadResponse> ExecuteAsync(Cancellat
{
try
{
FireTransferInitiatedEvent();

if (AsyncThrottler != null)
{
await this.AsyncThrottler.WaitAsync(cancellationToken)
.ConfigureAwait(continueOnCapturedContext: false);
}

FireTransferInitiatedEvent();

var putRequest = ConstructRequest();
var response = await _s3Client.PutObjectAsync(putRequest, cancellationToken)
.ConfigureAwait(continueOnCapturedContext: false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,52 @@ internal DownloadDirectoryCommand(IAmazonS3 s3Client, TransferUtilityDownloadDir

public override async Task<TransferUtilityDownloadDirectoryResponse> ExecuteAsync(CancellationToken cancellationToken)
{
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Starting - DownloadFilesConcurrently={0}, UseMultipartDownload={1}, ConcurrentServiceRequests={2}",
DownloadFilesConcurrently, this._useMultipartDownload, this._config.ConcurrentServiceRequests);
try
{
FireTransferInitiatedEvent();

// Step 1: Validate and setup
ValidateRequest();
EnsureDirectoryExists(new DirectoryInfo(this._request.LocalDirectory));
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Starting - DownloadFilesConcurrently={0}, UseMultipartDownload={1}, ConcurrentServiceRequests={2}",
DownloadFilesConcurrently, this._useMultipartDownload, this._config.ConcurrentServiceRequests);

// Step 2: List S3 objects
var (s3Objects, prefixLength) = await ListS3ObjectsAsync(cancellationToken)
.ConfigureAwait(false);
// Step 1: Validate and setup
ValidateRequest();
EnsureDirectoryExists(new DirectoryInfo(this._request.LocalDirectory));

this._totalNumberOfFilesToDownload = s3Objects.Count;
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Found {0} total objects, TotalBytes={1}",
s3Objects.Count, this._totalBytes);
// Step 2: List S3 objects
var (s3Objects, prefixLength) = await ListS3ObjectsAsync(cancellationToken)
.ConfigureAwait(false);

// Step 3: Filter to actual files (exclude directory markers)
var objectsToDownload = FilterObjectsToDownload(s3Objects);
this._totalNumberOfFilesToDownload = s3Objects.Count;
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Found {0} total objects, TotalBytes={1}",
s3Objects.Count, this._totalBytes);

// Step 4: Setup resources and execute downloads
using (var resources = CreateDownloadResources(cancellationToken))
{
await ExecuteParallelDownloadsAsync(
objectsToDownload,
prefixLength,
resources,
cancellationToken)
.ConfigureAwait(false);
}
// Step 3: Filter to actual files (exclude directory markers)
var objectsToDownload = FilterObjectsToDownload(s3Objects);

// Step 5: Build response
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Completed - ObjectsDownloaded={0}, ObjectsFailed={1}",
_numberOfFilesDownloaded, _errors.Count);
// Step 4: Setup resources and execute downloads
using (var resources = CreateDownloadResources(cancellationToken))
{
await ExecuteParallelDownloadsAsync(
objectsToDownload,
prefixLength,
resources,
cancellationToken)
.ConfigureAwait(false);
}

// Step 5: Build response
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Completed - ObjectsDownloaded={0}, ObjectsFailed={1}",
_numberOfFilesDownloaded, _errors.Count);

return BuildResponse();
var response = BuildResponse();
FireTransferCompletedEvent(response);
return response;
}
catch
{
FireTransferFailedEvent();
throw;
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,97 @@ internal void OnRaiseObjectDownloadFailedEvent(ObjectDownloadFailedEventArgs arg
ObjectDownloadFailedEvent?.Invoke(this, args);
}

/// <summary>
/// Occurs when the download directory operation is initiated.
/// </summary>
/// <remarks>
/// <para>
/// The DownloadDirectoryInitiatedEvent is fired when the download directory operation begins.
/// The DownloadDirectoryInitiatedEventArgs contains the original request information.
/// </para>
/// <para>
/// Attach event handlers to this event if you are interested in receiving
/// DownloadDirectoryInitiatedEvent notifications.
/// </para>
/// </remarks>
/// <example>
/// private void downloadStarted(object sender, DownloadDirectoryInitiatedEventArgs args)
/// {
/// Console.WriteLine("Download directory started for bucket {0}", args.Request.BucketName);
/// }
/// </example>
public event EventHandler<DownloadDirectoryInitiatedEventArgs> DownloadDirectoryInitiatedEvent;

/// <summary>
/// Occurs when the download directory operation is completed.
/// </summary>
/// <remarks>
/// <para>
/// The DownloadDirectoryCompletedEvent is fired when the download directory operation is completed successfully.
/// The DownloadDirectoryCompletedEventArgs contains a snapshot of the transfer state at completion.
/// </para>
/// <para>
/// Attach event handlers to this event if you are interested in receiving
/// DownloadDirectoryCompletedEvent notifications.
/// </para>
/// </remarks>
/// <example>
/// private void downloadCompleted(object sender, DownloadDirectoryCompletedEventArgs args)
/// {
/// Console.WriteLine("Download directory completed with {0} files downloaded", args.TransferredFiles);
/// }
/// </example>
public event EventHandler<DownloadDirectoryCompletedEventArgs> DownloadDirectoryCompletedEvent;

/// <summary>
/// Occurs when the download directory operation fails.
/// </summary>
/// <remarks>
/// <para>
/// The DownloadDirectoryFailedEvent is fired when the download directory operation fails.
/// The DownloadDirectoryFailedEventArgs contains a snapshot of the transfer state at failure.
/// </para>
/// <para>
/// Attach event handlers to this event if you are interested in receiving
/// DownloadDirectoryFailedEvent notifications.
/// </para>
/// </remarks>
/// <example>
/// private void downloadFailed(object sender, DownloadDirectoryFailedEventArgs args)
/// {
/// Console.WriteLine("Download directory failed with {0} files downloaded out of {1} total",
/// args.TransferredFiles, args.TotalFiles);
/// }
/// </example>
public event EventHandler<DownloadDirectoryFailedEventArgs> DownloadDirectoryFailedEvent;

/// <summary>
/// Raises the DownloadDirectoryInitiatedEvent.
/// </summary>
/// <param name="args">DownloadDirectoryInitiatedEventArgs args</param>
internal void OnRaiseDownloadDirectoryInitiatedEvent(DownloadDirectoryInitiatedEventArgs args)
{
DownloadDirectoryInitiatedEvent?.Invoke(this, args);
}

/// <summary>
/// Raises the DownloadDirectoryCompletedEvent.
/// </summary>
/// <param name="args">DownloadDirectoryCompletedEventArgs args</param>
internal void OnRaiseDownloadDirectoryCompletedEvent(DownloadDirectoryCompletedEventArgs args)
{
DownloadDirectoryCompletedEvent?.Invoke(this, args);
}

/// <summary>
/// Raises the DownloadDirectoryFailedEvent.
/// </summary>
/// <param name="args">DownloadDirectoryFailedEventArgs args</param>
internal void OnRaiseDownloadDirectoryFailedEvent(DownloadDirectoryFailedEventArgs args)
{
DownloadDirectoryFailedEvent?.Invoke(this, args);
}

/// <summary>
/// Gets or sets the name of the bucket.
/// </summary>
Expand Down Expand Up @@ -668,4 +759,133 @@ internal ObjectDownloadFailedEventArgs(
/// </value>
public Exception Exception { get; private set; }
}
}

/// <summary>
/// Provides data for <see cref="TransferUtilityDownloadDirectoryRequest.DownloadDirectoryInitiatedEvent"/>
/// which is raised when a download directory operation is initiated.
/// </summary>
public class DownloadDirectoryInitiatedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the DownloadDirectoryInitiatedEventArgs class.
/// </summary>
/// <param name="request">The transfer request</param>
internal DownloadDirectoryInitiatedEventArgs(TransferUtilityDownloadDirectoryRequest request)
{
Request = request;
}

/// <summary>
/// Gets the request associated with this transfer operation.
/// </summary>
public TransferUtilityDownloadDirectoryRequest Request { get; private set; }
}

/// <summary>
/// Provides data for <see cref="TransferUtilityDownloadDirectoryRequest.DownloadDirectoryCompletedEvent"/>
/// which is raised when a download directory operation is completed successfully.
/// </summary>
public class DownloadDirectoryCompletedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the DownloadDirectoryCompletedEventArgs class.
/// </summary>
/// <param name="request">The transfer request</param>
/// <param name="response">The transfer response</param>
/// <param name="transferredBytes">The total number of bytes that have been transferred so far</param>
/// <param name="totalBytes">The total size for all objects</param>
/// <param name="transferredFiles">The total number of files that have been transferred so far</param>
/// <param name="totalFiles">The total number of files</param>
internal DownloadDirectoryCompletedEventArgs(TransferUtilityDownloadDirectoryRequest request,
TransferUtilityDownloadDirectoryResponse response, long transferredBytes, long totalBytes,
long transferredFiles, long totalFiles)
{
Request = request;
Response = response;
TransferredBytes = transferredBytes;
TotalBytes = totalBytes;
TransferredFiles = transferredFiles;
TotalFiles = totalFiles;
}

/// <summary>
/// Gets the request associated with this transfer operation.
/// </summary>
public TransferUtilityDownloadDirectoryRequest Request { get; private set; }

/// <summary>
/// Gets the response from the transfer operation.
/// </summary>
public TransferUtilityDownloadDirectoryResponse Response { get; private set; }

/// <summary>
/// Gets the total number of bytes that have been transferred so far.
/// </summary>
public long TransferredBytes { get; private set; }

/// <summary>
/// Gets the total size for all objects. Returns -1 if unknown.
/// </summary>
public long TotalBytes { get; private set; }

/// <summary>
/// Gets the total number of files that have been transferred so far.
/// </summary>
public long TransferredFiles { get; private set; }

/// <summary>
/// Gets the total number of files. Returns -1 if unknown.
/// </summary>
public long TotalFiles { get; private set; }
}

/// <summary>
/// Provides data for <see cref="TransferUtilityDownloadDirectoryRequest.DownloadDirectoryFailedEvent"/>
/// which is raised when a download directory operation fails.
/// </summary>
public class DownloadDirectoryFailedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the DownloadDirectoryFailedEventArgs class.
/// </summary>
/// <param name="request">The transfer request</param>
/// <param name="transferredBytes">The total number of bytes that have been transferred so far</param>
/// <param name="totalBytes">The total size for all objects</param>
/// <param name="transferredFiles">The total number of files that have been transferred so far</param>
/// <param name="totalFiles">The total number of files</param>
internal DownloadDirectoryFailedEventArgs(TransferUtilityDownloadDirectoryRequest request,
long transferredBytes, long totalBytes, long transferredFiles, long totalFiles)
{
Request = request;
TransferredBytes = transferredBytes;
TotalBytes = totalBytes;
TransferredFiles = transferredFiles;
TotalFiles = totalFiles;
}

/// <summary>
/// Gets the request associated with this transfer operation.
/// </summary>
public TransferUtilityDownloadDirectoryRequest Request { get; private set; }

/// <summary>
/// Gets the total number of bytes that have been transferred so far.
/// </summary>
public long TransferredBytes { get; private set; }

/// <summary>
/// Gets the total size for all objects. Returns -1 if unknown.
/// </summary>
public long TotalBytes { get; private set; }

/// <summary>
/// Gets the total number of files that have been transferred so far.
/// </summary>
public long TransferredFiles { get; private set; }

/// <summary>
/// Gets the total number of files. Returns -1 if unknown.
/// </summary>
public long TotalFiles { get; private set; }
}
}
Loading