1- /* global XMLHttpRequest, Blob */
1+ /* global Blob */
22import CoreManager from './CoreManager' ;
33import type { FullOptions } from './RESTController' ;
44import 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- }
145
156type Base64 = { base64 : string } ;
167type Uri = { uri : string } ;
@@ -151,18 +142,29 @@ class ParseFile {
151142 * Data is present if initialized with Byte Array, Base64 or Saved with Uri.
152143 * Data is cleared if saved with File object selected with a file upload control
153144 *
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>
154157 * @returns {Promise } Promise that is resolve with base64 data
155158 */
156- async getData ( ) : Promise < string > {
159+ async getData ( options ) : Promise < string > {
160+ options = options || { } ;
157161 if ( this . _data ) {
158162 return this . _data ;
159163 }
160164 if ( ! this . _url ) {
161165 throw new Error ( 'Cannot retrieve data for unsaved ParseFile.' ) ;
162166 }
163- const options = {
164- requestTask : task => ( this . _requestTask = task ) ,
165- } ;
167+ options . requestTask = task => ( this . _requestTask = task ) ;
166168 const controller = CoreManager . getFileController ( ) ;
167169 const result = await controller . download ( this . _url , options ) ;
168170 this . _data = result . base64 ;
@@ -227,12 +229,12 @@ class ParseFile {
227229 * be used for this request.
228230 * <li>sessionToken: A valid session token, used for making a request on
229231 * 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:
231233 * <pre>
232234 * let parseFile = new Parse.File(name, file);
233235 * parseFile.save({
234- * progress: (progressValue, loaded, total, { type } ) => {
235- * if (type === "upload" && progressValue !== null) {
236+ * progress: (progressValue, loaded, total) => {
237+ * if (progressValue !== null) {
236238 * // Update the UI using progressValue
237239 * }
238240 * }
@@ -479,58 +481,50 @@ const DefaultController = {
479481 return CoreManager . getRESTController ( ) . request ( 'POST' , path , data , options ) ;
480482 } ,
481483
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 ;
524506 }
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,
530520 } ;
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+ }
534528 } ,
535529
536530 deleteFile : function ( name : string , options ?: FullOptions ) {
@@ -549,21 +543,13 @@ const DefaultController = {
549543 . ajax ( 'DELETE' , url , '' , headers )
550544 . catch ( response => {
551545 // 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' ) {
553547 return Promise . resolve ( ) ;
554548 } else {
555549 return CoreManager . getRESTController ( ) . handleError ( response ) ;
556550 }
557551 } ) ;
558552 } ,
559-
560- _setXHR ( xhr : any ) {
561- XHR = xhr ;
562- } ,
563-
564- _getXHR ( ) {
565- return XHR ;
566- } ,
567553} ;
568554
569555CoreManager . setFileController ( DefaultController ) ;
0 commit comments