Skip to content

Commit 4451803

Browse files
hellaisevilaliv3
authored andcommitted
Add support read hook and implement webAPI based read hook
Based on discussion and feedback from @AidasK in #42
1 parent 43574f0 commit 4451803

2 files changed

Lines changed: 82 additions & 43 deletions

File tree

src/flow.js

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @param {number} [opts.chunkRetryInterval]
3030
* @param {Array.<number>} [opts.permanentErrors]
3131
* @param {Array.<number>} [opts.successStatuses]
32+
* @param {Function} [opts.read]
3233
* @param {Function} [opts.generateUniqueIdentifier]
3334
* @constructor
3435
*/
@@ -91,9 +92,10 @@
9192
chunkRetryInterval: null,
9293
permanentErrors: [404, 415, 500, 501],
9394
successStatuses: [200, 201, 202],
94-
onDropStopPropagation: false
95+
onDropStopPropagation: false,
96+
read: webAPIFileRead,
9597
};
96-
98+
9799
/**
98100
* Current options
99101
* @type {Object}
@@ -144,6 +146,12 @@
144146
* @type {Object}
145147
*/
146148
this.opts = Flow.extend({}, this.defaults, opts || {});
149+
150+
if (!this.opts.fileFactory.supportsPrioritizeFirstAndLastChunk &&
151+
this.defaults.prioritizeFirstAndLastChunk) {
152+
throw Error("Cannot use prioritizeFirstAndLastChunk and with this fileFactory.");
153+
}
154+
147155
}
148156

149157
Flow.prototype = {
@@ -697,6 +705,12 @@
697705
* @type {Flow}
698706
*/
699707
this.flowObj = flowObj;
708+
709+
/**
710+
* Used to store the bytes read
711+
* @type {Blob|string}
712+
*/
713+
this.bytes = null;
700714

701715
/**
702716
* Reference to file
@@ -714,7 +728,7 @@
714728
* File size
715729
* @type {number}
716730
*/
717-
this.size = file.size;
731+
this.size = this.fileProxy.size;
718732

719733
/**
720734
* Relative file path
@@ -912,7 +926,7 @@
912926
this._prevProgress = 0;
913927
var round = this.flowObj.opts.forceChunkSize ? Math.ceil : Math.floor;
914928
var chunks = Math.max(
915-
round(this.file.size / this.flowObj.opts.chunkSize), 1
929+
round(this.size / this.flowObj.opts.chunkSize), 1
916930
);
917931
for (var offset = 0; offset < chunks; offset++) {
918932
this.chunks.push(
@@ -971,7 +985,7 @@
971985
var outstanding = false;
972986
each(this.chunks, function (chunk) {
973987
var status = chunk.status();
974-
if (status === 'pending' || status === 'uploading' || chunk.preprocessState === 1) {
988+
if (status === 'pending' || status === 'uploading' || status === 'reading' || chunk.preprocessState === 1 || chunk.readState === 1) {
975989
outstanding = true;
976990
return false;
977991
}
@@ -1021,21 +1035,21 @@
10211035
return this.file.type && this.file.type.split('/')[1];
10221036
},
10231037

1024-
/**
1025-
* Get file extension
1026-
* @function
1027-
* @returns {string}
1028-
*/
1029-
getExtension: function () {
1030-
return this.name.substr((~-this.name.lastIndexOf(".") >>> 0) + 2).toLowerCase();
1031-
}
10321038
};
10331039

1034-
1035-
1036-
1037-
1038-
1040+
/**
1041+
* Default read function using the webAPI
1042+
*
1043+
* @function webAPIFileRead(chunk, startByte, endByte, fileType)
1044+
*
1045+
*/
1046+
function webAPIFileRead(chunk, startByte, endByte, fileType) {
1047+
var function_name = (chunk.fileObj.file.slice ? 'slice' :
1048+
(chunk.fileObj.file.mozSlice ? 'mozSlice' :
1049+
(chunk.fileObj.file.webkitSlice ? 'webkitSlice' :
1050+
'slice')));
1051+
chunk.readFinished(chunk.fileObj.file[function_name](startByte, endByte, fileType));
1052+
}
10391053

10401054

10411055
/**
@@ -1060,12 +1074,6 @@
10601074
*/
10611075
this.fileObj = fileObj;
10621076

1063-
/**
1064-
* File size
1065-
* @type {number}
1066-
*/
1067-
this.fileObjSize = fileObj.size;
1068-
10691077
/**
10701078
* File offset
10711079
* @type {number}
@@ -1096,6 +1104,13 @@
10961104
*/
10971105
this.preprocessState = 0;
10981106

1107+
/**
1108+
* Read state
1109+
* @type {number} 0 = not read, 1 = reading, 2 = finished
1110+
*/
1111+
this.readState = 0;
1112+
1113+
10991114
/**
11001115
* Bytes transferred from total request size
11011116
* @type {number}
@@ -1124,21 +1139,16 @@
11241139
* Chunk end byte in a file
11251140
* @type {number}
11261141
*/
1127-
this.endByte = Math.min(this.fileObjSize, (this.offset + 1) * chunkSize);
1142+
this.endByte = Math.min(this.fileObj.size, (this.offset + 1) * chunkSize);
1143+
1144+
this.data = null;
11281145

11291146
/**
11301147
* XMLHttpRequest
11311148
* @type {XMLHttpRequest}
11321149
*/
11331150
this.xhr = null;
11341151

1135-
if (this.fileObjSize - this.endByte < chunkSize &&
1136-
!this.flowObj.opts.forceChunkSize) {
1137-
// The last chunk will be bigger than the chunk size,
1138-
// but less than 2*chunkSize
1139-
this.endByte = this.fileObjSize;
1140-
}
1141-
11421152
var $ = this;
11431153

11441154

@@ -1192,6 +1202,7 @@
11921202
this.doneHandler = function(event) {
11931203
var status = $.status();
11941204
if (status === 'success' || status === 'error') {
1205+
delete this.data;
11951206
$.event(status, $.message());
11961207
$.flowObj.uploadNextChunk();
11971208
} else {
@@ -1221,7 +1232,7 @@
12211232
flowChunkNumber: this.offset + 1,
12221233
flowChunkSize: this.flowObj.opts.chunkSize,
12231234
flowCurrentChunkSize: this.endByte - this.startByte,
1224-
flowTotalSize: this.fileObjSize,
1235+
flowTotalSize: this.fileObj.size,
12251236
flowIdentifier: this.fileObj.uniqueIdentifier,
12261237
flowFilename: this.fileObj.name,
12271238
flowRelativePath: this.fileObj.relativePath,
@@ -1264,16 +1275,37 @@
12641275
* @function
12651276
*/
12661277
preprocessFinished: function () {
1278+
// Compute the endByte after the preprocess function to allow an
1279+
// implementer of preprocess to set the fileObj size
1280+
this.endByte = Math.min(this.fileObj.size, (this.offset + 1) * chunkSize);
1281+
if (this.fileObj.size - this.endByte < chunkSize &&
1282+
!this.flowObj.opts.forceChunkSize) {
1283+
// The last chunk will be bigger than the chunk size,
1284+
// but less than 2*chunkSize
1285+
this.endByte = this.fileObj.size;
1286+
}
12671287
this.preprocessState = 2;
12681288
this.send();
12691289
},
12701290

1291+
/**
1292+
* Finish read state
1293+
* @function
1294+
*/
1295+
readFinished: function (bytes) {
1296+
this.readState = 2;
1297+
this.bytes = bytes;
1298+
this.send();
1299+
},
1300+
1301+
12711302
/**
12721303
* Uploads the actual data in a POST call
12731304
* @function
12741305
*/
12751306
send: function () {
1276-
var preprocess = this.flowObj.opts.preprocess;
1307+
var preprocess = this.flowObj.opts.preprocess,
1308+
read = this.flowObj.opts.read;
12771309
if (typeof preprocess === 'function') {
12781310
switch (this.preprocessState) {
12791311
case 0:
@@ -1284,6 +1316,16 @@
12841316
return;
12851317
}
12861318
}
1319+
if (typeof this.read === 'function') {
1320+
switch (this.readState) {
1321+
case 0:
1322+
this.readState = 1;
1323+
read(this, this.startByte, this.endByte, this.fileType);
1324+
return;
1325+
case 1:
1326+
return;
1327+
}
1328+
}
12871329
if (this.flowObj.opts.testChunks && !this.tested) {
12881330
this.test();
12891331
return;
@@ -1293,20 +1335,14 @@
12931335
this.total = 0;
12941336
this.pendingRetry = false;
12951337

1296-
var func = (this.fileObj.file.slice ? 'slice' :
1297-
(this.fileObj.file.mozSlice ? 'mozSlice' :
1298-
(this.fileObj.file.webkitSlice ? 'webkitSlice' :
1299-
'slice')));
1300-
var bytes = this.fileObj.file[func](this.startByte, this.endByte, this.fileObj.file.type);
1301-
13021338
// Set up request and listen for event
13031339
this.xhr = new XMLHttpRequest();
13041340
this.xhr.upload.addEventListener('progress', this.progressHandler, false);
13051341
this.xhr.addEventListener("load", this.doneHandler, false);
13061342
this.xhr.addEventListener("error", this.doneHandler, false);
13071343

13081344
var uploadMethod = evalOpts(this.flowObj.opts.uploadMethod, this.fileObj, this);
1309-
var data = this.prepareXhrRequest(uploadMethod, false, this.flowObj.opts.method, bytes);
1345+
var data = this.prepareXhrRequest(uploadMethod, false, this.flowObj.opts.method, this.bytes);
13101346
this.xhr.send(data);
13111347
},
13121348

@@ -1329,7 +1365,9 @@
13291365
* @returns {string} 'pending', 'uploading', 'success', 'error'
13301366
*/
13311367
status: function (isTest) {
1332-
if (this.pendingRetry || this.preprocessState === 1) {
1368+
if (this.readState === 1) {
1369+
return 'reading';
1370+
} else if (this.pendingRetry || this.preprocessState === 1) {
13331371
// if pending retry then that's effectively the same as actively uploading,
13341372
// there might just be a slight delay before the retry starts
13351373
return 'uploading';

test/fileSpec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ describe('FlowFile functions', function() {
3434
file.name = '.dwq.dq.wd.qdw.E';
3535
expect(file.getExtension()).toBe('e');
3636
});
37-
});
37+
38+
});

0 commit comments

Comments
 (0)