Skip to content

Commit e84bfc2

Browse files
committed
DownloadDirectoryProgress events
1 parent 0c0d54d commit e84bfc2

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
@@ -49,6 +49,39 @@ internal partial class DownloadDirectoryCommand : BaseCommand<TransferUtilityDow
4949
long _transferredBytes;
5050
string _currentFile;
5151

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

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

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

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

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

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

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

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

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

88100
/// <summary>

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

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

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

0 commit comments

Comments
 (0)