Matthias Mullie has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/363841 )

Change subject: Make chunkedUpload match upload behavior
......................................................................

Make chunkedUpload match upload behavior

.upload will upload the entire file, then reject the promise
if it has warnings.
This also happened in chunkedUpload, but a warning could already
be present after uploading only 1 chunk & that rejection would
cause the entire chain of chunks to stop.
Instead, it'll now keep uploading all chunks & then reject with
the complete upload data.

Also fixed how abort is dealt with when retrying because of
network issues.

Change-Id: I8ecef2271359a9505c8c5fa22883b0df55e9e914
---
M resources/src/mediawiki/api/upload.js
1 file changed, 76 insertions(+), 26 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/41/363841/1

diff --git a/resources/src/mediawiki/api/upload.js 
b/resources/src/mediawiki/api/upload.js
index 9814142..42778ee 100644
--- a/resources/src/mediawiki/api/upload.js
+++ b/resources/src/mediawiki/api/upload.js
@@ -391,7 +391,7 @@
                 * @return {jQuery.Promise}
                 */
                uploadChunk: function ( file, data, start, end, filekey, 
retries ) {
-                       var upload, retry,
+                       var upload,
                                api = this,
                                chunk = this.slice( file, start, end );
 
@@ -400,22 +400,6 @@
                        // In such case, it could be useful to try again: a 
network hickup
                        // doesn't necessarily have to result in upload 
failure...
                        retries = retries === undefined ? 1 : retries;
-                       retry = function ( code, result ) {
-                               var deferred = $.Deferred(),
-                                       callback = function () {
-                                               api.uploadChunk( file, data, 
start, end, filekey, retries - 1 )
-                                                       .then( 
deferred.resolve, deferred.reject );
-                                       };
-
-                               // Don't retry if the request failed because we 
aborted it (or
-                               // if it's another kind of request failure)
-                               if ( code !== 'http' || result.textStatus === 
'abort' ) {
-                                       return deferred.reject( code, result );
-                               }
-
-                               setTimeout( callback, 1000 );
-                               return deferred.promise();
-                       };
 
                        data.filesize = file.size;
                        data.chunk = chunk;
@@ -429,16 +413,82 @@
 
                        upload = this.uploadWithFormData( file, data );
                        return upload.then(
-                                       null,
-                                       // If the call fails, we may want to 
try again...
-                                       retries === 0 ? null : retry,
-                                       function ( fraction ) {
-                                               // Since we're only uploading 
small parts of a file, we
-                                               // need to adjust the reported 
progress to reflect where
-                                               // we actually are in the 
combined upload
-                                               return ( start + fraction * ( 
end - start ) ) / file.size;
+                               null,
+                               function ( code, result ) {
+                                       var retry;
+
+                                       // uploadWithFormData will reject 
uploads with warnings, but
+                                       // these warnings could be "harmless" 
or recovered from
+                                       // (e.g. exists-normalized, when it'll 
be renamed later)
+                                       // In the case of (only) a warning, we 
still want to
+                                       // continue the chunked upload until it 
completes: then
+                                       // reject it - at least it's been fully 
uploaded by then and
+                                       // failure handlers have a complete 
result object (including
+                                       // possibly more warnings, e.g. 
duplicate)
+                                       // This matches .upload, which also 
completes the upload.
+                                       if ( result.upload && 
result.upload.warnings && code in result.upload.warnings ) {
+                                               if ( end === file.size ) {
+                                                       // uploaded last chunk 
= reject with result data
+                                                       return 
$.Deferred().reject( code, result );
+                                               } else {
+                                                       // still uploading 
chunks = resolve to keep going
+                                                       return 
$.Deferred().resolve( result );
+                                               }
                                        }
-                               ).promise( { abort: upload.abort } );
+
+                                       if ( retries === 0 ) {
+                                               return $.Deferred().reject( 
code, result );
+                                       }
+
+                                       // If the call flat out failed, we may 
want to try again...
+                                       retry = api.uploadChunk.bind( this, 
file, data, start, end, filekey, retries - 1 );
+                                       return api.retry( code, result, retry );
+                               },
+                               function ( fraction ) {
+                                       // Since we're only uploading small 
parts of a file, we
+                                       // need to adjust the reported progress 
to reflect where
+                                       // we actually are in the combined 
upload
+                                       return ( start + fraction * ( end - 
start ) ) / file.size;
+                               }
+                       ).promise( { abort: upload.abort } );
+               },
+
+               /**
+                * Launch the upload anew if it failed because of network 
issues.
+                *
+                * @private
+                * @param {string} code Error code
+                * @param {Object} result API result
+                * @param {function} callable
+                * @return {$.Promise}
+                */
+               retry: function ( code, result, callable ) {
+                       var uploadPromise,
+                               retryTimer,
+                               deferred = $.Deferred(),
+                               // Wrap around the callable, so that once it 
completes, it'll
+                               // resolve/reject the promise we'll return
+                               retry = function () {
+                                       uploadPromise = callable();
+                                       uploadPromise.then( deferred.resolve, 
deferred.reject );
+                               };
+
+                       // Don't retry if the request failed because we aborted 
it (or if
+                       // it's another kind of request failure)
+                       if ( code !== 'http' || result.textStatus === 'abort' ) 
{
+                               return deferred.reject( code, result );
+                       }
+
+                       retryTimer = setTimeout( retry, 1000 );
+                       return deferred.promise( { abort: function () {
+                               // Clear the scheduled upload, or abort if 
already in flight
+                               if ( retryTimer ) {
+                                       clearTimeout( retryTimer );
+                               }
+                               if ( uploadPromise.abort ) {
+                                       uploadPromise.abort();
+                               }
+                       } } );
                },
 
                /**

-- 
To view, visit https://gerrit.wikimedia.org/r/363841
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8ecef2271359a9505c8c5fa22883b0df55e9e914
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Matthias Mullie <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to