wrap-rpc.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. Object.defineProperty(exports, "__esModule", { value: true });
  12. exports.wrapRpc = void 0;
  13. const controlled_promise_1 = require("../utils/async/controlled-promise");
  14. const rpc_error_1 = require("./rpc-error");
  15. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  16. function wrapRpc(childProcess) {
  17. return ((...args) => __awaiter(this, void 0, void 0, function* () {
  18. if (!childProcess.send) {
  19. throw new Error(`Process ${childProcess.pid} doesn't have IPC channels`);
  20. }
  21. else if (!childProcess.connected) {
  22. throw new Error(`Process ${childProcess.pid} doesn't have open IPC channels`);
  23. }
  24. const id = uuid();
  25. // create promises
  26. const { promise: resultPromise, resolve: resolveResult, reject: rejectResult, } = (0, controlled_promise_1.createControlledPromise)();
  27. const { promise: sendPromise, resolve: resolveSend, reject: rejectSend, } = (0, controlled_promise_1.createControlledPromise)();
  28. const handleMessage = (message) => {
  29. if ((message === null || message === void 0 ? void 0 : message.id) === id) {
  30. if (message.type === 'resolve') {
  31. // assume the contract is respected
  32. resolveResult(message.value);
  33. removeHandlers();
  34. }
  35. else if (message.type === 'reject') {
  36. rejectResult(message.error);
  37. removeHandlers();
  38. }
  39. }
  40. };
  41. const handleClose = (code, signal) => {
  42. rejectResult(new rpc_error_1.RpcExitError(code
  43. ? `Process ${childProcess.pid} exited with code ${code}` +
  44. (signal ? ` [${signal}]` : '')
  45. : `Process ${childProcess.pid} exited` + (signal ? ` [${signal}]` : ''), code, signal));
  46. removeHandlers();
  47. };
  48. // to prevent event handler leaks
  49. const removeHandlers = () => {
  50. childProcess.off('message', handleMessage);
  51. childProcess.off('close', handleClose);
  52. };
  53. // add event listeners
  54. childProcess.on('message', handleMessage);
  55. childProcess.on('close', handleClose);
  56. // send call message
  57. childProcess.send({
  58. type: 'call',
  59. id,
  60. args,
  61. }, (error) => {
  62. if (error) {
  63. rejectSend(error);
  64. removeHandlers();
  65. }
  66. else {
  67. resolveSend(undefined);
  68. }
  69. });
  70. return sendPromise.then(() => resultPromise);
  71. }));
  72. }
  73. exports.wrapRpc = wrapRpc;
  74. function uuid() {
  75. return new Array(4)
  76. .fill(0)
  77. .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))
  78. .join('-');
  79. }