UNPKG

puppeteer-core

Version:

A high-level API to control headless Chrome over the DevTools Protocol

136 lines 4.24 kB
"use strict"; /** * @license * Copyright 2023 Google Inc. * SPDX-License-Identifier: Apache-2.0 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Callback = exports.CallbackRegistry = void 0; const Deferred_js_1 = require("../util/Deferred.js"); const ErrorLike_js_1 = require("../util/ErrorLike.js"); const incremental_id_generator_js_1 = require("../util/incremental-id-generator.js"); const Errors_js_1 = require("./Errors.js"); const util_js_1 = require("./util.js"); /** * Manages callbacks and their IDs for the protocol request/response communication. * * @internal */ class CallbackRegistry { #callbacks = new Map(); #idGenerator = (0, incremental_id_generator_js_1.createIncrementalIdGenerator)(); create(label, timeout, request) { const callback = new Callback(this.#idGenerator(), label, timeout); this.#callbacks.set(callback.id, callback); try { request(callback.id); } catch (error) { // We still throw sync errors synchronously and clean up the scheduled // callback. callback.promise.catch(util_js_1.debugError).finally(() => { this.#callbacks.delete(callback.id); }); callback.reject(error); throw error; } // Must only have sync code up until here. return callback.promise.finally(() => { this.#callbacks.delete(callback.id); }); } reject(id, message, originalMessage) { const callback = this.#callbacks.get(id); if (!callback) { return; } this._reject(callback, message, originalMessage); } rejectRaw(id, error) { const callback = this.#callbacks.get(id); if (!callback) { return; } callback.reject(error); } _reject(callback, errorMessage, originalMessage) { let error; let message; if (errorMessage instanceof Errors_js_1.ProtocolError) { error = errorMessage; error.cause = callback.error; message = errorMessage.message; } else { error = callback.error; message = errorMessage; } callback.reject((0, ErrorLike_js_1.rewriteError)(error, `Protocol error (${callback.label}): ${message}`, originalMessage)); } resolve(id, value) { const callback = this.#callbacks.get(id); if (!callback) { return; } callback.resolve(value); } clear() { for (const callback of this.#callbacks.values()) { // TODO: probably we can accept error messages as params. this._reject(callback, new Errors_js_1.TargetCloseError('Target closed')); } this.#callbacks.clear(); } /** * @internal */ getPendingProtocolErrors() { const result = []; for (const callback of this.#callbacks.values()) { result.push(new Error(`${callback.label} timed out. Trace: ${callback.error.stack}`)); } return result; } } exports.CallbackRegistry = CallbackRegistry; /** * @internal */ class Callback { #id; #error = new Errors_js_1.ProtocolError(); #deferred = Deferred_js_1.Deferred.create(); #timer; #label; constructor(id, label, timeout) { this.#id = id; this.#label = label; if (timeout) { this.#timer = setTimeout(() => { this.#deferred.reject((0, ErrorLike_js_1.rewriteError)(this.#error, `${label} timed out. Increase the 'protocolTimeout' setting in launch/connect calls for a higher timeout if needed.`)); }, timeout); } } resolve(value) { clearTimeout(this.#timer); this.#deferred.resolve(value); } reject(error) { clearTimeout(this.#timer); this.#deferred.reject(error); } get id() { return this.#id; } get promise() { return this.#deferred.valueOrThrow(); } get error() { return this.#error; } get label() { return this.#label; } } exports.Callback = Callback; //# sourceMappingURL=CallbackRegistry.js.map