UNPKG

strikejs-react

Version:

A state management framework for ReactJS applications.

202 lines (186 loc) 4.93 kB
import {IMiddleware,IMiddlewareNext} from './Middleware'; import {Action} from './Action'; import {IStore} from './Store'; /** * An action to be sent to a worker middleware * * @export * @interface WorkerAction * @extends {Action} */ export interface WorkerAction extends Action { /** * The worker identifier, if you're using the single worker middleware, * you'll just need to set this to any truthy value. */ workerId:string; /** * Set this to true to terminate the worker with the provided ID. * If no such worker is found, the action is ignored. */ terminate?:boolean; } /** * A worker registry interface. * The interface represents a contract for a registry to manage multiple workers. * @see {MultiWorkerMiddleware} */ export interface WorkerRegistry{ /** * Returns a worker with a given key (identifier) * @param {string} key the worker key * @returns {Worker} the requested worker * @throws {Error} if no worker with the provided key exists. */ get(key:string):Worker; /** * Registers a worker with a key and a file. * @param {string} key the key to reference the worker by. * @param {string|Worker} fileOrWorker either a file name to use with the worker * or a worker object. * @returns {WorkerRegistry} the current instance of the worker registry. */ register(key:string,fileOrWorker:string|Worker):WorkerRegistry; /** * Terminates a worker with a given key * @param {string} key the worker key. * @returns {WorkerRegistry} the current instance of the worker registry. */ terminate(key:string):WorkerRegistry; } /** * Creates a single worker middleware. * @param {Worker} worker the worker to use. * @param {IStore} store the store instance. * @returns {IMiddleware} */ export function WorkerMiddleware(worker:Worker,store:IStore):IMiddleware{ worker.addEventListener('open',function(e){ let action = { type:'WorkerOpen', data:1 }; store.dispatch(action); }); worker.addEventListener('message',function(e){ let action = e.data; store.dispatch(action); }); worker.addEventListener('error',function(e){ let action = { type:'WorkerError', data:{ error:e.error, message:e.message, lineno:e.lineno, colno:e.colno } }; store.dispatch(action); }); return function(action:WorkerAction,store:IStore,next:IMiddlewareNext){ if (!action.workerId || !worker){ next(action); } ((action.terminate && worker.terminate()) || worker.postMessage(action)); next(); }; } /** * Creates a multi-worker middleware. * * @param {WorkerRegistry} registry the worker registry to use. * @param {IStore} store the state store instance * @returns {Middleware} a multi-worker middleware */ export function MultiWorkerMiddleware(registry:WorkerRegistry,store: IStore):IMiddleware { let workers:Dictionary<Worker> = {}; function addWorker(workerId:string){ let ww = workers[workerId] = registry.get(workerId); ww.addEventListener('open',function(e){ let action = { type:'WorkerOpen', workerId, data:{ workerId, } }; store.dispatch(action); }); ww.addEventListener('message',function(e){ let action = e.data; action.workerId = workerId; store.dispatch(action); }); ww.addEventListener('error',function(e){ let action = { type:'WorkerError', workerId, data:{ workerId, error:e.error, message:e.message, lineno:e.lineno, colno:e.colno } }; store.dispatch(action); }); return ww; } return function(action: WorkerAction, store: IStore, next:IMiddlewareNext) { const workerId = action.workerId; if (!workerId) { next(action); } let ww = workers[workerId]; if (!ww && !action.terminate){ ww = addWorker(workerId); } if (action.terminate && ww){ ww.terminate(); delete ww[workerId]; next(); return; } ww.postMessage(action); next(); } } /** * Creates a basic implementation of a worker registry. * @returns {WorkerRegistry} */ export function createWorkerRegistry():WorkerRegistry{ let o = null; let dict:Dictionary<string> = {}; let workers:Dictionary<Worker> = {}; function register(key:string,file:string|Worker){ if (typeof file === "string"){ dict[key] = file; }else if (typeof file === "object"){ workers[key] = file; } return o; } function get(key:string){ if (!workers[key]){ if (!dict[key]){ throw new Error(`No worker with key: ${key}`); } workers[key] = new Worker(dict[key]); } return workers[key]; } function terminate(key:string){ let w = workers[key]; w && w.terminate(); return o; } o = { register, get, terminate }; return o; }