'use strict'; function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } const errorUtils = require('./errorUtils'); class Child { constructor() { this.module = undefined; this.childId = undefined; this.callQueue = []; this.responseQueue = new Map(); this.responseId = 0; this.maxConcurrentCalls = 10; } messageListener(data) { if (data === 'die') { return this.end(); } if (data.type === 'module' && data.module && !this.module) { this.module = require(data.module); this.childId = data.child; if (this.module.setChildReference) { this.module.setChildReference(this); } return; } let type = data.type; if (type === 'response') { return this.handleResponse(data); } else if (type === 'request') { return this.handleRequest(data); } } send(data) { var _this = this; return _asyncToGenerator(function* () { process.send(data, function (err) { if (err && err instanceof Error) { if (err.code === 'ERR_IPC_CHANNEL_CLOSED') { // IPC connection closed // no need to keep the worker running if it can't send or receive data return _this.end(); } } }); })(); } handleRequest(data) { var _this2 = this; return _asyncToGenerator(function* () { let idx = data.idx; let child = data.child; let method = data.method; let args = data.args; let result = { idx, child, type: 'response' }; try { result.contentType = 'data'; result.content = yield _this2.module[method](...args); } catch (e) { result.contentType = 'error'; result.content = errorUtils.errorToJson(e); } _this2.send(result); })(); } handleResponse(data) { var _this3 = this; return _asyncToGenerator(function* () { let idx = data.idx; let contentType = data.contentType; let content = data.content; let call = _this3.responseQueue.get(idx); if (contentType === 'error') { call.reject(errorUtils.jsonToError(content)); } else { call.resolve(content); } _this3.responseQueue.delete(idx); // Process the next call _this3.processQueue(); })(); } // Keep in mind to make sure responses to these calls are JSON.Stringify safe addCall(request, awaitResponse = true) { var _this4 = this; return _asyncToGenerator(function* () { let call = request; call.type = 'request'; call.child = _this4.childId; call.awaitResponse = awaitResponse; let promise; if (awaitResponse) { promise = new Promise(function (resolve, reject) { call.resolve = resolve; call.reject = reject; }); } _this4.callQueue.push(call); _this4.processQueue(); return promise; })(); } sendRequest(call) { var _this5 = this; return _asyncToGenerator(function* () { let idx; if (call.awaitResponse) { idx = _this5.responseId++; _this5.responseQueue.set(idx, call); } _this5.send({ idx: idx, child: call.child, type: call.type, location: call.location, method: call.method, args: call.args, awaitResponse: call.awaitResponse }); })(); } processQueue() { var _this6 = this; return _asyncToGenerator(function* () { if (!_this6.callQueue.length) { return; } if (_this6.responseQueue.size < _this6.maxConcurrentCalls) { _this6.sendRequest(_this6.callQueue.shift()); } })(); } end() { return process.exit(0); } } let child = new Child(); process.on('message', child.messageListener.bind(child)); module.exports = child;