Skip to content

Commit 7765303

Browse files
committed
DownloadDirectoryProgress events
1 parent 6a31b25 commit 7765303

File tree

6 files changed

+640
-33
lines changed

6 files changed

+640
-33
lines changed

sdk/src/Services/S3/Custom/Transfer/Internal/DownloadDirectoryCommand.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,39 @@ internal partial class DownloadDirectoryCommand : BaseCommand<TransferUtilityDow
4848
long _transferredBytes;
4949
string _currentFile;
5050

51+
#region Event Firing Methods
52+
53+
private void FireTransferInitiatedEvent()
54+
{
55+
var transferInitiatedEventArgs = new DownloadDirectoryInitiatedEventArgs(_request);
56+
_request.OnRaiseDownloadDirectoryInitiatedEvent(transferInitiatedEventArgs);
57+
}
58+
59+
private void FireTransferCompletedEvent(TransferUtilityDownloadDirectoryResponse response)
60+
{
61+
var transferCompletedEventArgs = new DownloadDirectoryCompletedEventArgs(
62+
_request,
63+
response,
64+
Interlocked.Read(ref _transferredBytes),
65+
_totalBytes,
66+
_numberOfFilesDownloaded,
67+
_totalNumberOfFilesToDownload);
68+
_request.OnRaiseDownloadDirectoryCompletedEvent(transferCompletedEventArgs);
69+
}
70+
71+
private void FireTransferFailedEvent()
72+
{
73+
var eventArgs = new DownloadDirectoryFailedEventArgs(
74+
_request,
75+
Interlocked.Read(ref _transferredBytes),
76+
_totalBytes,
77+
_numberOfFilesDownloaded,
78+
_totalNumberOfFilesToDownload);
79+
_request.OnRaiseDownloadDirectoryFailedEvent(eventArgs);
80+
}
81+
82+
#endregion
83+
5184
internal DownloadDirectoryCommand(IAmazonS3 s3Client, TransferUtilityDownloadDirectoryRequest request, TransferUtilityConfig config, bool useMultipartDownload)
5285
{
5386
if (s3Client == null)

sdk/src/Services/S3/Custom/Transfer/Internal/_async/DownloadCommand.async.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ internal partial class DownloadCommand : BaseCommand<TransferUtilityDownloadResp
3232
{
3333
public override async Task<TransferUtilityDownloadResponse> ExecuteAsync(CancellationToken cancellationToken)
3434
{
35-
ValidateRequest();
36-
3735
FireTransferInitiatedEvent();
38-
36+
37+
ValidateRequest();
38+
3939
GetObjectRequest getRequest = ConvertToGetObjectRequest(this._request);
4040

4141
var maxRetries = _s3Client.Config.MaxErrorRetry;

sdk/src/Services/S3/Custom/Transfer/Internal/_async/SimpleUploadCommand.async.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ public override async Task<TransferUtilityUploadResponse> ExecuteAsync(Cancellat
3232
{
3333
try
3434
{
35+
FireTransferInitiatedEvent();
36+
3537
if (AsyncThrottler != null)
3638
{
3739
await this.AsyncThrottler.WaitAsync(cancellationToken)
3840
.ConfigureAwait(continueOnCapturedContext: false);
3941
}
4042

41-
FireTransferInitiatedEvent();
42-
4343
var putRequest = ConstructRequest();
4444
var response = await _s3Client.PutObjectAsync(putRequest, cancellationToken)
4545
.ConfigureAwait(continueOnCapturedContext: false);

sdk/src/Services/S3/Custom/Transfer/Internal/_bcl+netstandard/DownloadDirectoryCommand.cs

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,40 +48,52 @@ internal DownloadDirectoryCommand(IAmazonS3 s3Client, TransferUtilityDownloadDir
4848

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

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

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

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

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

69-
// Step 4: Setup resources and execute downloads
70-
using (var resources = CreateDownloadResources(cancellationToken))
71-
{
72-
await ExecuteParallelDownloadsAsync(
73-
objectsToDownload,
74-
prefixLength,
75-
resources,
76-
cancellationToken)
77-
.ConfigureAwait(false);
78-
}
70+
// Step 3: Filter to actual files (exclude directory markers)
71+
var objectsToDownload = FilterObjectsToDownload(s3Objects);
7972

80-
// Step 5: Build response
81-
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Completed - ObjectsDownloaded={0}, ObjectsFailed={1}",
82-
_numberOfFilesDownloaded, _errors.Count);
73+
// Step 4: Setup resources and execute downloads
74+
using (var resources = CreateDownloadResources(cancellationToken))
75+
{
76+
await ExecuteParallelDownloadsAsync(
77+
objectsToDownload,
78+
prefixLength,
79+
resources,
80+
cancellationToken)
81+
.ConfigureAwait(false);
82+
}
83+
84+
// Step 5: Build response
85+
Logger.DebugFormat("DownloadDirectoryCommand.ExecuteAsync: Completed - ObjectsDownloaded={0}, ObjectsFailed={1}",
86+
_numberOfFilesDownloaded, _errors.Count);
8387

84-
return BuildResponse();
88+
var response = BuildResponse();
89+
FireTransferCompletedEvent(response);
90+
return response;
91+
}
92+
catch
93+
{
94+
FireTransferFailedEvent();
95+
throw;
96+
}
8597
}
8698

8799
/// <summary>

sdk/src/Services/S3/Custom/Transfer/TransferUtilityDownloadDirectoryRequest.cs

Lines changed: 221 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,97 @@ internal void OnRaiseObjectDownloadFailedEvent(ObjectDownloadFailedEventArgs arg
9696
ObjectDownloadFailedEvent?.Invoke(this, args);
9797
}
9898

99+
/// <summary>
100+
/// Occurs when the download directory operation is initiated.
101+
/// </summary>
102+
/// <remarks>
103+
/// <para>
104+
/// The DownloadDirectoryInitiatedEvent is fired when the download directory operation begins.
105+
/// The DownloadDirectoryInitiatedEventArgs contains the original request information.
106+
/// </para>
107+
/// <para>
108+
/// Attach event handlers to this event if you are interested in receiving
109+
/// DownloadDirectoryInitiatedEvent notifications.
110+
/// </para>
111+
/// </remarks>
112+
/// <example>
113+
/// private void downloadStarted(object sender, DownloadDirectoryInitiatedEventArgs args)
114+
/// {
115+
/// Console.WriteLine("Download directory started for bucket {0}", args.Request.BucketName);
116+
/// }
117+
/// </example>
118+
public event EventHandler<DownloadDirectoryInitiatedEventArgs> DownloadDirectoryInitiatedEvent;
119+
120+
/// <summary>
121+
/// Occurs when the download directory operation is completed.
122+
/// </summary>
123+
/// <remarks>
124+
/// <para>
125+
/// The DownloadDirectoryCompletedEvent is fired when the download directory operation is completed successfully.
126+
/// The DownloadDirectoryCompletedEventArgs contains a snapshot of the transfer state at completion.
127+
/// </para>
128+
/// <para>
129+
/// Attach event handlers to this event if you are interested in receiving
130+
/// DownloadDirectoryCompletedEvent notifications.
131+
/// </para>
132+
/// </remarks>
133+
/// <example>
134+
/// private void downloadCompleted(object sender, DownloadDirectoryCompletedEventArgs args)
135+
/// {
136+
/// Console.WriteLine("Download directory completed with {0} files downloaded", args.TransferredFiles);
137+
/// }
138+
/// </example>
139+
public event EventHandler<DownloadDirectoryCompletedEventArgs> DownloadDirectoryCompletedEvent;
140+
141+
/// <summary>
142+
/// Occurs when the download directory operation fails.
143+
/// </summary>
144+
/// <remarks>
145+
/// <para>
146+
/// The DownloadDirectoryFailedEvent is fired when the download directory operation fails.
147+
/// The DownloadDirectoryFailedEventArgs contains a snapshot of the transfer state at failure.
148+
/// </para>
149+
/// <para>
150+
/// Attach event handlers to this event if you are interested in receiving
151+
/// DownloadDirectoryFailedEvent notifications.
152+
/// </para>
153+
/// </remarks>
154+
/// <example>
155+
/// private void downloadFailed(object sender, DownloadDirectoryFailedEventArgs args)
156+
/// {
157+
/// Console.WriteLine("Download directory failed with {0} files downloaded out of {1} total",
158+
/// args.TransferredFiles, args.TotalFiles);
159+
/// }
160+
/// </example>
161+
public event EventHandler<DownloadDirectoryFailedEventArgs> DownloadDirectoryFailedEvent;
162+
163+
/// <summary>
164+
/// Raises the DownloadDirectoryInitiatedEvent.
165+
/// </summary>
166+
/// <param name="args">DownloadDirectoryInitiatedEventArgs args</param>
167+
internal void OnRaiseDownloadDirectoryInitiatedEvent(DownloadDirectoryInitiatedEventArgs args)
168+
{
169+
DownloadDirectoryInitiatedEvent?.Invoke(this, args);
170+
}
171+
172+
/// <summary>
173+
/// Raises the DownloadDirectoryCompletedEvent.
174+
/// </summary>
175+
/// <param name="args">DownloadDirectoryCompletedEventArgs args</param>
176+
internal void OnRaiseDownloadDirectoryCompletedEvent(DownloadDirectoryCompletedEventArgs args)
177+
{
178+
DownloadDirectoryCompletedEvent?.Invoke(this, args);
179+
}
180+
181+
/// <summary>
182+
/// Raises the DownloadDirectoryFailedEvent.
183+
/// </summary>
184+
/// <param name="args">DownloadDirectoryFailedEventArgs args</param>
185+
internal void OnRaiseDownloadDirectoryFailedEvent(DownloadDirectoryFailedEventArgs args)
186+
{
187+
DownloadDirectoryFailedEvent?.Invoke(this, args);
188+
}
189+
99190
/// <summary>
100191
/// Gets or sets the name of the bucket.
101192
/// </summary>
@@ -668,4 +759,133 @@ internal ObjectDownloadFailedEventArgs(
668759
/// </value>
669760
public Exception Exception { get; private set; }
670761
}
671-
}
762+
763+
/// <summary>
764+
/// Provides data for <see cref="TransferUtilityDownloadDirectoryRequest.DownloadDirectoryInitiatedEvent"/>
765+
/// which is raised when a download directory operation is initiated.
766+
/// </summary>
767+
public class DownloadDirectoryInitiatedEventArgs : EventArgs
768+
{
769+
/// <summary>
770+
/// Initializes a new instance of the DownloadDirectoryInitiatedEventArgs class.
771+
/// </summary>
772+
/// <param name="request">The transfer request</param>
773+
internal DownloadDirectoryInitiatedEventArgs(TransferUtilityDownloadDirectoryRequest request)
774+
{
775+
Request = request;
776+
}
777+
778+
/// <summary>
779+
/// Gets the request associated with this transfer operation.
780+
/// </summary>
781+
public TransferUtilityDownloadDirectoryRequest Request { get; private set; }
782+
}
783+
784+
/// <summary>
785+
/// Provides data for <see cref="TransferUtilityDownloadDirectoryRequest.DownloadDirectoryCompletedEvent"/>
786+
/// which is raised when a download directory operation is completed successfully.
787+
/// </summary>
788+
public class DownloadDirectoryCompletedEventArgs : EventArgs
789+
{
790+
/// <summary>
791+
/// Initializes a new instance of the DownloadDirectoryCompletedEventArgs class.
792+
/// </summary>
793+
/// <param name="request">The transfer request</param>
794+
/// <param name="response">The transfer response</param>
795+
/// <param name="transferredBytes">The total number of bytes that have been transferred so far</param>
796+
/// <param name="totalBytes">The total size for all objects</param>
797+
/// <param name="transferredFiles">The total number of files that have been transferred so far</param>
798+
/// <param name="totalFiles">The total number of files</param>
799+
internal DownloadDirectoryCompletedEventArgs(TransferUtilityDownloadDirectoryRequest request,
800+
TransferUtilityDownloadDirectoryResponse response, long transferredBytes, long totalBytes,
801+
long transferredFiles, long totalFiles)
802+
{
803+
Request = request;
804+
Response = response;
805+
TransferredBytes = transferredBytes;
806+
TotalBytes = totalBytes;
807+
TransferredFiles = transferredFiles;
808+
TotalFiles = totalFiles;
809+
}
810+
811+
/// <summary>
812+
/// Gets the request associated with this transfer operation.
813+
/// </summary>
814+
public TransferUtilityDownloadDirectoryRequest Request { get; private set; }
815+
816+
/// <summary>
817+
/// Gets the response from the transfer operation.
818+
/// </summary>
819+
public TransferUtilityDownloadDirectoryResponse Response { get; private set; }
820+
821+
/// <summary>
822+
/// Gets the total number of bytes that have been transferred so far.
823+
/// </summary>
824+
public long TransferredBytes { get; private set; }
825+
826+
/// <summary>
827+
/// Gets the total size for all objects. Returns -1 if unknown.
828+
/// </summary>
829+
public long TotalBytes { get; private set; }
830+
831+
/// <summary>
832+
/// Gets the total number of files that have been transferred so far.
833+
/// </summary>
834+
public long TransferredFiles { get; private set; }
835+
836+
/// <summary>
837+
/// Gets the total number of files. Returns -1 if unknown.
838+
/// </summary>
839+
public long TotalFiles { get; private set; }
840+
}
841+
842+
/// <summary>
843+
/// Provides data for <see cref="TransferUtilityDownloadDirectoryRequest.DownloadDirectoryFailedEvent"/>
844+
/// which is raised when a download directory operation fails.
845+
/// </summary>
846+
public class DownloadDirectoryFailedEventArgs : EventArgs
847+
{
848+
/// <summary>
849+
/// Initializes a new instance of the DownloadDirectoryFailedEventArgs class.
850+
/// </summary>
851+
/// <param name="request">The transfer request</param>
852+
/// <param name="transferredBytes">The total number of bytes that have been transferred so far</param>
853+
/// <param name="totalBytes">The total size for all objects</param>
854+
/// <param name="transferredFiles">The total number of files that have been transferred so far</param>
855+
/// <param name="totalFiles">The total number of files</param>
856+
internal DownloadDirectoryFailedEventArgs(TransferUtilityDownloadDirectoryRequest request,
857+
long transferredBytes, long totalBytes, long transferredFiles, long totalFiles)
858+
{
859+
Request = request;
860+
TransferredBytes = transferredBytes;
861+
TotalBytes = totalBytes;
862+
TransferredFiles = transferredFiles;
863+
TotalFiles = totalFiles;
864+
}
865+
866+
/// <summary>
867+
/// Gets the request associated with this transfer operation.
868+
/// </summary>
869+
public TransferUtilityDownloadDirectoryRequest Request { get; private set; }
870+
871+
/// <summary>
872+
/// Gets the total number of bytes that have been transferred so far.
873+
/// </summary>
874+
public long TransferredBytes { get; private set; }
875+
876+
/// <summary>
877+
/// Gets the total size for all objects. Returns -1 if unknown.
878+
/// </summary>
879+
public long TotalBytes { get; private set; }
880+
881+
/// <summary>
882+
/// Gets the total number of files that have been transferred so far.
883+
/// </summary>
884+
public long TransferredFiles { get; private set; }
885+
886+
/// <summary>
887+
/// Gets the total number of files. Returns -1 if unknown.
888+
/// </summary>
889+
public long TotalFiles { get; private set; }
890+
}
891+
}

0 commit comments

Comments
 (0)