UNPKG

react-saasify-chrisvxd

Version:

React components for Saasify web clients.

145 lines (120 loc) 3.22 kB
const {errorUtils} = require('@parcel/utils'); class Child { constructor() { if (!process.send) { throw new Error('Only create Child instances in a worker!'); } 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(); } let type = data.type; if (type === 'response') { return this.handleResponse(data); } else if (type === 'request') { return this.handleRequest(data); } } async send(data) { process.send(data, 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(); } } }); } childInit(module, childId) { this.module = require(module); this.childId = childId; } async handleRequest(data) { 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'; if (method === 'childInit') { result.content = this.childInit(...args, child); } else { result.content = await this.module[method](...args); } } catch (e) { result.contentType = 'error'; result.content = errorUtils.errorToJson(e); } this.send(result); } async handleResponse(data) { let idx = data.idx; let contentType = data.contentType; let content = data.content; let call = this.responseQueue.get(idx); if (contentType === 'error') { call.reject(errorUtils.jsonToError(content)); } else { call.resolve(content); } this.responseQueue.delete(idx); // Process the next call this.processQueue(); } // Keep in mind to make sure responses to these calls are JSON.Stringify safe async addCall(request, awaitResponse = true) { let call = request; call.type = 'request'; call.child = this.childId; call.awaitResponse = awaitResponse; let promise; if (awaitResponse) { promise = new Promise((resolve, reject) => { call.resolve = resolve; call.reject = reject; }); } this.callQueue.push(call); this.processQueue(); return promise; } async sendRequest(call) { let idx; if (call.awaitResponse) { idx = this.responseId++; this.responseQueue.set(idx, call); } this.send({ idx: idx, child: call.child, type: call.type, location: call.location, method: call.method, args: call.args, awaitResponse: call.awaitResponse }); } async processQueue() { if (!this.callQueue.length) { return; } if (this.responseQueue.size < this.maxConcurrentCalls) { this.sendRequest(this.callQueue.shift()); } } end() { process.exit(); } } let child = new Child(); process.on('message', child.messageListener.bind(child)); module.exports = child;