Spaces:
Running
Running
| import { Cache } from './Cache.js'; | |
| import { Loader } from './Loader.js'; | |
| const loading = {}; | |
| 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 | |
| }); | |
| // 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.'); | |
| } | |
| if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) { | |
| return response; | |
| } | |
| const callbacks = loading[url]; | |
| const reader = response.body.getReader(); | |
| const contentLength = response.headers.get('Content-Length'); | |
| 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 Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`); | |
| } | |
| }) | |
| .then((response) => { | |
| switch (this.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, this.mimeType); | |
| }); | |
| case 'json': | |
| return response.json(); | |
| default: | |
| return response.text(); | |
| } | |
| }) | |
| .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 }; | |