processHost.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.ProcessHost = void 0;
  6. var _child_process = _interopRequireDefault(require("child_process"));
  7. var _events = require("events");
  8. var _utilsBundle = require("playwright-core/lib/utilsBundle");
  9. var _esmUtils = require("../transform/esmUtils");
  10. var _utils = require("playwright-core/lib/utils");
  11. var _esmLoaderHost = require("../common/esmLoaderHost");
  12. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  13. /**
  14. * Copyright Microsoft Corporation. All rights reserved.
  15. *
  16. * Licensed under the Apache License, Version 2.0 (the "License");
  17. * you may not use this file except in compliance with the License.
  18. * You may obtain a copy of the License at
  19. *
  20. * http://www.apache.org/licenses/LICENSE-2.0
  21. *
  22. * Unless required by applicable law or agreed to in writing, software
  23. * distributed under the License is distributed on an "AS IS" BASIS,
  24. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25. * See the License for the specific language governing permissions and
  26. * limitations under the License.
  27. */
  28. class ProcessHost extends _events.EventEmitter {
  29. constructor(runnerScript, processName, env) {
  30. super();
  31. this.process = void 0;
  32. this._didSendStop = false;
  33. this._processDidExit = false;
  34. this._didExitAndRanOnExit = false;
  35. this._runnerScript = void 0;
  36. this._lastMessageId = 0;
  37. this._callbacks = new Map();
  38. this._processName = void 0;
  39. this._producedEnv = {};
  40. this._extraEnv = void 0;
  41. this._runnerScript = runnerScript;
  42. this._processName = processName;
  43. this._extraEnv = env;
  44. }
  45. async startRunner(runnerParams, options = {}) {
  46. var _this$process$stdout, _this$process$stderr, _process$stdout$getCo, _process$stdout, _process$stderr$getCo, _process$stderr;
  47. (0, _utils.assert)(!this.process, 'Internal error: starting the same process twice');
  48. this.process = _child_process.default.fork(require.resolve('../common/process'), {
  49. detached: false,
  50. env: {
  51. ...process.env,
  52. ...this._extraEnv,
  53. ...(_esmLoaderHost.esmLoaderRegistered ? {
  54. PW_TS_ESM_LOADER_ON: '1'
  55. } : {})
  56. },
  57. stdio: ['ignore', options.onStdOut ? 'pipe' : 'inherit', options.onStdErr && !process.env.PW_RUNNER_DEBUG ? 'pipe' : 'inherit', 'ipc'],
  58. ...(process.env.PW_TS_ESM_LEGACY_LOADER_ON ? {
  59. execArgv: (0, _esmUtils.execArgvWithExperimentalLoaderOptions)()
  60. } : {})
  61. });
  62. this.process.on('exit', async (code, signal) => {
  63. this._processDidExit = true;
  64. await this.onExit();
  65. this._didExitAndRanOnExit = true;
  66. this.emit('exit', {
  67. unexpectedly: !this._didSendStop,
  68. code,
  69. signal
  70. });
  71. });
  72. this.process.on('error', e => {}); // do not yell at a send to dead process.
  73. this.process.on('message', message => {
  74. if (_utilsBundle.debug.enabled('pw:test:protocol')) (0, _utilsBundle.debug)('pw:test:protocol')('◀ RECV ' + JSON.stringify(message));
  75. if (message.method === '__env_produced__') {
  76. const producedEnv = message.params;
  77. this._producedEnv = Object.fromEntries(producedEnv.map(e => {
  78. var _e$;
  79. return [e[0], (_e$ = e[1]) !== null && _e$ !== void 0 ? _e$ : undefined];
  80. }));
  81. } else if (message.method === '__dispatch__') {
  82. const {
  83. id,
  84. error,
  85. method,
  86. params,
  87. result
  88. } = message.params;
  89. if (id && this._callbacks.has(id)) {
  90. const {
  91. resolve,
  92. reject
  93. } = this._callbacks.get(id);
  94. this._callbacks.delete(id);
  95. if (error) {
  96. const errorObject = new Error(error.message);
  97. errorObject.stack = error.stack;
  98. reject(errorObject);
  99. } else {
  100. resolve(result);
  101. }
  102. } else {
  103. this.emit(method, params);
  104. }
  105. } else {
  106. this.emit(message.method, message.params);
  107. }
  108. });
  109. if (options.onStdOut) (_this$process$stdout = this.process.stdout) === null || _this$process$stdout === void 0 ? void 0 : _this$process$stdout.on('data', options.onStdOut);
  110. if (options.onStdErr) (_this$process$stderr = this.process.stderr) === null || _this$process$stderr === void 0 ? void 0 : _this$process$stderr.on('data', options.onStdErr);
  111. const error = await new Promise(resolve => {
  112. this.process.once('exit', (code, signal) => resolve({
  113. unexpectedly: true,
  114. code,
  115. signal
  116. }));
  117. this.once('ready', () => resolve(undefined));
  118. });
  119. if (error) return error;
  120. const processParams = {
  121. stdoutParams: {
  122. rows: process.stdout.rows,
  123. columns: process.stdout.columns,
  124. colorDepth: ((_process$stdout$getCo = (_process$stdout = process.stdout).getColorDepth) === null || _process$stdout$getCo === void 0 ? void 0 : _process$stdout$getCo.call(_process$stdout)) || 8
  125. },
  126. stderrParams: {
  127. rows: process.stderr.rows,
  128. columns: process.stderr.columns,
  129. colorDepth: ((_process$stderr$getCo = (_process$stderr = process.stderr).getColorDepth) === null || _process$stderr$getCo === void 0 ? void 0 : _process$stderr$getCo.call(_process$stderr)) || 8
  130. },
  131. processName: this._processName
  132. };
  133. this.send({
  134. method: '__init__',
  135. params: {
  136. processParams,
  137. runnerScript: this._runnerScript,
  138. runnerParams
  139. }
  140. });
  141. }
  142. sendMessage(message) {
  143. const id = ++this._lastMessageId;
  144. this.send({
  145. method: '__dispatch__',
  146. params: {
  147. id,
  148. ...message
  149. }
  150. });
  151. return new Promise((resolve, reject) => {
  152. this._callbacks.set(id, {
  153. resolve,
  154. reject
  155. });
  156. });
  157. }
  158. sendMessageNoReply(message) {
  159. this.sendMessage(message).catch(() => {});
  160. }
  161. async onExit() {}
  162. async stop() {
  163. if (!this._processDidExit && !this._didSendStop) {
  164. this.send({
  165. method: '__stop__'
  166. });
  167. this._didSendStop = true;
  168. }
  169. if (!this._didExitAndRanOnExit) await new Promise(f => this.once('exit', f));
  170. }
  171. didSendStop() {
  172. return this._didSendStop;
  173. }
  174. producedEnv() {
  175. return this._producedEnv;
  176. }
  177. send(message) {
  178. var _this$process;
  179. if (_utilsBundle.debug.enabled('pw:test:protocol')) (0, _utilsBundle.debug)('pw:test:protocol')('SEND ► ' + JSON.stringify(message));
  180. (_this$process = this.process) === null || _this$process === void 0 ? void 0 : _this$process.send(message);
  181. }
  182. }
  183. exports.ProcessHost = ProcessHost;