{"version":3,"file":"WorkerManager.mjs","sources":["../../../src/loader/parsers/WorkerManager.ts"],"sourcesContent":["let UUID = 0;\nlet MAX_WORKERS: number;\n\n// 1x1 White PNG Data URL\nconst WHITE_PNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42m'\n    + 'P8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=';\nconst checkImageBitmapCode = {\n    id: 'checkImageBitmap',\n    code: `\n    async function checkImageBitmap()\n    {\n        try\n        {\n            if (typeof createImageBitmap !== 'function') return false;\n\n            const response = await fetch('${WHITE_PNG}');\n            const imageBlob =  await response.blob();\n            const imageBitmap = await createImageBitmap(imageBlob);\n\n            return imageBitmap.width === 1 && imageBitmap.height === 1;\n        }\n        catch (e)\n        {\n            return false;\n        }\n    }\n    checkImageBitmap().then((result) => { self.postMessage(result); });\n    `,\n};\n\ntype LoadImageBitmapResult = {\n    data?: ImageBitmap,\n    error?: Error,\n    uuid: number,\n    id: string,\n};\n\nconst workerCode = {\n    id: 'loadImageBitmap',\n    code: `\n    async function loadImageBitmap(url)\n    {\n        const response = await fetch(url);\n\n        if (!response.ok)\n        {\n            throw new Error(\\`[WorkerManager.loadImageBitmap] Failed to fetch \\${url}: \\`\n                + \\`\\${response.status} \\${response.statusText}\\`);\n        }\n\n        const imageBlob =  await response.blob();\n        const imageBitmap = await createImageBitmap(imageBlob);\n\n        return imageBitmap;\n    }\n    self.onmessage = async (event) =>\n    {\n        try\n        {\n            const imageBitmap = await loadImageBitmap(event.data.data[0]);\n\n            self.postMessage({\n                data: imageBitmap,\n                uuid: event.data.uuid,\n                id: event.data.id,\n            }, [imageBitmap]);\n        }\n        catch(e)\n        {\n            self.postMessage({\n                error: e,\n                uuid: event.data.uuid,\n                id: event.data.id,\n            });\n        }\n    };`,\n};\n\nlet workerURL: string;\n\nclass WorkerManagerClass\n{\n    public worker: Worker;\n    private resolveHash: {\n        [key: string]: {\n            resolve: (...param: any[]) => void;\n            reject: (...param: any[]) => void;\n        }\n    };\n    private readonly workerPool: Worker[];\n    private readonly queue: {\n        id: string;\n        arguments: any[];\n        resolve: (...param: any[]) => void;\n        reject: (...param: any[]) => void;\n    }[];\n    private _initialized = false;\n    private _createdWorkers = 0;\n    private _isImageBitmapSupported?: Promise<boolean>;\n\n    constructor()\n    {\n        this.workerPool = [];\n        this.queue = [];\n\n        this.resolveHash = {};\n    }\n\n    public isImageBitmapSupported(): Promise<boolean>\n    {\n        if (this._isImageBitmapSupported !== undefined) return this._isImageBitmapSupported;\n\n        this._isImageBitmapSupported = new Promise((resolve) =>\n        {\n            const workerURL = URL.createObjectURL(new Blob([checkImageBitmapCode.code],\n                { type: 'application/javascript' }));\n            const worker = new Worker(workerURL);\n\n            worker.addEventListener('message', (event: MessageEvent<boolean>) =>\n            {\n                worker.terminate();\n                URL.revokeObjectURL(workerURL);\n                resolve(event.data);\n            });\n        });\n\n        return this._isImageBitmapSupported;\n    }\n\n    public loadImageBitmap(src: string): Promise<ImageBitmap>\n    {\n        return this._run('loadImageBitmap', [src]) as Promise<ImageBitmap>;\n    }\n\n    private async _initWorkers()\n    {\n        if (this._initialized) return;\n\n        this._initialized = true;\n    }\n\n    private getWorker(): Worker\n    {\n        if (MAX_WORKERS === undefined)\n        {\n            MAX_WORKERS = navigator.hardwareConcurrency || 4;\n        }\n        let worker = this.workerPool.pop();\n\n        if (!worker && this._createdWorkers < MAX_WORKERS)\n        {\n            if (!workerURL)\n            {\n                workerURL = URL.createObjectURL(new Blob([workerCode.code], { type: 'application/javascript' }));\n            }\n\n            // only create as many as MAX_WORKERS allows..\n            this._createdWorkers++;\n            worker = new Worker(workerURL);\n\n            worker.addEventListener('message', (event: MessageEvent) =>\n            {\n                this.complete(event.data);\n\n                this.returnWorker(event.target as Worker);\n                this.next();\n            });\n        }\n\n        return worker;\n    }\n\n    private returnWorker(worker: Worker)\n    {\n        this.workerPool.push(worker);\n    }\n\n    private complete(data: LoadImageBitmapResult): void\n    {\n        if (data.error !== undefined)\n        {\n            this.resolveHash[data.uuid].reject(data.error);\n        }\n        else\n        {\n            this.resolveHash[data.uuid].resolve(data.data);\n        }\n\n        this.resolveHash[data.uuid] = null;\n    }\n\n    private async _run(id: string, args: any[]): Promise<any>\n    {\n        await this._initWorkers();\n        // push into the queue...\n\n        const promise = new Promise((resolve, reject) =>\n        {\n            this.queue.push({ id, arguments: args, resolve, reject });\n        });\n\n        this.next();\n\n        return promise;\n    }\n\n    private next(): void\n    {\n        // nothing to do\n        if (!this.queue.length) return;\n\n        const worker = this.getWorker();\n\n        // no workers available...\n        if (!worker)\n        {\n            return;\n        }\n\n        const toDo = this.queue.pop();\n\n        const id = toDo.id;\n\n        this.resolveHash[UUID] = { resolve: toDo.resolve, reject: toDo.reject };\n\n        worker.postMessage({\n            data: toDo.arguments,\n            uuid: UUID++,\n            id,\n        });\n    }\n}\n\nconst WorkerManager = new WorkerManagerClass();\n\nexport {\n    WorkerManager,\n};\n"],"names":[],"mappings":"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"}