import { extname , join } from 'path' ; import { URL } from 'url' ; import { Worker } from 'worker_threads' ; import { app } from '..' ; import { createLogger } from './Console' ; type Options = { roundify ? : boolean ; } ; const { debug } = createLogger ( 'PictureWorker' ) ; /**
 * Controls the lifecycle of a picture-loading worker.
 * It prevents image loading from blocking the main thread due to hundreds of requests.
 */ class PictureWorker { /**
     * Worker that is being managed.
     */ worker : Worker ; /**
     * Callbacks that are awaiting their image file paths.
     */ private callbacks = new Map < string , { resolve ( imagePath ) : void ; reject ( error ) : void ; } > ( ) ; constructor ( ) { this . worker = new Worker ( join ( __dirname , 'worker.js' ) ) ; this . worker . on ( 'message' , this . resolveImage . bind ( this ) ) ; } param url param options loadImage ( url , options ? ) { const { callbacks , worker } = this ; if ( ( url || '' ) . toString ( ) . trim ( ) === '' ) { debug ( 'An empty URL was requested.' ) ; return Promise . reject ( new Error ( 'URL was empty or null.' ) ) ; } const opts = { roundify : app . config . get ( 'roundifyAvatars' ) , ... ( options || { } ) } ; const uri = new URL ( url ) ; if ( uri . hostname === 'cdn.discordapp.com' ) { if ( extname ( uri . pathname ) . toLowerCase ( ) !== '.png' ) { opts . roundify = false ; } } else if ( uri . protocol !== 'file:' ) { opts . roundify = false ; } uri . searchParams . append ( 'roundify' , opts . roundify ? 'true' : 'false' ) ; const urlHref = uri . href ; debug ( `Sending ${ urlHref }...` ) ; return new Promise ( ( resolve , reject ) => { const cb = callbacks . get ( urlHref ) ; if ( cb !== undefined ) { callbacks . set ( urlHref , { reject , resolve : ( b ) => { cb . resolve ( b ) ; resolve ( b ) ; } , } ) ; return ; } worker . postMessage ( { url : urlHref } ) ; callbacks . set ( urlHref , { resolve , reject } ) ; } ) ; } param result private resolveImage ( result ) { const { url , path } = result ; if ( typeof url !== 'string' ) { return debug ( 'URL was strange:' , url ) ; } const cb = this . callbacks . get ( url ) ; if ( ! cb ) { return debug ( 'There was no callback for' , url ) ; } if ( ! path || ! path . length ) { debug ( `Couldn't load URL: ${ url }, throwing error...` ) ; return cb . reject ( "Couldn't get path." ) ; } this . callbacks . delete ( url ) ; return cb . resolve ( path ) ; } } export const pictureWorker = new PictureWorker ( ) ; global . pictureWorker = pictureWorker ;