Buckets:
| import { Cache } from './Cache.js'; | |
| import { Loader } from './Loader.js'; | |
| const loading = {}; | |
| class HttpError extends Error { | |
| constructor( message, response ) { | |
| super( message ); | |
| this.response = response; | |
| } | |
| } | |
| class FileLoader extends Loader { | |
| constructor( manager ) { | |
| super( manager ); | |
| } | |
| load( url, onLoad, onProgress, onError ) { | |
| if ( url === undefined ) url = ''; | |
| if ( this.path !== undefined ) url = this.path + url; | |
| url = this.manager.resolveURL( url ); | |
| const cached = Cache.get( url ); | |
| if ( cached !== undefined ) { | |
| this.manager.itemStart( url ); | |
| setTimeout( () => { | |
| if ( onLoad ) onLoad( cached ); | |
| this.manager.itemEnd( url ); | |
| }, 0 ); | |
| return cached; | |
| } | |
| // Check if request is duplicate | |
| if ( loading[ url ] !== undefined ) { | |
| loading[ url ].push( { | |
| onLoad: onLoad, | |
| onProgress: onProgress, | |
| onError: onError | |
| } ); | |
| return; | |
| } | |
| // Initialise array for duplicate requests | |
| loading[ url ] = []; | |
| loading[ url ].push( { | |
| onLoad: onLoad, | |
| onProgress: onProgress, | |
| onError: onError, | |
| } ); | |
| // create request | |
| const req = new Request( url, { | |
| headers: new Headers( this.requestHeader ), | |
| credentials: this.withCredentials ? 'include' : 'same-origin', | |
| // An abort controller could be added within a future PR | |
| } ); | |
| // record states ( avoid data race ) | |
| const mimeType = this.mimeType; | |
| const responseType = this.responseType; | |
| // start the fetch | |
| fetch( req ) | |
| .then( response => { | |
| if ( response.status === 200 || response.status === 0 ) { | |
| // Some browsers return HTTP Status 0 when using non-http protocol | |
| // e.g. 'file://' or 'data://'. Handle as success. | |
| if ( response.status === 0 ) { | |
| console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); | |
| } | |
| // Workaround: Checking if response.body === undefined for Alipay browser #23548 | |
| if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { | |
| return response; | |
| } | |
| const callbacks = loading[ url ]; | |
| const reader = response.body.getReader(); | |
| // Nginx needs X-File-Size check | |
| // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content | |
| const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' ); | |
| const total = contentLength ? parseInt( contentLength ) : 0; | |
| const lengthComputable = total !== 0; | |
| let loaded = 0; | |
| // periodically read data into the new stream tracking while download progress | |
| const stream = new ReadableStream( { | |
| start( controller ) { | |
| readData(); | |
| function readData() { | |
| reader.read().then( ( { done, value } ) => { | |
| if ( done ) { | |
| controller.close(); | |
| } else { | |
| loaded += value.byteLength; | |
| const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); | |
| for ( let i = 0, il = callbacks.length; i < il; i ++ ) { | |
| const callback = callbacks[ i ]; | |
| if ( callback.onProgress ) callback.onProgress( event ); | |
| } | |
| controller.enqueue( value ); | |
| readData(); | |
| } | |
| } ); | |
| } | |
| } | |
| } ); | |
| return new Response( stream ); | |
| } else { | |
| throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); | |
| } | |
| } ) | |
| .then( response => { | |
| switch ( responseType ) { | |
| case 'arraybuffer': | |
| return response.arrayBuffer(); | |
| case 'blob': | |
| return response.blob(); | |
| case 'document': | |
| return response.text() | |
| .then( text => { | |
| const parser = new DOMParser(); | |
| return parser.parseFromString( text, mimeType ); | |
| } ); | |
| case 'json': | |
| return response.json(); | |
| default: | |
| if ( mimeType === undefined ) { | |
| return response.text(); | |
| } else { | |
| // sniff encoding | |
| const re = /charset="?([^;"\s]*)"?/i; | |
| const exec = re.exec( mimeType ); | |
| const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; | |
| const decoder = new TextDecoder( label ); | |
| return response.arrayBuffer().then( ab => decoder.decode( ab ) ); | |
| } | |
| } | |
| } ) | |
| .then( data => { | |
| // Add to cache only on HTTP success, so that we do not cache | |
| // error response bodies as proper responses to requests. | |
| Cache.add( url, data ); | |
| const callbacks = loading[ url ]; | |
| delete loading[ url ]; | |
| for ( let i = 0, il = callbacks.length; i < il; i ++ ) { | |
| const callback = callbacks[ i ]; | |
| if ( callback.onLoad ) callback.onLoad( data ); | |
| } | |
| } ) | |
| .catch( err => { | |
| // Abort errors and other errors are handled the same | |
| const callbacks = loading[ url ]; | |
| if ( callbacks === undefined ) { | |
| // When onLoad was called and url was deleted in `loading` | |
| this.manager.itemError( url ); | |
| throw err; | |
| } | |
| delete loading[ url ]; | |
| for ( let i = 0, il = callbacks.length; i < il; i ++ ) { | |
| const callback = callbacks[ i ]; | |
| if ( callback.onError ) callback.onError( err ); | |
| } | |
| this.manager.itemError( url ); | |
| } ) | |
| .finally( () => { | |
| this.manager.itemEnd( url ); | |
| } ); | |
| this.manager.itemStart( url ); | |
| } | |
| setResponseType( value ) { | |
| this.responseType = value; | |
| return this; | |
| } | |
| setMimeType( value ) { | |
| this.mimeType = value; | |
| return this; | |
| } | |
| } | |
| export { FileLoader }; | |
Xet Storage Details
- Size:
- 5.55 kB
- Xet hash:
- 68ea08a9e2fc3041f46cc8a7c01ce2892dbc48412ff6f3e445b8914c265f2562
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.