1
- /* global XMLHttpRequest, Blob */
1
+ /* global Blob */
2
2
import CoreManager from './CoreManager' ;
3
3
import type { FullOptions } from './RESTController' ;
4
4
import ParseError from './ParseError' ;
5
- import XhrWeapp from './Xhr.weapp' ;
6
-
7
- let XHR : any = null ;
8
- if ( typeof XMLHttpRequest !== 'undefined' ) {
9
- XHR = XMLHttpRequest ;
10
- }
11
- if ( process . env . PARSE_BUILD === 'weapp' ) {
12
- XHR = XhrWeapp ;
13
- }
14
5
15
6
type Base64 = { base64 : string } ;
16
7
type Uri = { uri : string } ;
@@ -151,18 +142,29 @@ class ParseFile {
151
142
* Data is present if initialized with Byte Array, Base64 or Saved with Uri.
152
143
* Data is cleared if saved with File object selected with a file upload control
153
144
*
145
+ * @param {object } options
146
+ * @param {function } [options.progress] callback for download progress
147
+ * <pre>
148
+ * const parseFile = new Parse.File(name, file);
149
+ * parseFile.getData({
150
+ * progress: (progressValue, loaded, total) => {
151
+ * if (progressValue !== null) {
152
+ * // Update the UI using progressValue
153
+ * }
154
+ * }
155
+ * });
156
+ * </pre>
154
157
* @returns {Promise } Promise that is resolve with base64 data
155
158
*/
156
- async getData ( ) : Promise < string > {
159
+ async getData ( options ) : Promise < string > {
160
+ options = options || { } ;
157
161
if ( this . _data ) {
158
162
return this . _data ;
159
163
}
160
164
if ( ! this . _url ) {
161
165
throw new Error ( 'Cannot retrieve data for unsaved ParseFile.' ) ;
162
166
}
163
- const options = {
164
- requestTask : task => ( this . _requestTask = task ) ,
165
- } ;
167
+ options . requestTask = task => ( this . _requestTask = task ) ;
166
168
const controller = CoreManager . getFileController ( ) ;
167
169
const result = await controller . download ( this . _url , options ) ;
168
170
this . _data = result . base64 ;
@@ -227,12 +229,12 @@ class ParseFile {
227
229
* be used for this request.
228
230
* <li>sessionToken: A valid session token, used for making a request on
229
231
* behalf of a specific user.
230
- * <li>progress: In Browser only, callback for upload progress. For example:
232
+ * <li>progress: callback for upload progress. For example:
231
233
* <pre>
232
234
* let parseFile = new Parse.File(name, file);
233
235
* parseFile.save({
234
- * progress: (progressValue, loaded, total, { type } ) => {
235
- * if (type === "upload" && progressValue !== null) {
236
+ * progress: (progressValue, loaded, total) => {
237
+ * if (progressValue !== null) {
236
238
* // Update the UI using progressValue
237
239
* }
238
240
* }
@@ -479,58 +481,50 @@ const DefaultController = {
479
481
return CoreManager . getRESTController ( ) . request ( 'POST' , path , data , options ) ;
480
482
} ,
481
483
482
- download : function ( uri , options ) {
483
- if ( XHR ) {
484
- return this . downloadAjax ( uri , options ) ;
485
- } else if ( process . env . PARSE_BUILD === 'node' ) {
486
- return new Promise ( ( resolve , reject ) => {
487
- const client = uri . indexOf ( 'https' ) === 0 ? require ( 'https' ) : require ( 'http' ) ;
488
- const req = client . get ( uri , resp => {
489
- resp . setEncoding ( 'base64' ) ;
490
- let base64 = '' ;
491
- resp . on ( 'data' , data => ( base64 += data ) ) ;
492
- resp . on ( 'end' , ( ) => {
493
- resolve ( {
494
- base64,
495
- contentType : resp . headers [ 'content-type' ] ,
496
- } ) ;
497
- } ) ;
498
- } ) ;
499
- req . on ( 'abort' , ( ) => {
500
- resolve ( { } ) ;
501
- } ) ;
502
- req . on ( 'error' , reject ) ;
503
- options . requestTask ( req ) ;
504
- } ) ;
505
- } else {
506
- return Promise . reject ( 'Cannot make a request: No definition of XMLHttpRequest was found.' ) ;
507
- }
508
- } ,
509
-
510
- downloadAjax : function ( uri : string , options : any ) {
511
- return new Promise ( ( resolve , reject ) => {
512
- const xhr = new XHR ( ) ;
513
- xhr . open ( 'GET' , uri , true ) ;
514
- xhr . responseType = 'arraybuffer' ;
515
- xhr . onerror = function ( e ) {
516
- reject ( e ) ;
517
- } ;
518
- xhr . onreadystatechange = function ( ) {
519
- if ( xhr . readyState !== xhr . DONE ) {
520
- return ;
521
- }
522
- if ( ! this . response ) {
523
- return resolve ( { } ) ;
484
+ download : async function ( uri , options ) {
485
+ const controller = new AbortController ( ) ;
486
+ options . requestTask ( controller ) ;
487
+ const { signal } = controller ;
488
+ try {
489
+ const response = await fetch ( uri , { signal } ) ;
490
+ const reader = response . body . getReader ( ) ;
491
+ const length = + response . headers . get ( 'Content-Length' ) || 0 ;
492
+ const contentType = response . headers . get ( 'Content-Type' ) ;
493
+ if ( length === 0 ) {
494
+ options . progress ?.( null , null , null ) ;
495
+ return {
496
+ base64 : '' ,
497
+ contentType,
498
+ } ;
499
+ }
500
+ let recieved = 0 ;
501
+ const chunks = [ ] ;
502
+ while ( true ) {
503
+ const { done, value } = await reader . read ( ) ;
504
+ if ( done ) {
505
+ break ;
524
506
}
525
- const bytes = new Uint8Array ( this . response ) ;
526
- resolve ( {
527
- base64 : ParseFile . encodeBase64 ( bytes ) ,
528
- contentType : xhr . getResponseHeader ( 'content-type' ) ,
529
- } ) ;
507
+ chunks . push ( value ) ;
508
+ recieved += value ?. length || 0 ;
509
+ options . progress ?.( recieved / length , recieved , length ) ;
510
+ }
511
+ const body = new Uint8Array ( recieved ) ;
512
+ let offset = 0 ;
513
+ for ( const chunk of chunks ) {
514
+ body . set ( chunk , offset ) ;
515
+ offset += chunk . length ;
516
+ }
517
+ return {
518
+ base64 : ParseFile . encodeBase64 ( body ) ,
519
+ contentType,
530
520
} ;
531
- options . requestTask ( xhr ) ;
532
- xhr . send ( ) ;
533
- } ) ;
521
+ } catch ( error ) {
522
+ if ( error . name === 'AbortError' ) {
523
+ return { } ;
524
+ } else {
525
+ throw error ;
526
+ }
527
+ }
534
528
} ,
535
529
536
530
deleteFile : function ( name : string , options ?: FullOptions ) {
@@ -549,21 +543,13 @@ const DefaultController = {
549
543
. ajax ( 'DELETE' , url , '' , headers )
550
544
. catch ( response => {
551
545
// TODO: return JSON object in server
552
- if ( ! response || response === 'SyntaxError: Unexpected end of JSON input' ) {
546
+ if ( ! response || response . toString ( ) === 'SyntaxError: Unexpected end of JSON input' ) {
553
547
return Promise . resolve ( ) ;
554
548
} else {
555
549
return CoreManager . getRESTController ( ) . handleError ( response ) ;
556
550
}
557
551
} ) ;
558
552
} ,
559
-
560
- _setXHR ( xhr : any ) {
561
- XHR = xhr ;
562
- } ,
563
-
564
- _getXHR ( ) {
565
- return XHR ;
566
- } ,
567
553
} ;
568
554
569
555
CoreManager . setFileController ( DefaultController ) ;
0 commit comments