"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Child = void 0; var coreWorker = _interopRequireWildcard(require("./core-worker")); function _assert() { const data = _interopRequireDefault(require("assert")); _assert = function () { return data; }; return data; } function _nullthrows() { const data = _interopRequireDefault(require("nullthrows")); _nullthrows = function () { return data; }; return data; } function _logger() { const data = _interopRequireWildcard(require("@parcel/logger")); _logger = function () { return data; }; return data; } function _diagnostic() { const data = _interopRequireWildcard(require("@parcel/diagnostic")); _diagnostic = function () { return data; }; return data; } function _core() { const data = require("@parcel/core"); _core = function () { return data; }; return data; } var _bus = _interopRequireDefault(require("./bus")); function _profiler() { const data = require("@parcel/profiler"); _profiler = function () { return data; }; return data; } var _Handle2 = _interopRequireDefault(require("./Handle")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } // The import of './Handle' should really be imported eagerly (with @babel/plugin-transform-modules-commonjs's lazy mode). const Handle = _Handle2.default; class Child { callQueue = []; maxConcurrentCalls = 10; responseId = 0; responseQueue = new Map(); handles = new Map(); sharedReferences = new Map(); sharedReferencesByValue = new Map(); constructor(ChildBackend) { this.child = new ChildBackend(m => { this.messageListener(m); }, () => this.handleEnd()); // Monitior all logging events inside this child process and forward to // the main process via the bus. this.loggerDisposable = _logger().default.onLog(event => { _bus.default.emit('logEvent', event); }); // .. and do the same for trace events this.tracerDisposable = _profiler().tracer.onTrace(event => { _bus.default.emit('traceEvent', event); }); } workerApi = { callMaster: (request, awaitResponse = true) => this.addCall(request, awaitResponse), createReverseHandle: fn => this.createReverseHandle(fn), runHandle: (handle, args) => this.workerApi.callMaster({ handle: handle.id, args }, true), getSharedReference: ref => this.sharedReferences.get(ref), resolveSharedReference: value => this.sharedReferencesByValue.get(value) }; messageListener(message) { if (message.type === 'response') { return this.handleResponse(message); } else if (message.type === 'request') { return this.handleRequest(message); } } send(data) { this.child.send(data); } async childInit(module, childId) { // $FlowFixMe if (process.browser) { if (module === '@parcel/core/src/worker.js') { this.module = coreWorker; } else { throw new Error('No dynamic require possible: ' + module); } } else { // $FlowFixMe this must be dynamic this.module = require(module); } this.childId = childId; if (this.module.childInit != null) { await this.module.childInit(); } } async handleRequest(data) { let { idx, method, args, handle: handleId } = data; let child = (0, _nullthrows().default)(data.child); const responseFromContent = content => ({ idx, child, type: 'response', contentType: 'data', content }); const errorResponseFromError = e => ({ idx, child, type: 'response', contentType: 'error', content: (0, _diagnostic().anyToDiagnostic)(e) }); let result; if (handleId != null) { try { var _this$handles$get; let fn = (0, _nullthrows().default)((_this$handles$get = this.handles.get(handleId)) === null || _this$handles$get === void 0 ? void 0 : _this$handles$get.fn); result = responseFromContent(fn(...args)); } catch (e) { result = errorResponseFromError(e); } } else if (method === 'childInit') { try { let [moduleName, childOptions] = args; if (childOptions.shouldPatchConsole) { (0, _logger().patchConsole)(); } else { (0, _logger().unpatchConsole)(); } if (childOptions.shouldTrace) { _profiler().tracer.enable(); } result = responseFromContent(await this.childInit(moduleName, child)); } catch (e) { result = errorResponseFromError(e); } } else if (method === 'startProfile') { this.profiler = new (_profiler().SamplingProfiler)(); try { result = responseFromContent(await this.profiler.startProfiling()); } catch (e) { result = errorResponseFromError(e); } } else if (method === 'endProfile') { try { let res = this.profiler ? await this.profiler.stopProfiling() : null; result = responseFromContent(res); } catch (e) { result = errorResponseFromError(e); } } else if (method === 'takeHeapSnapshot') { try { let v8 = require('v8'); result = responseFromContent(v8.writeHeapSnapshot('heap-' + args[0] + '-' + (this.childId ? 'worker' + this.childId : 'main') + '.heapsnapshot')); } catch (e) { result = errorResponseFromError(e); } } else if (method === 'createSharedReference') { let [ref, _value] = args; let value = _value instanceof ArrayBuffer ? // In the case the value is pre-serialized as a buffer, // deserialize it. (0, _core().deserialize)(Buffer.from(_value)) : _value; this.sharedReferences.set(ref, value); this.sharedReferencesByValue.set(value, ref); result = responseFromContent(null); } else if (method === 'deleteSharedReference') { let ref = args[0]; let value = this.sharedReferences.get(ref); this.sharedReferencesByValue.delete(value); this.sharedReferences.delete(ref); result = responseFromContent(null); } else { try { result = responseFromContent( // $FlowFixMe await this.module[method](this.workerApi, ...args)); } catch (e) { result = errorResponseFromError(e); } } try { this.send(result); } catch (e) { result = this.send(errorResponseFromError(e)); } } handleResponse(data) { let idx = (0, _nullthrows().default)(data.idx); let contentType = data.contentType; let content = data.content; let call = (0, _nullthrows().default)(this.responseQueue.get(idx)); if (contentType === 'error') { (0, _assert().default)(typeof content !== 'string'); call.reject(new (_diagnostic().default)({ diagnostic: 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 addCall(request, awaitResponse = true) { var _promise; // $FlowFixMe let call = { ...request, type: 'request', child: this.childId, // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381 awaitResponse, resolve: () => {}, reject: () => {} }; let promise; if (awaitResponse) { promise = new Promise((resolve, reject) => { call.resolve = resolve; call.reject = reject; }); } this.callQueue.push(call); this.processQueue(); return (_promise = promise) !== null && _promise !== void 0 ? _promise : Promise.resolve(); } sendRequest(call) { let idx; if (call.awaitResponse) { idx = this.responseId++; this.responseQueue.set(idx, call); } this.send({ idx, child: call.child, type: call.type, location: call.location, handle: call.handle, method: call.method, args: call.args, awaitResponse: call.awaitResponse }); } processQueue() { if (!this.callQueue.length) { return; } if (this.responseQueue.size < this.maxConcurrentCalls) { this.sendRequest(this.callQueue.shift()); } } handleEnd() { this.loggerDisposable.dispose(); this.tracerDisposable.dispose(); } createReverseHandle(fn) { let handle = new Handle({ fn, childId: this.childId }); this.handles.set(handle.id, handle); return handle; } } exports.Child = Child;