Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
purplecabbage committed Feb 3, 2015
2 parents c12f1eb + fa900e1 commit bc43b46
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 93 deletions.
6 changes: 2 additions & 4 deletions doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,13 @@ Although in the global scope, they are not available until after the `deviceread
- Firefox OS**
- iOS
- Windows Phone 7 and 8*
- Windows 8***
- Windows***
- Windows 8
- Windows

\* _Do not support `onprogress` nor `abort()`_

\** _Do not support `onprogress`_

\*** Partial support of `onprogress` for upload method. `onprogress` is called with empty progress event due to Windows limitations_

# FileTransfer

The `FileTransfer` object provides a way to upload files using an HTTP
Expand Down
174 changes: 125 additions & 49 deletions src/windows/FileTransferProxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
*/

/*jshint -W030 */
/*global Windows, WinJS*/
/*global module, require*/

var FTErr = require('./FileTransferError'),
ProgressEvent = require('org.apache.cordova.file.ProgressEvent'),
Expand Down Expand Up @@ -71,17 +73,17 @@ exec(win, fail, 'FileTransfer', 'upload',
var fileName = options[3];
var mimeType = options[4];
var params = options[5];
var trustAllHosts = options[6]; // todo
var chunkedMode = options[7]; // todo
// var trustAllHosts = options[6]; // todo
// var chunkedMode = options[7]; // todo
var headers = options[8] || {};
var uploadId = options[9];

if (!filePath || (typeof filePath != 'string')) {
if (!filePath || (typeof filePath !== 'string')) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR,null,server));
return;
}

if (filePath.substr(0, 8) == "file:///") {
if (filePath.substr(0, 8) === "file:///") {
filePath = appData.localFolder.path + filePath.substr(8).split("/").join("\\");
} else if (filePath.indexOf('ms-appdata:///') === 0) {
// Handle 'ms-appdata' scheme
Expand All @@ -106,55 +108,127 @@ exec(win, fail, 'FileTransfer', 'upload',
mimeType = storageFile.contentType;
}

storageFile.openAsync(Windows.Storage.FileAccessMode.read)
.then(function (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(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
return;
}

// 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(new FTErr(FTErr.ABORT_ERR, filePath, server));
return;
// 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 blob = MSApp.createBlobFromRandomAccessStream(mimeType, stream);

var formData = new FormData();
formData.append(fileKey, blob, fileName);
// add params
for(var key in params) {
formData.append(key,params[key]);
// 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);
}
}

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(new FTErr(FTErr.INVALID_URL_ERR, filePath, server, null, null, e));
return;
}
// 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(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();
});
}
}
});

uploadOperation.then(function (response) {
storageFile.getBasicPropertiesAsync().done(function(basicProperties) {
var ftResult = new FileUploadResult(basicProperties.size, response.status, response.responseText);
successCallback(ftResult);
});
}, function(err) {
if ('status' in err) {
errorCallback(new FTErr(FTErr.CONNECTION_ERR, filePath, server, err.status, err.responseText, err));
} else {
errorCallback(new FTErr(FTErr.INVALID_URL_ERR, filePath, server, null, null, err));
// 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
// We can't specify ProgressEvent data here since evt not provides any helpful information
var progressEvent = new ProgressEvent('progress');
successCallback(progressEvent, { keepCallback: true });
});
});
);
} catch (e) {
errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
}
}, function(err) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, server, server, null, null, err));
});
Expand All @@ -171,7 +245,7 @@ exec(win, fail, 'FileTransfer', 'upload',
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR));
return;
}
if (target.substr(0, 8) == "file:///") {
if (target.substr(0, 8) === "file:///") {
target = appData.localFolder.path + target.substr(8).split("/").join("\\");
} else if (target.indexOf('ms-appdata:///') === 0) {
// Handle 'ms-appdata' scheme
Expand All @@ -197,7 +271,7 @@ exec(win, fail, 'FileTransfer', 'upload',

// check if download isn't already cancelled
var downloadOp = fileTransferOps[downloadId];
if (downloadOp && downloadOp.state == FileTransferOperation.CANCELLED) {
if (downloadOp && downloadOp.state === FileTransferOperation.CANCELLED) {
// Here we should call errorCB with ABORT_ERR error
errorCallback(new FTErr(FTErr.ABORT_ERR, source, target));
return;
Expand All @@ -206,7 +280,9 @@ exec(win, fail, 'FileTransfer', 'upload',
// if download isn't cancelled, contunue with creating and preparing download operation
var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
for (var header in headers) {
downloader.setRequestHeader(header, headers[header]);
if (header.hasOwnProperty(header)) {
downloader.setRequestHeader(header, headers[header]);
}
}

// create download object. This will throw an exception if URL is malformed
Expand Down
Loading

0 comments on commit bc43b46

Please sign in to comment.