123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- "use strict";
- const { ConnectionDelegate } = require("@zoon/rialto"),
- Logger = require("@zoon/rialto/src/node-process/Logger"),
- ConsoleInterceptor = require("@zoon/rialto/src/node-process/NodeInterceptors/ConsoleInterceptor"),
- StandardStreamsInterceptor = require("@zoon/rialto/src/node-process/NodeInterceptors/StandardStreamsInterceptor");
- /**
- * Handle the requests of a connection to control Puppeteer.
- */
- class PuppeteerConnectionDelegate extends ConnectionDelegate {
- /**
- * Constructor.
- *
- * @param {Object} options
- */
- constructor(options) {
- super(options);
- this.browsers = new Set();
- this.addSignalEventListeners();
- }
- /**
- * @inheritdoc
- */
- async handleInstruction(instruction, responseHandler, errorHandler) {
- if (this.options.js_extra) {
- eval(this.options.js_extra);
- } else {
- const puppeteer = require("puppeteer");
- instruction.setDefaultResource(puppeteer);
- }
- let value = null;
- try {
- value = await instruction.execute();
- } catch (error) {
- if (instruction.shouldCatchErrors()) {
- return errorHandler(error);
- }
- throw error;
- }
- if (this.isInstanceOf(value, "Browser")) {
- this.browsers.add(value);
- if (this.options.log_browser_console === true) {
- const initialPages = await value.pages();
- initialPages.forEach((page) =>
- page.on("console", this.logConsoleMessage)
- );
- }
- }
- if (
- this.options.log_browser_console === true &&
- this.isInstanceOf(value, "Page")
- ) {
- value.on("console", this.logConsoleMessage);
- }
- responseHandler(value);
- }
- /**
- * Checks if a value is an instance of a class. The check must be done with the `[object].constructor.name`
- * property because relying on Puppeteer's constructors isn't viable since the exports aren't constrained by semver.
- *
- * @protected
- * @param {*} value
- * @param {string} className
- *
- * @see {@link https://github.com/GoogleChrome/puppeteer/issues/3067|Puppeteer's issue about semver on exports}
- */
- isInstanceOf(value, className) {
- const nonObjectValues = [undefined, null];
- return (
- !nonObjectValues.includes(value) &&
- !nonObjectValues.includes(value.constructor) &&
- (value.constructor.name === className ||
- value.constructor.name === "CDP" + className)
- );
- }
- /**
- * Log the console message.
- *
- * @param {ConsoleMessage} consoleMessage
- */
- async logConsoleMessage(consoleMessage) {
- const type = consoleMessage.type();
- if (!ConsoleInterceptor.typeIsSupported(type)) {
- return;
- }
- const level = ConsoleInterceptor.getLevelFromType(type);
- const args = await Promise.all(
- consoleMessage.args().map((arg) => arg.jsonValue())
- );
- StandardStreamsInterceptor.startInterceptingStrings((message) => {
- Logger.log("Browser", level, ConsoleInterceptor.formatMessage(message));
- });
- ConsoleInterceptor.originalConsole[type](...args);
- StandardStreamsInterceptor.stopInterceptingStrings();
- }
- /**
- * Listen for process signal events.
- *
- * @protected
- */
- addSignalEventListeners() {
- for (let eventName of ["SIGINT", "SIGTERM", "SIGHUP"]) {
- process.on(eventName, () => {
- this.closeAllBrowsers();
- process.exit();
- });
- }
- }
- /**
- * Close all the browser instances when the process exits.
- *
- * Calling this method before exiting Node is mandatory since Puppeteer doesn't seem to handle that properly.
- *
- * @protected
- */
- closeAllBrowsers() {
- for (let browser of this.browsers.values()) {
- browser.close();
- }
- }
- }
- module.exports = PuppeteerConnectionDelegate;
|