@@ -33,12 +33,17 @@ internal partial class DownloadCommand : BaseCommand<TransferUtilityDownloadResp
3333 public override async Task < TransferUtilityDownloadResponse > ExecuteAsync ( CancellationToken cancellationToken )
3434 {
3535 ValidateRequest ( ) ;
36+
37+ FireTransferInitiatedEvent ( ) ;
38+
3639 GetObjectRequest getRequest = ConvertToGetObjectRequest ( this . _request ) ;
3740
3841 var maxRetries = _s3Client . Config . MaxErrorRetry ;
3942 var retries = 0 ;
4043 bool shouldRetry = false ;
4144 string mostRecentETag = null ;
45+ TransferUtilityDownloadResponse lastSuccessfulMappedResponse = null ;
46+ long ? totalBytesFromResponse = null ; // Track total bytes once we have response headers
4247 do
4348 {
4449 shouldRetry = false ;
@@ -54,12 +59,16 @@ public override async Task<TransferUtilityDownloadResponse> ExecuteAsync(Cancell
5459 using ( var response = await this . _s3Client . GetObjectAsync ( getRequest , cancellationToken )
5560 . ConfigureAwait ( continueOnCapturedContext : false ) )
5661 {
62+ // Capture total bytes from response headers as soon as we get them
63+ totalBytesFromResponse = response . ContentLength ;
64+
5765 if ( ! string . IsNullOrEmpty ( mostRecentETag ) && ! string . Equals ( mostRecentETag , response . ETag ) )
5866 {
5967 //if the eTag changed, we need to retry from the start of the file
6068 mostRecentETag = response . ETag ;
6169 getRequest . ByteRange = null ;
6270 retries = 0 ;
71+ Interlocked . Exchange ( ref _totalTransferredBytes , 0 ) ;
6372 shouldRetry = true ;
6473 WaitBeforeRetry ( retries ) ;
6574 continue ;
@@ -101,6 +110,8 @@ await response.WriteResponseStreamToFileAsync(this._request.FilePath, false, can
101110 await response . WriteResponseStreamToFileAsync ( this . _request . FilePath , true , cancellationToken )
102111 . ConfigureAwait ( continueOnCapturedContext : false ) ;
103112 }
113+
114+ lastSuccessfulMappedResponse = ResponseMapper . MapGetObjectResponse ( response ) ;
104115 }
105116 }
106117 catch ( Exception exception )
@@ -109,6 +120,9 @@ await response.WriteResponseStreamToFileAsync(this._request.FilePath, true, canc
109120 shouldRetry = HandleExceptionForHttpClient ( exception , retries , maxRetries ) ;
110121 if ( ! shouldRetry )
111122 {
123+ // Pass total bytes if we have them from response headers, otherwise -1 for unknown
124+ FireTransferFailedEvent ( this . _request . FilePath , Interlocked . Read ( ref _totalTransferredBytes ) , totalBytesFromResponse ?? - 1 ) ;
125+
112126 if ( exception is IOException )
113127 {
114128 throw ;
@@ -131,8 +145,9 @@ await response.WriteResponseStreamToFileAsync(this._request.FilePath, true, canc
131145 WaitBeforeRetry ( retries ) ;
132146 } while ( shouldRetry ) ;
133147
134- // TODO map and return response
135- return new TransferUtilityDownloadResponse ( ) ;
148+ FireTransferCompletedEvent ( lastSuccessfulMappedResponse , this . _request . FilePath , Interlocked . Read ( ref _totalTransferredBytes ) , totalBytesFromResponse ?? - 1 ) ;
149+
150+ return lastSuccessfulMappedResponse ;
136151 }
137152
138153 private static bool HandleExceptionForHttpClient ( Exception exception , int retries , int maxRetries )
0 commit comments