UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

122 lines 4.05 kB
import { DataSerializer } from '../data'; import { Node } from '../Node'; import { GraphBuilder } from '../graph/builders/GraphBuilder'; import { WorkerHandler } from '../worker'; /** * Worker nodes are normal nodes that initialize multiple web workers. * Push and pull requests are forwarded to these web workers. * * ## Usage * * ### Absolute Imports * ```typescript * const workerNode = new WorkerNode((builder) => { * const TimeConsumingNode = require('@openhps/abc'); * builder.to(new TimeConsumingNode()); * }); * ``` * * ### Relative Imports * ```typescript * const workerNode = new WorkerNode((builder) => { * const TimeConsumingNode = require(path.join(__dirname, '../TimeConsumingNode')); * builder.to(new TimeConsumingNode()); * }, { directory: __dirname }); * ``` * * ### Web Worker * Web workers can be used by specifying the worker file. * ```typescript * const workerNode = new WorkerNode((builder) => { * const TimeConsumingNode = require(path.join(__dirname, '../TimeConsumingNode')); * builder.to(new TimeConsumingNode()); * }, { * worker: 'worker.openhps-core.min.js' // Worker JS file * }); * ``` * @category Node */ export class WorkerNode extends Node { constructor(worker, options) { super(options); this.config = {}; this.options.worker = this.options.worker || '../worker/WorkerRunner'; this.options.type = this.options.type || 'classic'; if (worker instanceof GraphBuilder) { // Serializable node this.config.serialized = DataSerializer.serialize(worker.graph); } else if (worker instanceof Node) { // Serializable node this.config.serialized = DataSerializer.serialize(worker); } else if (worker instanceof Function) { // Code this.config.builder = worker.toString(); if (this.options.type === 'typescript') { // eslint-disable-next-line this.config.builder = require('typescript').transpile(this.config.builder); } } else { this.config.shape = worker; } this.once('build', this._onBuild.bind(this)); this.once('destroy', this._onDestroy.bind(this)); this.on('pull', this._onPull.bind(this)); this.on('push', this._onPush.bind(this)); } _onBuild() { return new Promise((resolve, reject) => { this.handler = new WorkerHandler(this.model, this.options, this.config); this.handler.on('push', this._onWorkerPush.bind(this)); this.handler.on('pull', this._onWorkerPull.bind(this)); this.handler.on('event', this._onWorkerEvent.bind(this)); this.handler.build().then(resolve).catch(reject); }); } _onDestroy() { return new Promise((resolve, reject) => { this.handler.destroy().then(resolve).catch(reject); }); } _onPull(options) { return new Promise((resolve, reject) => { if (this.options.optimizedPull) { // Do not pass the pull request to the worker Promise.all(this.inlets.map(inlet => inlet.pull(options))).then(() => { resolve(); }).catch(reject); } else { this.handler.pull(options).then(resolve).catch(reject); } }); } _onPush(frame, options) { return this.handler.push(frame, options); } _onWorkerEvent(value) { this.inlets.map(inlet => inlet.emit(value.name, value.event)); } /** * Triggered for each worker that requests a pull * @param {PullOptions} options Pull options */ _onWorkerPull(options) { this.inlets.forEach(inlet => inlet.pull(options)); } /** * Triggered for each worker that pushes data * @param {DataFrame} frame Deserialized frame * @param {PushOptions} options Push options */ _onWorkerPush(frame, options) { this.outlets.forEach(outlet => outlet.push(frame, options)); } /** * Invoke a worker method * @param {string} methodName Method name * @param {any[]} args Arguments * @returns {Promise<any>} Promise with result(s) */ invokeMethod(methodName, ...args) { return this.handler.invokeMethod(methodName, ...args); } }