You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

150 lines
6.5 KiB

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const RpcIpcMessagePortClosedError_1 = require("./error/RpcIpcMessagePortClosedError");
function createRpcIpcMessagePort(process) {
const messageListeners = new Set();
const errorListeners = new Set();
let closedError;
const handleExit = (code, signal) => __awaiter(this, void 0, void 0, function* () {
closedError = new RpcIpcMessagePortClosedError_1.RpcIpcMessagePortClosedError(code
? `Process ${process.pid} exited with code "${code}" [${signal}]`
: `Process ${process.pid} exited [${signal}].`, code, signal);
errorListeners.forEach((listener) => {
if (closedError) {
listener(closedError);
}
});
yield port.close();
});
const handleMessage = (message) => {
messageListeners.forEach((listener) => {
listener(message);
});
};
process.on('message', handleMessage);
process.on('exit', handleExit);
const port = {
dispatchMessage: (message) => __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
if (!process.connected) {
reject(closedError ||
new RpcIpcMessagePortClosedError_1.RpcIpcMessagePortClosedError(`Process ${process.pid} doesn't have open IPC channels`));
}
if (process.send) {
process.send(Object.assign(Object.assign({}, message), { source: process.pid }), undefined, undefined, (sendError) => {
if (sendError) {
if (!closedError) {
closedError = new RpcIpcMessagePortClosedError_1.RpcIpcMessagePortClosedError(`Cannot send the message - the message port has been closed for the process ${process.pid}.`);
}
reject(closedError);
}
else {
resolve();
}
});
}
else {
reject(new RpcIpcMessagePortClosedError_1.RpcIpcMessagePortClosedError(`Process ${process.pid} doesn't have IPC channels`));
}
});
}),
addMessageListener: (listener) => {
messageListeners.add(listener);
},
removeMessageListener: (listener) => {
messageListeners.delete(listener);
},
addErrorListener: (listener) => {
errorListeners.add(listener);
},
removeErrorListener: (listener) => {
errorListeners.delete(listener);
},
isOpen: () => !!process.connected,
open: () => __awaiter(this, void 0, void 0, function* () {
if (!process.connected || closedError) {
throw (closedError ||
new RpcIpcMessagePortClosedError_1.RpcIpcMessagePortClosedError(`Cannot open closed IPC channel for process ${process.pid}.`));
}
}),
close: () => __awaiter(this, void 0, void 0, function* () {
process.off('message', handleMessage);
process.off('exit', handleExit);
messageListeners.clear();
errorListeners.clear();
if (process.disconnect && process.connected) {
process.disconnect();
}
}),
};
return port;
}
exports.createRpcIpcMessagePort = createRpcIpcMessagePort;
function createRpcIpcForkedProcessMessagePort(filePath, memoryLimit = 2048, autoRecreate = true) {
function createChildProcess() {
return child_process_1.fork(filePath, [], {
execArgv: [`--max-old-space-size=${memoryLimit}`],
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
});
}
const messageListeners = new Set();
const errorListeners = new Set();
let childProcess = createChildProcess();
let port = createRpcIpcMessagePort(childProcess);
return {
dispatchMessage: (message) => port.dispatchMessage(message),
addMessageListener: (listener) => {
messageListeners.add(listener);
return port.addMessageListener(listener);
},
removeMessageListener: (listener) => {
messageListeners.delete(listener);
return port.removeMessageListener(listener);
},
addErrorListener: (listener) => {
errorListeners.add(listener);
return port.addErrorListener(listener);
},
removeErrorListener: (listener) => {
errorListeners.delete(listener);
return port.removeErrorListener(listener);
},
isOpen: () => port.isOpen(),
open: () => __awaiter(this, void 0, void 0, function* () {
if (!port.isOpen() && autoRecreate) {
// recreate the process and add existing message listeners
childProcess = createChildProcess();
port = createRpcIpcMessagePort(childProcess);
messageListeners.forEach((listener) => {
port.addMessageListener(listener);
});
errorListeners.forEach((listener) => {
port.addErrorListener(listener);
});
}
else {
return port.open();
}
}),
close: () => __awaiter(this, void 0, void 0, function* () {
yield port.close();
messageListeners.clear();
errorListeners.clear();
if (childProcess) {
childProcess.kill('SIGTERM');
childProcess = undefined;
}
}),
};
}
exports.createRpcIpcForkedProcessMessagePort = createRpcIpcForkedProcessMessagePort;