import RinzlerEventEmitter from './event-emitter' ; import src from '../dist/internals/worker-src.js' ; interface InternalWorkerMsg { type : string ; } export interface InitCall extends InternalWorkerMsg { type : 'init' ; message ? : unknown ; transfer ? : Transferable [ ] ; } export interface JobCall extends InternalWorkerMsg { type : 'job' ; id : string ; message ? : unknown ; transfer ? : Transferable [ ] ; } export interface JobAcceptCall extends InternalWorkerMsg { type : 'jobok' ; id : string ; } export interface JobReturnCall < T = undefined > extends InternalWorkerMsg { type : 'jobdone' ; id : string ; error : boolean ; message : T ; } /**
    Interface for passing messages and `Transferable` data to Web Worker instances.

    See [`DedicatedWorkerGlobalScope.postMessage()`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage) for more details.
*/ export type WorkerFunctionTransferArgs = [ message ? : unknown , transfer ? : Transferable [ ] ] ; /**
    A function for setting up a Web Worker environment before it starts processing jobs. May be sync or async.
    Worker functions cannot use variables defined outside of their block, because the function code itself is inlined
    and written to the Web Worker source code.

    You should pass any dynamic data that won't change between jobs using `initArgs` in  RinzlerEngine . configureAndStart ,
    and parse/use them in the init function.

    If you need to store some global state to be used later when processing jobs, you can write a property to `self`, which will be a [`DedicatedWorkerGlobalScope`](https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope).
    But be careful not to overwrite any browser-initialized properties in there!

     typeParam T Anything passed as `initArgs` in  RinzlerEngine . configureAndStart , with `Transferable` objects inlined.
 export type WorkerInitFunction < T = unknown > = ( message ? : T ) => Promise < void > | void ; typeParam T Anything passed in  RinzlerEngine . runJob , with `Transferable` objects inlined.
 export type WorkerFunction < T = unknown > = ( message ? : T ) => Promise < WorkerFunctionTransferArgs > | WorkerFunctionTransferArgs ; export default class WebWorker extends RinzlerEventEmitter { jobs : JobCall [ ] = [ ] ; active = false ; #workerRef : Worker ; #workingJob : string | null = null ; #initArgs ? : WorkerFunctionTransferArgs ; constructor ( workFunction , initFunction ? , initArgs ? ) { super ( ) ; const populatedSrc = src . replace ( 'INIT_FUNCTION' , initFunction ?. toString ( ) || 'function(){}' ) . replace ( 'WORK_FUNCTION' , workFunction . toString ( ) ) ; const srcBlob = new Blob ( [ populatedSrc ] , { type : 'application/javascript' } ) ; this . #workerRef = new Worker ( URL . createObjectURL ( srcBlob ) ) ; this . #workerRef . addEventListener ( 'message' , this . #messageHandler . bind ( this ) ) ; this . #workerRef . addEventListener ( 'messageerror' , this . #errMessageHandler . bind ( this ) ) ; this . #workerRef . addEventListener ( 'error' , this . #errorHandler . bind ( this ) ) ; this . #initArgs = initArgs ; } async start ( ) { const initMsg = { type : 'init' , message : this . #initArgs && this . #initArgs [ 0 ] , transfer : this . #initArgs && this . #initArgs [ 1 ] } ; this . #workerRef . postMessage ( initMsg ) ; await super . waitFor ( 'ready' ) ; this . active = true ; super . _triggerEvent ( 'idle' ) ; } submitJob ( job ) { if ( ! this . active ) throw new Error ( 'Rinzler WorkerWrapper: not taking new jobs' ) ; this . jobs . push ( job ) ; this . #processQueue ( ) ; } async shutdown ( ) { this . active = false ; if ( this . jobs . length > 0 ) { await this . waitFor ( 'idle' ) ; } this . terminate ( ) ; } terminate ( ) { return this . #workerRef . terminate ( ) ; } async #processQueue ( ) { if ( this . #workingJob !== null ) return ; const job = this . jobs [ 0 ] ; this . #workingJob = job . id ; this . #workerRef . postMessage ( job , job . transfer || [ ] ) ; await super . waitFor ( `jobok-${ job . id }` ) ; } #messageHandler ( e ) { switch ( e . data . type ) { case 'ready' : super . _triggerEvent ( 'ready' ) ; break ; case 'jobok' : super . _triggerEvent < JobAcceptCall > ( 'jobok' , e . data ) ; super . _triggerEvent < JobAcceptCall > ( `jobok-${ e . data . id }` , e . data ) ; break ; case 'jobdone' : super . _triggerEvent < JobReturnCall > ( 'jobdone' , e . data ) ; super . _triggerEvent < JobReturnCall > ( `jobdone-${ e . data . id }` , e . data ) ; this . jobs . splice ( this . jobs . map ( j => j . id ) . indexOf ( e . data . id ) , 1 ) ; this . #workingJob = null ; if ( this . jobs . length === 0 ) { super . _triggerEvent ( 'idle' ) ; } else { this . #processQueue ( ) ; } break ; default : throw new Error ( 'Rinzler WorkerWrapper: unknown message received' ) ; } } #errMessageHandler ( ) { throw new Error ( 'Rinzler WorkerWrapper: failed to deserialize message' ) ; } #errorHandler ( e ) { throw new Error ( 'Rinzler WorkerWrapper internal error: ' + e . message ) ; } }