Tons of Solutions Engineering work done today for the rest of the CS team! Headway, Howard Hanna, Engels, Brighton, etc. Also completed Datasnippers auth flow and worked on Anthology's script. Cloned Anthology's courses (900..) and will clone Full Story on Monday.

This commit is contained in:
Norm Rasmussen
2024-01-05 17:07:59 -05:00
parent ce261975ca
commit a5fe4bd2c8
3157 changed files with 554269 additions and 16 deletions

View File

@ -0,0 +1,27 @@
import { type ChromeReleaseChannel, type Process } from '@puppeteer/browsers';
import type { MapperOptions } from '../bidiMapper/BidiServer.js';
import { MapperCdpConnection } from './MapperCdpConnection.js';
import type { SimpleTransport } from './SimpleTransport.js';
type ChromeOptions = {
chromeArgs: string[];
chromeBinary?: string;
channel: ChromeReleaseChannel;
headless: boolean;
};
/**
* BrowserProcess is responsible for running the browser and BiDi Mapper within
* it.
* 1. Launch Chromium (using Puppeteer for now).
* 2. Get `BiDi-CDP` mapper JS binaries using `MapperReader`.
* 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
* 4. Bind `BiDi-CDP` mapper to the `BiDi server` to forward messages from BiDi
* Mapper to the client.
*/
export declare class BrowserInstance {
#private;
static run(chromeOptions: ChromeOptions, mapperOptions: MapperOptions, verbose: boolean): Promise<BrowserInstance>;
constructor(mapperCdpConnection: MapperCdpConnection, browserProcess: Process);
close(): Promise<void>;
bidiSession(): SimpleTransport;
}
export {};

View File

@ -0,0 +1,125 @@
"use strict";
/*
* Copyright 2023 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserInstance = void 0;
const promises_1 = require("fs/promises");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const browsers_1 = require("@puppeteer/browsers");
const debug_1 = __importDefault(require("debug"));
const ws_1 = __importDefault(require("ws"));
const CdpConnection_js_1 = require("../cdp/CdpConnection.js");
const WebsocketTransport_js_1 = require("../utils/WebsocketTransport.js");
const MapperCdpConnection_js_1 = require("./MapperCdpConnection.js");
const reader_js_1 = require("./reader.js");
const debugInternal = (0, debug_1.default)('bidi:mapper:internal');
/**
* BrowserProcess is responsible for running the browser and BiDi Mapper within
* it.
* 1. Launch Chromium (using Puppeteer for now).
* 2. Get `BiDi-CDP` mapper JS binaries using `MapperReader`.
* 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
* 4. Bind `BiDi-CDP` mapper to the `BiDi server` to forward messages from BiDi
* Mapper to the client.
*/
class BrowserInstance {
#mapperCdpConnection;
#browserProcess;
static async run(chromeOptions, mapperOptions, verbose) {
const profileDir = await (0, promises_1.mkdtemp)(path_1.default.join(os_1.default.tmpdir(), 'web-driver-bidi-server-'));
// See https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
const chromeArguments = [
...(chromeOptions.headless
? ['--headless', '--hide-scrollbars', '--mute-audio']
: []),
// keep-sorted start
'--allow-browser-signin=false',
'--disable-component-update',
'--disable-default-apps',
'--disable-features=DialMediaRouteProvider,TrackingProtection3pcd',
'--disable-infobars',
'--disable-notifications',
'--disable-popup-blocking',
'--disable-search-engine-choice-screen',
'--enable-automation',
'--no-default-browser-check',
'--no-first-run',
'--password-store=basic',
'--remote-debugging-port=9222',
'--use-mock-keychain',
`--user-data-dir=${profileDir}`,
// keep-sorted end
...chromeOptions.chromeArgs.filter((arg) => !arg.startsWith('--headless')),
'about:blank',
];
const executablePath = chromeOptions.chromeBinary ??
process.env['BROWSER_BIN'] ??
(0, browsers_1.computeSystemExecutablePath)({
browser: browsers_1.Browser.CHROME,
channel: chromeOptions.channel,
});
if (!executablePath) {
throw new Error('Could not find Chrome binary');
}
const browserProcess = (0, browsers_1.launch)({
executablePath,
args: chromeArguments,
});
const cdpEndpoint = await browserProcess.waitForLineOutput(browsers_1.CDP_WEBSOCKET_ENDPOINT_REGEX);
// There is a conflict between prettier and eslint here.
// prettier-ignore
const cdpConnection = await this.#establishCdpConnection(cdpEndpoint);
// 2. Get `BiDi-CDP` mapper JS binaries.
const mapperTabSource = await (0, reader_js_1.getMapperTabSource)();
// 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
const mapperCdpConnection = await MapperCdpConnection_js_1.MapperCdpConnection.create(cdpConnection, mapperTabSource, verbose, mapperOptions);
return new BrowserInstance(mapperCdpConnection, browserProcess);
}
constructor(mapperCdpConnection, browserProcess) {
this.#mapperCdpConnection = mapperCdpConnection;
this.#browserProcess = browserProcess;
}
async close() {
// Close the mapper tab.
this.#mapperCdpConnection.close();
// Close browser.
await this.#browserProcess.close();
}
bidiSession() {
return this.#mapperCdpConnection.bidiSession();
}
static #establishCdpConnection(cdpUrl) {
return new Promise((resolve, reject) => {
debugInternal('Establishing session with cdpUrl: ', cdpUrl);
const ws = new ws_1.default(cdpUrl);
ws.once('error', reject);
ws.on('open', () => {
debugInternal('Session established.');
const transport = new WebsocketTransport_js_1.WebSocketTransport(ws);
const connection = new CdpConnection_js_1.CdpConnection(transport);
resolve(connection);
});
});
}
}
exports.BrowserInstance = BrowserInstance;
//# sourceMappingURL=BrowserInstance.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"BrowserInstance.js","sourceRoot":"","sources":["../../../src/bidiServer/BrowserInstance.ts"],"names":[],"mappings":"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"}

View File

@ -0,0 +1,26 @@
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { MapperOptions } from '../bidiMapper/BidiServer.js';
import type { CdpConnection } from '../cdp/CdpConnection.js';
import { SimpleTransport } from './SimpleTransport.js';
export declare class MapperCdpConnection {
#private;
static create(cdpConnection: CdpConnection, mapperTabSource: string, verbose: boolean, mapperOptions: MapperOptions): Promise<MapperCdpConnection>;
private constructor();
close(): void;
bidiSession(): SimpleTransport;
}

View File

@ -0,0 +1,140 @@
"use strict";
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapperCdpConnection = void 0;
const debug_1 = __importDefault(require("debug"));
const SimpleTransport_js_1 = require("./SimpleTransport.js");
const debugInternal = (0, debug_1.default)('bidi:mapper:internal');
const debugInfo = (0, debug_1.default)('bidi:mapper:info');
const debugOthers = (0, debug_1.default)('bidi:mapper:debug:others');
// Memorizes a debug creation
const loggers = new Map();
const getLogger = (type) => {
const prefix = `bidi:mapper:${type}`;
let logger = loggers.get(prefix);
if (!logger) {
logger = (0, debug_1.default)(prefix);
loggers.set(prefix, logger);
}
return logger;
};
class MapperCdpConnection {
#cdpConnection;
#mapperCdpClient;
#bidiSession;
static async create(cdpConnection, mapperTabSource, verbose, mapperOptions) {
try {
const mapperCdpClient = await this.#initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions);
return new MapperCdpConnection(cdpConnection, mapperCdpClient);
}
catch (e) {
cdpConnection.close();
throw e;
}
}
constructor(cdpConnection, mapperCdpClient) {
this.#cdpConnection = cdpConnection;
this.#mapperCdpClient = mapperCdpClient;
this.#bidiSession = new SimpleTransport_js_1.SimpleTransport(async (message) => await this.#sendMessage(message));
this.#mapperCdpClient.on('Runtime.bindingCalled', this.#onBindingCalled);
this.#mapperCdpClient.on('Runtime.consoleAPICalled', this.#onConsoleAPICalled);
// Catch unhandled exceptions in the mapper.
this.#mapperCdpClient.on('Runtime.exceptionThrown', this.#onRuntimeExceptionThrown);
}
async #sendMessage(message) {
try {
await this.#mapperCdpClient.sendCommand('Runtime.evaluate', {
expression: `onBidiMessage(${JSON.stringify(message)})`,
});
}
catch (error) {
debugInternal('Call to onBidiMessage failed', error);
}
}
close() {
this.#cdpConnection.close();
}
bidiSession() {
return this.#bidiSession;
}
#onBindingCalled = (params) => {
if (params.name === 'sendBidiResponse') {
this.#bidiSession.emit('message', params.payload);
}
else if (params.name === 'sendDebugMessage') {
this.#onDebugMessage(params.payload);
}
};
#onDebugMessage = (json) => {
try {
const log = JSON.parse(json);
if (log.logType !== undefined && log.messages !== undefined) {
const logger = getLogger(log.logType);
logger(log.messages);
}
}
catch {
// Fall back to raw log in case of unknown
debugOthers(json);
}
};
#onConsoleAPICalled = (params) => {
debugInfo('consoleAPICalled: %s %O', params.type, params.args.map((arg) => arg.value));
};
#onRuntimeExceptionThrown = (params) => {
debugInfo('exceptionThrown:', params);
};
static async #initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions) {
debugInternal('Initializing Mapper.', mapperOptions);
const browserClient = await cdpConnection.createBrowserSession();
const { targetId: mapperTabTargetId } = await browserClient.sendCommand('Target.createTarget', {
url: 'about:blank',
});
const { sessionId: mapperSessionId } = await browserClient.sendCommand('Target.attachToTarget', { targetId: mapperTabTargetId, flatten: true });
const mapperCdpClient = cdpConnection.getCdpClient(mapperSessionId);
await mapperCdpClient.sendCommand('Runtime.enable');
await browserClient.sendCommand('Target.exposeDevToolsProtocol', {
bindingName: 'cdp',
targetId: mapperTabTargetId,
});
await mapperCdpClient.sendCommand('Runtime.addBinding', {
name: 'sendBidiResponse',
});
if (verbose) {
// Needed to request verbose logs from Mapper.
await mapperCdpClient.sendCommand('Runtime.addBinding', {
name: 'sendDebugMessage',
});
}
// Evaluate Mapper Tab sources in the tab.
await mapperCdpClient.sendCommand('Runtime.evaluate', {
expression: mapperTabSource,
});
await mapperCdpClient.sendCommand('Runtime.evaluate', {
expression: `window.runMapperInstance('${mapperTabTargetId}', ${JSON.stringify(mapperOptions)})`,
awaitPromise: true,
});
debugInternal('Mapper is launched!');
return mapperCdpClient;
}
}
exports.MapperCdpConnection = MapperCdpConnection;
//# sourceMappingURL=MapperCdpConnection.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"MapperCdpConnection.js","sourceRoot":"","sources":["../../../src/bidiServer/MapperCdpConnection.ts"],"names":[],"mappings":"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"}

View File

@ -0,0 +1,13 @@
import { EventEmitter } from '../utils/EventEmitter';
/**
* Implements simple transport that allows sending string messages via
* `sendCommand` and receiving them via `on('message')`.
*/
export declare class SimpleTransport extends EventEmitter<Record<'message', string>> {
#private;
/**
* @param sendCommandDelegate delegate to be called in `sendCommand`.
*/
constructor(sendCommandDelegate: (plainCommand: string) => Promise<void>);
sendCommand(plainCommand: string): Promise<void>;
}

View File

@ -0,0 +1,39 @@
"use strict";
/*
* Copyright 2023 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SimpleTransport = void 0;
const EventEmitter_1 = require("../utils/EventEmitter");
/**
* Implements simple transport that allows sending string messages via
* `sendCommand` and receiving them via `on('message')`.
*/
class SimpleTransport extends EventEmitter_1.EventEmitter {
#sendCommandDelegate;
/**
* @param sendCommandDelegate delegate to be called in `sendCommand`.
*/
constructor(sendCommandDelegate) {
super();
this.#sendCommandDelegate = sendCommandDelegate;
}
async sendCommand(plainCommand) {
await this.#sendCommandDelegate(plainCommand);
}
}
exports.SimpleTransport = SimpleTransport;
//# sourceMappingURL=SimpleTransport.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"SimpleTransport.js","sourceRoot":"","sources":["../../../src/bidiServer/SimpleTransport.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,wDAAmD;AAEnD;;;GAGG;AACH,MAAa,eAAgB,SAAQ,2BAAuC;IACjE,oBAAoB,CAA0C;IAEvE;;OAEG;IACH,YAAY,mBAA4D;QACtE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,YAAoB;QACpC,MAAM,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC;CACF;AAdD,0CAcC"}

View File

@ -0,0 +1,13 @@
import type { ChromeReleaseChannel } from '@puppeteer/browsers';
import debug from 'debug';
export declare const debugInfo: debug.Debugger;
export declare class WebSocketServer {
#private;
/**
* @param bidiPort Port to start ws server on.
* @param channel
* @param headless
* @param verbose
*/
static run(bidiPort: number, channel: ChromeReleaseChannel, headless: boolean, verbose: boolean): void;
}

View File

@ -0,0 +1,339 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocketServer = exports.debugInfo = void 0;
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const http_1 = __importDefault(require("http"));
const debug_1 = __importDefault(require("debug"));
const websocket = __importStar(require("websocket"));
const uuid_js_1 = require("../utils/uuid.js");
const BrowserInstance_js_1 = require("./BrowserInstance.js");
exports.debugInfo = (0, debug_1.default)('bidi:server:info');
const debugInternal = (0, debug_1.default)('bidi:server:internal');
const debugSend = (0, debug_1.default)('bidi:server:SEND â–¸');
const debugRecv = (0, debug_1.default)('bidi:server:RECV â—‚');
class WebSocketServer {
static #sessions = new Map();
/**
* @param bidiPort Port to start ws server on.
* @param channel
* @param headless
* @param verbose
*/
static run(bidiPort, channel, headless, verbose) {
const server = http_1.default.createServer(async (request, response) => {
debugInternal(`${new Date().toString()} Received HTTP ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)}`);
if (!request.url) {
return response.end(404);
}
// https://w3c.github.io/webdriver-bidi/#transport, step 2.
if (request.url === '/session') {
const body = [];
request
.on('data', (chunk) => {
body.push(chunk);
})
.on('end', () => {
const jsonBody = JSON.parse(Buffer.concat(body).toString());
response.writeHead(200, {
'Content-Type': 'application/json;charset=utf-8',
'Cache-Control': 'no-cache',
});
const sessionId = (0, uuid_js_1.uuidv4)();
const session = {
sessionId,
// TODO: launch browser instance and set it to the session after WPT
// tests clean up is switched to pure BiDi.
browserInstancePromise: undefined,
sessionOptions: {
chromeOptions: this.#getChromeOptions(jsonBody.capabilities, channel, headless),
mapperOptions: this.#getMapperOptions(jsonBody.capabilities),
verbose,
},
};
this.#sessions.set(sessionId, session);
const webSocketUrl = `ws://localhost:${bidiPort}/session/${sessionId}`;
debugInternal(`Session created. WebSocket URL: ${JSON.stringify(webSocketUrl)}.`);
response.write(JSON.stringify({
value: {
sessionId,
capabilities: {
webSocketUrl,
},
},
}));
return response.end();
});
return;
}
else if (request.url.startsWith('/session')) {
debugInternal(`Unknown session command ${request.method ?? 'UNKNOWN METHOD'} request for ${request.url} with payload ${await WebSocketServer.#getHttpRequestPayload(request)}. 200 returned.`);
response.writeHead(200, {
'Content-Type': 'application/json;charset=utf-8',
'Cache-Control': 'no-cache',
});
response.write(JSON.stringify({
value: {},
}));
}
else {
debugInternal(`Unknown ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)} with payload ${JSON.stringify(await WebSocketServer.#getHttpRequestPayload(request))}. 404 returned.`);
response.writeHead(404);
}
return response.end();
});
server.listen(bidiPort, () => {
(0, exports.debugInfo)('BiDi server is listening on port', bidiPort);
});
const wsServer = new websocket.server({
httpServer: server,
autoAcceptConnections: false,
});
wsServer.on('request', (request) => {
// Session is set either by Classic or BiDi commands.
let session;
const requestSessionId = (request.resource ?? '').split('/').pop();
debugInternal(`new WS request received. Path: ${JSON.stringify(request.resourceURL.path)}, sessionId: ${JSON.stringify(requestSessionId)}`);
if (requestSessionId !== '' &&
requestSessionId !== undefined &&
!this.#sessions.has(requestSessionId)) {
debugInternal('Unknown session id:', requestSessionId);
request.reject();
return;
}
const connection = request.accept();
session = this.#sessions.get(requestSessionId ?? '');
if (session !== undefined) {
// BrowserInstance is created for each new WS connection, even for the
// same SessionId. This is because WPT uses a single session for all the
// tests, but cleans up tests using WebDriver Classic commands, which is
// not implemented in this Mapper runner.
// TODO: connect to an existing BrowserInstance instead.
const sessionOptions = session.sessionOptions;
session.browserInstancePromise = this.#closeBrowserInstanceIfLaunched(session)
.then(async () => await this.#launchBrowserInstance(connection, sessionOptions))
.catch((e) => {
(0, exports.debugInfo)('Error while creating session', e);
connection.close(500, 'cannot create browser instance');
throw e;
});
}
connection.on('message', async (message) => {
// If type is not text, return error.
if (message.type !== 'utf8') {
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `not supported type (${message.type})`);
return;
}
const plainCommandData = message.utf8Data;
if (debugRecv.enabled) {
try {
debugRecv(JSON.parse(plainCommandData));
}
catch {
debugRecv(plainCommandData);
}
}
// Try to parse the message to handle some of BiDi commands.
let parsedCommandData;
try {
parsedCommandData = JSON.parse(plainCommandData);
}
catch (e) {
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `Cannot parse data as JSON`);
return;
}
// Handle creating new session.
if (parsedCommandData.method === 'session.new') {
if (session !== undefined) {
(0, exports.debugInfo)('WS connection already have an associated session.');
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, 'WS connection already have an associated session.');
return;
}
try {
const sessionOptions = {
chromeOptions: this.#getChromeOptions(parsedCommandData.params?.capabilities, channel, headless),
mapperOptions: this.#getMapperOptions(parsedCommandData.params?.capabilities),
verbose,
};
const browserInstance = await this.#launchBrowserInstance(connection, sessionOptions);
const sessionId = (0, uuid_js_1.uuidv4)();
session = {
sessionId,
browserInstancePromise: Promise.resolve(browserInstance),
sessionOptions,
};
this.#sessions.set(sessionId, session);
}
catch (e) {
(0, exports.debugInfo)('Error while creating session', e);
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, e?.message ?? 'Unknown error');
return;
}
// TODO: extend with capabilities.
this.#sendClientMessage({
id: parsedCommandData.id,
type: 'success',
result: {
sessionId: session.sessionId,
capabilities: {},
},
}, connection);
return;
}
if (session === undefined) {
(0, exports.debugInfo)('Session is not yet initialized.');
this.#respondWithError(connection, plainCommandData, "invalid session id" /* ErrorCode.InvalidSessionId */, 'Session is not yet initialized.');
return;
}
if (session.browserInstancePromise === undefined) {
(0, exports.debugInfo)('Browser instance is not launched.');
this.#respondWithError(connection, plainCommandData, "invalid session id" /* ErrorCode.InvalidSessionId */, 'Browser instance is not launched.');
return;
}
const browserInstance = await session.browserInstancePromise;
// Handle `browser.close` command.
if (parsedCommandData.method === 'browser.close') {
await browserInstance.close();
this.#sendClientMessage({
id: parsedCommandData.id,
type: 'success',
result: {},
}, connection);
return;
}
// Forward all other commands to BiDi Mapper.
await browserInstance.bidiSession().sendCommand(plainCommandData);
});
connection.on('close', async () => {
debugInternal(`${new Date().toString()} Peer ${connection.remoteAddress} disconnected.`);
// TODO: don't close Browser instance to allow re-connecting to the session.
await this.#closeBrowserInstanceIfLaunched(session);
});
});
}
static async #closeBrowserInstanceIfLaunched(session) {
if (session === undefined || session.browserInstancePromise === undefined) {
return;
}
const browserInstance = await session.browserInstancePromise;
session.browserInstancePromise = undefined;
void browserInstance.close();
}
static #getMapperOptions(capabilities) {
const acceptInsecureCerts = capabilities?.alwaysMatch?.acceptInsecureCerts ?? false;
return { acceptInsecureCerts };
}
static #getChromeOptions(capabilities, channel, headless) {
const chromeCapabilities = capabilities?.alwaysMatch?.['goog:chromeOptions'];
return {
chromeArgs: chromeCapabilities?.args ?? [],
channel,
headless,
chromeBinary: chromeCapabilities?.binary ?? undefined,
};
}
static async #launchBrowserInstance(connection, sessionOptions) {
(0, exports.debugInfo)('Scheduling browser launch...');
const browserInstance = await BrowserInstance_js_1.BrowserInstance.run(sessionOptions.chromeOptions, sessionOptions.mapperOptions, sessionOptions.verbose);
// Forward messages from BiDi Mapper to the client unconditionally.
browserInstance.bidiSession().on('message', (message) => {
this.#sendClientMessageString(message, connection);
});
(0, exports.debugInfo)('Browser is launched!');
return browserInstance;
}
static #sendClientMessageString(message, connection) {
if (debugSend.enabled) {
try {
debugSend(JSON.parse(message));
}
catch {
debugSend(message);
}
}
connection.sendUTF(message);
}
static #sendClientMessage(object, connection) {
const json = JSON.stringify(object);
return this.#sendClientMessageString(json, connection);
}
static #respondWithError(connection, plainCommandData, errorCode, errorMessage) {
const errorResponse = this.#getErrorResponse(plainCommandData, errorCode, errorMessage);
void this.#sendClientMessage(errorResponse, connection);
}
static #getErrorResponse(plainCommandData, errorCode, errorMessage) {
// XXX: this is bizarre per spec. We reparse the payload and
// extract the ID, regardless of what kind of value it was.
let commandId;
try {
const commandData = JSON.parse(plainCommandData);
if ('id' in commandData) {
commandId = commandData.id;
}
}
catch { }
return {
type: 'error',
id: commandId,
error: errorCode,
message: errorMessage,
// XXX: optional stacktrace field.
};
}
static #getHttpRequestPayload(request) {
return new Promise((resolve, reject) => {
let data = '';
request.on('data', (chunk) => {
data += chunk;
});
request.on('end', () => {
resolve(data);
});
request.on('error', (error) => {
reject(error);
});
});
}
}
exports.WebSocketServer = WebSocketServer;
//# sourceMappingURL=WebSocketServer.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export {};

View File

@ -0,0 +1,63 @@
"use strict";
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const browsers_1 = require("@puppeteer/browsers");
const argparse_1 = require("argparse");
const WebSocketServer_js_1 = require("./WebSocketServer.js");
function parseArguments() {
const parser = new argparse_1.ArgumentParser({
add_help: true,
exit_on_error: true,
});
parser.add_argument('-c', '--channel', {
help: 'If set, the given installed Chrome Release Channel will be used ' +
'instead of one pointed by Puppeteer version',
choices: Object.values(browsers_1.ChromeReleaseChannel),
default: browsers_1.ChromeReleaseChannel.DEV,
});
parser.add_argument('--headless', {
help: 'Sets if browser should run in headless or headful mode. Default is true.',
default: true,
});
parser.add_argument('-p', '--port', {
help: 'Port that BiDi server should listen to. Default is 8080.',
type: 'int',
default: process.env['PORT'] ?? 8080,
});
parser.add_argument('-v', '--verbose', {
help: 'If present, the Mapper debug log, including CDP commands and events will be logged into the server output.',
action: 'store_true',
default: process.env['VERBOSE'] === 'true' || false,
});
return parser.parse_known_args()[0];
}
(() => {
try {
const args = parseArguments();
const { channel, port } = args;
const headless = args.headless !== 'false';
const verbose = args.verbose === true;
(0, WebSocketServer_js_1.debugInfo)('Launching BiDi server...');
WebSocketServer_js_1.WebSocketServer.run(port, channel, headless, verbose);
(0, WebSocketServer_js_1.debugInfo)('BiDi server launched');
}
catch (e) {
(0, WebSocketServer_js_1.debugInfo)('Error launching BiDi server', e);
}
})();
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bidiServer/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,kDAAyD;AACzD,uCAAwC;AAExC,6DAAgE;AAEhE,SAAS,cAAc;IAMrB,MAAM,MAAM,GAAG,IAAI,yBAAc,CAAC;QAChC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE;QACrC,IAAI,EACF,kEAAkE;YAClE,6CAA6C;QAC/C,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,+BAAoB,CAAC;QAC5C,OAAO,EAAE,+BAAoB,CAAC,GAAG;KAClC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE;QAChC,IAAI,EAAE,0EAA0E;QAChF,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE;QAClC,IAAI,EAAE,0DAA0D;QAChE,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI;KACrC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE;QACrC,IAAI,EAAE,4GAA4G;QAClH,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,KAAK;KACpD,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,CAAC,GAAG,EAAE;IACJ,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAC9B,MAAM,EAAC,OAAO,EAAE,IAAI,EAAC,GAAG,IAAI,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;QAEtC,IAAA,8BAAS,EAAC,0BAA0B,CAAC,CAAC;QAEtC,oCAAe,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,IAAA,8BAAS,EAAC,sBAAsB,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAA,8BAAS,EAAC,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC,EAAE,CAAC"}

View File

@ -0,0 +1,17 @@
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export declare function getMapperTabSource(): Promise<string>;

View File

@ -0,0 +1,29 @@
"use strict";
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMapperTabSource = void 0;
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = __importDefault(require("path"));
async function getMapperTabSource() {
return await promises_1.default.readFile(path_1.default.join(__dirname, '../../iife/mapperTab.js'), 'utf8');
}
exports.getMapperTabSource = getMapperTabSource;
//# sourceMappingURL=reader.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/bidiServer/reader.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;AAEH,2DAA6B;AAC7B,gDAAwB;AAEjB,KAAK,UAAU,kBAAkB;IACtC,OAAO,MAAM,kBAAE,CAAC,QAAQ,CACtB,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,yBAAyB,CAAC,EAC/C,MAAM,CACP,CAAC;AACJ,CAAC;AALD,gDAKC"}