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
156interface Base64 {
167 base64 : string ;
@@ -155,18 +146,29 @@ class ParseFile {
155146 * Data is present if initialized with Byte Array, Base64 or Saved with Uri.
156147 * Data is cleared if saved with File object selected with a file upload control
157148 *
149+ * @param {object } options
150+ * @param {function } [options.progress] callback for download progress
151+ * <pre>
152+ * const parseFile = new Parse.File(name, file);
153+ * parseFile.getData({
154+ * progress: (progressValue, loaded, total) => {
155+ * if (progressValue !== null) {
156+ * // Update the UI using progressValue
157+ * }
158+ * }
159+ * });
160+ * </pre>
158161 * @returns {Promise } Promise that is resolve with base64 data
159162 */
160- async getData ( ) : Promise < string > {
163+ async getData ( options ?: { progress ?: ( ) => void } ) : Promise < string > {
164+ options = options || { } ;
161165 if ( this . _data ) {
162166 return this . _data ;
163167 }
164168 if ( ! this . _url ) {
165169 throw new Error ( 'Cannot retrieve data for unsaved ParseFile.' ) ;
166170 }
167- const options = {
168- requestTask : task => ( this . _requestTask = task ) ,
169- } ;
171+ ( options as any ) . requestTask = task => ( this . _requestTask = task ) ;
170172 const controller = CoreManager . getFileController ( ) ;
171173 const result = await controller . download ( this . _url , options ) ;
172174 this . _data = result . base64 ;
@@ -231,12 +233,12 @@ class ParseFile {
231233 * be used for this request.
232234 * <li>sessionToken: A valid session token, used for making a request on
233235 * behalf of a specific user.
234- * <li>progress: In Browser only, callback for upload progress. For example:
236+ * <li>progress: callback for upload progress. For example:
235237 * <pre>
236238 * let parseFile = new Parse.File(name, file);
237239 * parseFile.save({
238- * progress: (progressValue, loaded, total, { type } ) => {
239- * if (type === "upload" && progressValue !== null) {
240+ * progress: (progressValue, loaded, total) => {
241+ * if (progressValue !== null) {
240242 * // Update the UI using progressValue
241243 * }
242244 * }
@@ -483,58 +485,50 @@ const DefaultController = {
483485 return CoreManager . getRESTController ( ) . request ( 'POST' , path , data , options ) ;
484486 } ,
485487
486- download : function ( uri , options ) {
487- if ( XHR ) {
488- return this . downloadAjax ( uri , options ) ;
489- } else if ( process . env . PARSE_BUILD === 'node' ) {
490- return new Promise ( ( resolve , reject ) => {
491- const client = uri . indexOf ( 'https' ) === 0 ? require ( 'https' ) : require ( 'http' ) ;
492- const req = client . get ( uri , resp => {
493- resp . setEncoding ( 'base64' ) ;
494- let base64 = '' ;
495- resp . on ( 'data' , data => ( base64 += data ) ) ;
496- resp . on ( 'end' , ( ) => {
497- resolve ( {
498- base64,
499- contentType : resp . headers [ 'content-type' ] ,
500- } ) ;
501- } ) ;
502- } ) ;
503- req . on ( 'abort' , ( ) => {
504- resolve ( { } ) ;
505- } ) ;
506- req . on ( 'error' , reject ) ;
507- options . requestTask ( req ) ;
508- } ) ;
509- } else {
510- return Promise . reject ( 'Cannot make a request: No definition of XMLHttpRequest was found.' ) ;
511- }
512- } ,
513-
514- downloadAjax : function ( uri : string , options : any ) {
515- return new Promise ( ( resolve , reject ) => {
516- const xhr = new XHR ( ) ;
517- xhr . open ( 'GET' , uri , true ) ;
518- xhr . responseType = 'arraybuffer' ;
519- xhr . onerror = function ( e ) {
520- reject ( e ) ;
521- } ;
522- xhr . onreadystatechange = function ( ) {
523- if ( xhr . readyState !== xhr . DONE ) {
524- return ;
525- }
526- if ( ! this . response ) {
527- return resolve ( { } ) ;
488+ download : async function ( uri , options ) {
489+ const controller = new AbortController ( ) ;
490+ options . requestTask ( controller ) ;
491+ const { signal } = controller ;
492+ try {
493+ const response = await fetch ( uri , { signal } ) ;
494+ const reader = response . body . getReader ( ) ;
495+ const length = + response . headers . get ( 'Content-Length' ) || 0 ;
496+ const contentType = response . headers . get ( 'Content-Type' ) ;
497+ if ( length === 0 ) {
498+ options . progress ?.( null , null , null ) ;
499+ return {
500+ base64 : '' ,
501+ contentType,
502+ } ;
503+ }
504+ let recieved = 0 ;
505+ const chunks = [ ] ;
506+ while ( true ) {
507+ const { done, value } = await reader . read ( ) ;
508+ if ( done ) {
509+ break ;
528510 }
529- const bytes = new Uint8Array ( this . response ) ;
530- resolve ( {
531- base64 : ParseFile . encodeBase64 ( bytes ) ,
532- contentType : xhr . getResponseHeader ( 'content-type' ) ,
533- } ) ;
511+ chunks . push ( value ) ;
512+ recieved += value ?. length || 0 ;
513+ options . progress ?.( recieved / length , recieved , length ) ;
514+ }
515+ const body = new Uint8Array ( recieved ) ;
516+ let offset = 0 ;
517+ for ( const chunk of chunks ) {
518+ body . set ( chunk , offset ) ;
519+ offset += chunk . length ;
520+ }
521+ return {
522+ base64 : ParseFile . encodeBase64 ( body ) ,
523+ contentType,
534524 } ;
535- options . requestTask ( xhr ) ;
536- xhr . send ( ) ;
537- } ) ;
525+ } catch ( error ) {
526+ if ( error . name === 'AbortError' ) {
527+ return { } ;
528+ } else {
529+ throw error ;
530+ }
531+ }
538532 } ,
539533
540534 deleteFile : function ( name : string , options ?: FullOptions ) {
@@ -553,21 +547,13 @@ const DefaultController = {
553547 . ajax ( 'DELETE' , url , '' , headers )
554548 . catch ( response => {
555549 // TODO: return JSON object in server
556- if ( ! response || response === 'SyntaxError: Unexpected end of JSON input' ) {
550+ if ( ! response || response . toString ( ) === 'SyntaxError: Unexpected end of JSON input' ) {
557551 return Promise . resolve ( ) ;
558552 } else {
559553 return CoreManager . getRESTController ( ) . handleError ( response ) ;
560554 }
561555 } ) ;
562556 } ,
563-
564- _setXHR ( xhr : any ) {
565- XHR = xhr ;
566- } ,
567-
568- _getXHR ( ) {
569- return XHR ;
570- } ,
571557} ;
572558
573559CoreManager . setFileController ( DefaultController ) ;
0 commit comments