CB-8095 Rewrite upload method to support progress events properly * Uses backgroundUploader class instead of XHR * Returns proper response body in case of error
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/970c1cfb Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/970c1cfb Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/970c1cfb Branch: refs/heads/CB-8095 Commit: 970c1cfb4921e4e2a9ec278556c08d759b54bca4 Parents: 6fee835 Author: Vladimir Kotikov <[email protected]> Authored: Thu Nov 27 18:49:13 2014 +0300 Committer: Vladimir Kotikov <[email protected]> Committed: Thu Nov 27 18:49:13 2014 +0300 ---------------------------------------------------------------------- src/windows/FileTransferProxy.js | 167 +++++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/970c1cfb/src/windows/FileTransferProxy.js ---------------------------------------------------------------------- diff --git a/src/windows/FileTransferProxy.js b/src/windows/FileTransferProxy.js index 0eeef90..7a7e3ae 100644 --- a/src/windows/FileTransferProxy.js +++ b/src/windows/FileTransferProxy.js @@ -103,54 +103,137 @@ exec(win, fail, 'FileTransfer', 'upload', mimeType = storageFile.contentType; } - storageFile.openAsync(Windows.Storage.FileAccessMode.read).then(function (stream) { - - // check if upload isn't already cancelled - var uploadOp = fileTransferOps[uploadId]; - if (uploadOp && uploadOp.state == FileTransferOperation.CANCELLED) { - // Here we should call errorCB with ABORT_ERR error - errorCallback && errorCallback(new FileTransferError(FileTransferError.ABORT_ERR, filePath, server)); - return; - } - - var blob = MSApp.createBlobFromRandomAccessStream(mimeType, stream); + // check if download isn't already cancelled + var uploadOp = fileTransferOps[uploadId]; + if (uploadOp && uploadOp.state === FileTransferOperation.CANCELLED) { + // Here we should call errorCB with ABORT_ERR error + errorCallback && errorCallback(new FileTransferError(FileTransferError.ABORT_ERR, nativePathToCordova(filePath), server)); + return; + } - var formData = new FormData(); - formData.append(fileKey, blob, fileName); - // add params - for(var key in params) { - formData.append(key,params[key]); + // setting request headers for uploader + var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader(); + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + uploader.setRequestHeader(header, headers[header]); } + } - var uploadOperation; - try { - // Create XHR promise for uploading data to server - uploadOperation = WinJS.xhr({ type: "POST", url: server, data: formData, headers: headers }); - fileTransferOps[uploadId].promise = uploadOperation; - } catch (e) { - // it will fail if URL is malformed, so we handle this situation - errorCallback && errorCallback(new FileTransferError(FileTransferError.INVALID_URL_ERR, filePath, server, null, null, e)); - return; + // adding params supplied to request payload + var transferParts = []; + for (var key in params) { + if (params.hasOwnProperty(key)) { + var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(); + contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\""); + contentPart.setText(params[key]); + transferParts.push(contentPart); } + } - uploadOperation.then(function (response) { - storageFile.getBasicPropertiesAsync().done(function(basicProperties) { - var ftResult = new FileUploadResult(basicProperties.size, response.status, response.responseText); - successCallback && successCallback(ftResult); - }); - }, function(err) { - if ('status' in err) { - errorCallback && errorCallback(new FileTransferError(FileTransferError.CONNECTION_ERR, filePath, server, err.status, err.responseText, err)); - } else { - errorCallback && errorCallback(new FileTransferError(FileTransferError.INVALID_URL_ERR, filePath, server, null, null, err)); + // Adding file to upload to request payload + var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName); + fileToUploadPart.setFile(storageFile); + transferParts.push(fileToUploadPart); + + // create download object. This will throw an exception if URL is malformed + var uri = new Windows.Foundation.Uri(server); + try { + uploader.createUploadAsync(uri, transferParts).then( + function (upload) { + + // update internal TransferOperation object with newly created promise + var uploadOperation = upload.startAsync(); + fileTransferOps[uploadId].promise = uploadOperation; + + uploadOperation.then( + function (result) { + + // Update TransferOperation object with new state, delete promise property + // since it is not actual anymore + var currentUploadOp = fileTransferOps[uploadId]; + if (currentUploadOp) { + currentUploadOp.state = FileTransferOperation.DONE; + currentUploadOp.promise = null; + } + + var response = result.getResponseInformation(); + // creating a data reader, attached to response stream to get server's response + var reader = new Windows.Storage.Streams.DataReader(result.getResultStreamAt(0)); + reader.loadAsync(result.progress.bytesReceived).then(function(size) { + var responseText = reader.readString(size); + var ftResult = new FileUploadResult(size, response.statusCode, responseText); + successCallback && successCallback(ftResult); + reader.close(); + }); + }, + function (error) { + + var source = nativePathToCordova(filePath); + + // Handle download error here. + // Wrap this routines into promise due to some async methods + var getTransferError = new WinJS.Promise(function(resolve) { + if (error.message === 'Canceled') { + // If download was cancelled, message property will be specified + resolve(new FileTransferError(FileTransferError.ABORT_ERR, source, server, null, null, error)); + } else { + // in the other way, try to get response property + var response = upload.getResponseInformation(); + if (!response) { + resolve(new FileTransferError(FileTransferError.CONNECTION_ERR, source, server)); + } else { + var reader = new Windows.Storage.Streams.DataReader(upload.getResultStreamAt(0)); + reader.loadAsync(upload.progress.bytesReceived).then(function (size) { + var responseText = reader.readString(size); + resolve(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, source, server, response.statusCode, responseText, error)); + reader.close(); + }); + } + } + }); + + // Update TransferOperation object with new state, delete promise property + // since it is not actual anymore + var currentUploadOp = fileTransferOps[uploadId]; + if (currentUploadOp) { + currentUploadOp.state = FileTransferOperation.CANCELLED; + currentUploadOp.promise = null; + } + + // Cleanup, remove incompleted file + getTransferError.then(function(transferError) { + storageFile.deleteAsync().then(function() { + errorCallback && errorCallback(transferError); + }); + }); + + + }, + function (evt) { + + var progressEvent = new ProgressEvent('progress', { + loaded: evt.progress.bytesSent, + total: evt.progress.totalBytesToSend, + target: evt.resultFile + }); + progressEvent.lengthComputable = true; + + successCallback && successCallback(progressEvent, { keepCallback: true }); + } + ); + + }, + function (err) { + var errorObj = new FileTransferError(FileTransferError.INVALID_URL_ERR); + errorObj.exception = err; + errorCallback && errorCallback(errorObj); } - }, function(evt) { - // progress event handler, calls successCallback with empty ProgressEvent - // We can't specify ProgressEvent data here since evt not provides any helpful information - var progressEvent = new ProgressEvent('progress'); - successCallback && successCallback(progressEvent, { keepCallback: true }); - }); - }); + ); + } catch (e) { + errorCallback && errorCallback(new FileTransferError(FileTransferError.INVALID_URL_ERR)); + } + + }, function(err) { errorCallback && errorCallback(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, server, server, null, null, err)); }); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
