Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(browser): multipartUpload err will cancel this task #399

Merged
merged 3 commits into from
Mar 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = {
'no-underscore-dangle': [0],
'no-plusplus': [0],
'no-param-reassign': [0],
'max-len': ['warn', 100, 2, {
'max-len': ['warn', 120, 2, {
ignoreUrls: true,
ignoreComments: false,
ignoreRegExpLiterals: true,
Expand Down
71 changes: 38 additions & 33 deletions lib/browser/managed_upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ const proto = exports;
* @param {String} name
* @param {String|File} file
* @param {Object} options
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
*/
proto.multipartUpload = function* multipartUpload(name, file, options) {
this.resetCancelFlag();
Expand Down Expand Up @@ -107,7 +107,7 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
const partOffs = this._divideParts(fileSize, partSize);
const numParts = partOffs.length;

const uploadPartJob = function* (self, partNo) {
const uploadPartJob = function* uploadPartJob(self, partNo) {
if (!self.isCancel()) {
try {
const pi = partOffs[partNo - 1];
Expand All @@ -117,18 +117,23 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
};

const result = yield self._uploadPart(name, uploadId, partNo, data);
doneParts.push({
number: partNo,
etag: result.res.headers.etag,
});
checkpoint.doneParts = doneParts;

if (!self.isCancel() && options && options.progress) {
yield options.progress(doneParts.length / numParts, checkpoint, result.res);
if (!self.isCancel()) {
doneParts.push({
number: partNo,
etag: result.res.headers.etag,
});
checkpoint.doneParts = doneParts;

if (options && options.progress) {
yield options.progress(doneParts.length / numParts, checkpoint, result.res);
}
}
} catch (err) {
err.partNum = partNo;
throw err;
if (!self.isCancel()) {
self.cancel();
err.partNum = partNo;
throw err;
}
}
}
};
Expand Down Expand Up @@ -156,24 +161,25 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
// start uploads jobs
const errors = yield this._thunkPool(jobs, parallel);

if (this.isCancel()) {
jobs = null;
throw this._makeCancelEvent();
}

// check errors after all jobs are completed
if (errors && errors.length > 0) {
this.resetCancelFlag();
const err = errors[0];
err.message = `Failed to upload some parts with error: ${err.toString()} part_num: ${err.partNum}`;
throw err;
}

if (this.isCancel()) {
jobs = null;
throw this._makeCancelEvent();
}
}
return yield this.completeMultipartUpload(name, uploadId, doneParts, options);
};


is.file = function (file) {
return typeof (File) !== 'undefined' && file instanceof File;
is.file = function file(obj) {
return typeof (File) !== 'undefined' && obj instanceof File;
};

/**
Expand Down Expand Up @@ -241,7 +247,7 @@ WebFileReadStream.prototype._read = function _read(size) {
size = size || defaultReadSize;

const that = this;
this.reader.onload = function (e) {
this.reader.onload = function onload(e) {
that.fileBuffer = new Buffer(new Uint8Array(e.target.result));
that.file = null;
that.readFileAndPush(size);
Expand Down Expand Up @@ -270,7 +276,7 @@ proto._createStream = function _createStream(file, start, end) {

proto._getPartSize = function _getPartSize(fileSize, partSize) {
const maxNumParts = 10 * 1000;
const defaultPartSize = 1 * 1024 * 1024;
const defaultPartSize = 1024 * 1024;

if (!partSize) {
return defaultPartSize;
Expand Down Expand Up @@ -300,10 +306,9 @@ proto._divideParts = function _divideParts(fileSize, partSize) {
};

// cancel is not error , so create an object
proto._makeCancelEvent = function () {
const cancelEvent = {
proto._makeCancelEvent = function _makeCancelEvent() {
return {
status: 0,
name: 'cancel',
};
return cancelEvent;
};
20 changes: 10 additions & 10 deletions lib/browser/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ proto.append = function* (name, file, options) {
* @param {String} name the object key
* @param {Mixed} file String(file path)/Buffer/ReadableStream
* @param {Object} options
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
* @return {Object}
*/
proto.put = function* put(name, file, options) {
Expand Down
2 changes: 1 addition & 1 deletion lib/common/thunkpool.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ proto._thunkPool = function thunkPool(thunks, parallel) {
if (endQueueSum === concurrency) {
queue.fns = [];
queue.buffer = [];
resolve();
resolve(_errs);
}
}

Expand Down
20 changes: 10 additions & 10 deletions lib/managed_upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ const proto = exports;
* @param {String} name
* @param {String|File} file
* @param {Object} options
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
*/
proto.multipartUpload = function* multipartUpload(name, file, options) {
options = options || {};
Expand Down
20 changes: 10 additions & 10 deletions lib/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ proto.append = function* (name, file, options) {
* @param {String} name the object key
* @param {Mixed} file String(file path)/Buffer/ReadableStream
* @param {Object} options
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
* {Object} options.callback The callback parameter is composed of a JSON string encoded in Base64
* {String} options.callback.url the OSS sends a callback request to this URL
* {String} options.callback.host The host header value for initiating callback requests
* {String} options.callback.body The value of the request body when a callback is initiated
* {String} options.callback.contentType The Content-Type of the callback requests initiatiated
* {Object} options.callback.customValue Custom parameters are a map of key-values, e.g:
* customValue = {
* key1: 'value1',
* key2: 'value2'
* }
* @return {Object}
*/
proto.put = function* put(name, file, options) {
Expand Down
9 changes: 8 additions & 1 deletion test/browser/browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -786,27 +786,34 @@ describe('browser', () => {
const name = `${prefix}multipart/upload-file-exception`;

const stubUploadPart = sinon.stub(this.store, '_uploadPart');
stubUploadPart.throws('TestUploadPartException');
const testUploadPartException = new Error();
testUploadPartException.name = 'TestUploadPartException';
testUploadPartException.status = 403;
stubUploadPart.throws(testUploadPartException);

let errorMsg = '';
let partNumz = 0;
let errStatus = 0;
try {
yield this.store.multipartUpload(name, file, {
progress() {
return function (done) {
done();
};
},
partSize: 100 * 1024,
});
} catch (err) {
errorMsg = err.message;
partNumz = err.partNum;
errStatus = err.status;
}
assert.equal(
errorMsg,
'Failed to upload some parts with error: TestUploadPartException part_num: 1',
);
assert.equal(partNumz, 1);
assert.equal(errStatus, 403);
this.store._uploadPart.restore();
});

Expand Down