UNPKG

container.ts

Version:
153 lines 6.15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /// <reference types="node" /> const process = require("process"); const Observable_1 = require("rxjs/Observable"); require("rxjs/add/observable/fromEvent"); require("rxjs/add/operator/map"); require("rxjs/add/operator/mergeMap"); require("rxjs/add/operator/filter"); require("rxjs/add/operator/timeout"); require("rxjs/add/operator/takeWhile"); const Process_1 = require("./Process"); /** Process message types. */ var EProcessMessageType; (function (EProcessMessageType) { EProcessMessageType[EProcessMessageType["Log"] = 0] = "Log"; EProcessMessageType[EProcessMessageType["Metric"] = 1] = "Metric"; EProcessMessageType[EProcessMessageType["CallRequest"] = 2] = "CallRequest"; EProcessMessageType[EProcessMessageType["CallResponse"] = 3] = "CallResponse"; EProcessMessageType[EProcessMessageType["User"] = 4] = "User"; })(EProcessMessageType = exports.EProcessMessageType || (exports.EProcessMessageType = {})); /** Process error class. */ class ProcessError extends Error { constructor(name, message, stack) { const error = super(message); this.name = error.name = name; this.message = error.message = message; this.stack = error.stack = stack; } } exports.ProcessError = ProcessError; class ChildProcess extends Process_1.Process { constructor(name, opts) { super(name, opts); // Listen for and handle messages from parent process. this._message = Observable_1.Observable.fromEvent(process, "message"); this._message .subscribe((message) => this.handleMessage(message)); // Forward log and metric messages to parent process. this.container.logs .subscribe((log) => this.send(EProcessMessageType.Log, log)); this.container.metrics .subscribe((metric) => this.send(EProcessMessageType.Metric, metric)); } /** Extract serialisable error properties to object. */ static serialiseError(error) { return { name: error.name, message: error.message, stack: error.stack, }; } /** Convert serialised error to error instance. */ static deserialiseError(error) { return new ProcessError(error.name || "", error.message || "", error.stack || ""); } /** Handle method call requests. */ static handleCallRequest(emitter, container, data) { const type = EProcessMessageType.CallResponse; const responseData = { id: data.id }; try { // Retrieve target module and make subscribe call to method. const mod = container.resolve(data.target); const method = mod[data.method].bind(mod); method(...data.args) .subscribe({ next: (value) => { const nextData = Object.assign({ next: value }, responseData); emitter.send(type, nextData); }, error: (error) => { error = ChildProcess.serialiseError(error); const errorData = Object.assign({ error }, responseData); emitter.send(type, errorData); }, complete: () => { const completeData = Object.assign({ complete: true }, responseData); emitter.send(type, completeData); }, }); } catch (error) { error = ChildProcess.serialiseError(error); const errorData = Object.assign({ error }, responseData); emitter.send(type, errorData); } } /** Handle method call responses. */ static handleCallResponse(messageObservable, id, args, timeout) { return messageObservable .filter((message) => { // Filter by message type and identifier. if (message.type === EProcessMessageType.CallResponse) { const data = message.data; return data.id === id; } return false; }) .map((message) => { // Cast message data to type. const data = message.data; return data; }) .timeout(timeout) .takeWhile((data) => { // Complete observable when complete message received. return !data.complete; }) .mergeMap((data) => { // Throw error or emit next data. if (data.error != null) { const error = ChildProcess.deserialiseError(data.error); return Observable_1.Observable.throw(error); } else { return Observable_1.Observable.of(data.next); } }); } /** Messages received from parent process. */ get message() { return this._message; } /** Send message to parent process. */ send(type, data) { if (process.send != null) { process.send({ type, data }); } } /** Make call to module.method in parent process. */ call(target, method, options = {}) { const timeout = options.timeout || ChildProcess.DEFAULT_TIMEOUT; const args = options.args || []; const id = this.identifier; this.debug(`call '${target}.${method}' '${id}'`); // Send call request to parent process. const sendData = { id, target, method, args }; this.send(EProcessMessageType.CallRequest, sendData); return ChildProcess.handleCallResponse(this.message, id, args, timeout); } /** Handle messages received from parent process. */ handleMessage(message) { switch (message.type) { // Call request received from parent. case EProcessMessageType.CallRequest: { ChildProcess.handleCallRequest(this, this.container, message.data); break; } } } } /** Default call method timeout. */ ChildProcess.DEFAULT_TIMEOUT = 10000; exports.ChildProcess = ChildProcess; //# sourceMappingURL=ChildProcess.js.map