mirror of
https://github.com/apache/cordova-plugin-file-transfer.git
synced 2026-04-28 00:02:49 +08:00
CB-8095 Rewrite upload method to support progress events properly
* Uses backgroundUploader class instead of XHR * Returns proper response body in case of error
This commit is contained in:
committed by
Jesse MacFadyen
parent
0aae94495f
commit
e781bceba7
@@ -106,55 +106,134 @@ exec(win, fail, 'FileTransfer', 'upload',
|
|||||||
mimeType = storageFile.contentType;
|
mimeType = storageFile.contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
storageFile.openAsync(Windows.Storage.FileAccessMode.read)
|
// check if download isn't already cancelled
|
||||||
.then(function (stream) {
|
var uploadOp = fileTransferOps[uploadId];
|
||||||
|
if (uploadOp && uploadOp.state === FileTransferOperation.CANCELLED) {
|
||||||
|
// Here we should call errorCB with ABORT_ERR error
|
||||||
|
errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// check if upload isn't already cancelled
|
// setting request headers for uploader
|
||||||
var uploadOp = fileTransferOps[uploadId];
|
var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
|
||||||
if (uploadOp && uploadOp.state == FileTransferOperation.CANCELLED) {
|
for (var header in headers) {
|
||||||
// Here we should call errorCB with ABORT_ERR error
|
if (headers.hasOwnProperty(header)) {
|
||||||
errorCallback(new FTErr(FTErr.ABORT_ERR, filePath, server));
|
uploader.setRequestHeader(header, headers[header]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var blob = MSApp.createBlobFromRandomAccessStream(mimeType, stream);
|
// adding params supplied to request payload
|
||||||
|
var transferParts = [];
|
||||||
var formData = new FormData();
|
for (var key in params) {
|
||||||
formData.append(fileKey, blob, fileName);
|
if (params.hasOwnProperty(key)) {
|
||||||
// add params
|
var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart();
|
||||||
for(var key in params) {
|
contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\"");
|
||||||
formData.append(key,params[key]);
|
contentPart.setText(params[key]);
|
||||||
|
transferParts.push(contentPart);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var uploadOperation;
|
// Adding file to upload to request payload
|
||||||
try {
|
var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName);
|
||||||
// Create XHR promise for uploading data to server
|
fileToUploadPart.setFile(storageFile);
|
||||||
uploadOperation = WinJS.xhr({ type: "POST", url: server, data: formData, headers: headers });
|
transferParts.push(fileToUploadPart);
|
||||||
fileTransferOps[uploadId].promise = uploadOperation;
|
|
||||||
} catch (e) {
|
|
||||||
// it will fail if URL is malformed, so we handle this situation
|
|
||||||
errorCallback(new FTErr(FTErr.INVALID_URL_ERR, filePath, server, null, null, e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadOperation.then(function (response) {
|
// create download object. This will throw an exception if URL is malformed
|
||||||
storageFile.getBasicPropertiesAsync().done(function(basicProperties) {
|
var uri = new Windows.Foundation.Uri(server);
|
||||||
var ftResult = new FileUploadResult(basicProperties.size, response.status, response.responseText);
|
try {
|
||||||
successCallback(ftResult);
|
uploader.createUploadAsync(uri, transferParts).then(
|
||||||
});
|
function (upload) {
|
||||||
}, function(err) {
|
|
||||||
if ('status' in err) {
|
// update internal TransferOperation object with newly created promise
|
||||||
errorCallback(new FTErr(FTErr.CONNECTION_ERR, filePath, server, err.status, err.responseText, err));
|
var uploadOperation = upload.startAsync();
|
||||||
} else {
|
fileTransferOps[uploadId].promise = uploadOperation;
|
||||||
errorCallback(new FTErr(FTErr.INVALID_URL_ERR, filePath, server, null, null, err));
|
|
||||||
|
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(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 FTErr(FTErr.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 FTErr(FTErr.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 FTErr(FTErr.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(transferError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
function (evt) {
|
||||||
|
|
||||||
|
|
||||||
|
var progressEvent = new ProgressEvent('progress', {
|
||||||
|
loaded: evt.progress.bytesSent,
|
||||||
|
total: evt.progress.totalBytesToSend,
|
||||||
|
target: evt.resultFile
|
||||||
|
});
|
||||||
|
progressEvent.lengthComputable = true;
|
||||||
|
successCallback(progressEvent, { keepCallback: true });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
|
||||||
|
errorObj.exception = err;
|
||||||
|
errorCallback(errorObj);
|
||||||
}
|
}
|
||||||
}, function(evt) {
|
);
|
||||||
// progress event handler, calls successCallback with empty ProgressEvent
|
} catch (e) {
|
||||||
// We can't specify ProgressEvent data here since evt not provides any helpful information
|
errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
|
||||||
var progressEvent = new ProgressEvent('progress');
|
}
|
||||||
successCallback(progressEvent, { keepCallback: true });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, server, server, null, null, err));
|
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, server, server, null, null, err));
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user