chore: move server-side code to src/server (#411)
This commit is contained in:
parent
e0693654b7
commit
6318b1de75
1
index.d.ts
vendored
1
index.d.ts
vendored
|
|
@ -18,3 +18,4 @@ export * from './lib/api';
|
|||
export function playwright(browser: 'chromium'): import('./lib/api').ChromiumPlaywright;
|
||||
export function playwright(browser: 'firefox'): import('./lib/api').FirefoxPlaywright;
|
||||
export function playwright(browser: 'webkit'): import('./lib/api').WebKitPlaywright;
|
||||
export function connect(browser: 'chromium'): import('./lib/api').ChromiumBrowser.connect;
|
||||
|
|
|
|||
6
index.js
6
index.js
|
|
@ -33,3 +33,9 @@ module.exports.playwright = browser => {
|
|||
return new api.WebKitPlaywright(__dirname, packageJson.playwright.webkit_revision);
|
||||
throw new Error(`Unsupported browser "${browser}"`);
|
||||
};
|
||||
|
||||
module.exports.connect = browser => {
|
||||
if (browser === 'chromium')
|
||||
return api.ChromiumBrowser.connect;
|
||||
throw new Error(`Unsupported browser "${browser}"`);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
export { Accessibility } from './accessibility';
|
||||
export { Browser, BrowserServer } from './browser';
|
||||
export { BrowserContext } from './browserContext';
|
||||
export { BrowserFetcher } from './browserFetcher';
|
||||
export { ConsoleMessage } from './console';
|
||||
export { Dialog } from './dialog';
|
||||
export { ElementHandle } from './dom';
|
||||
|
|
@ -28,6 +27,9 @@ export { JSHandle } from './javascript';
|
|||
export { Request, Response } from './network';
|
||||
export { Coverage, FileChooser, Page, Worker } from './page';
|
||||
|
||||
export { BrowserFetcher } from './server/browserFetcher';
|
||||
export { CRPlaywright as ChromiumPlaywright, CRBrowserServer as ChromiumBrowserServer } from './server/crPlaywright';
|
||||
|
||||
export * from './chromium/crApi';
|
||||
export * from './firefox/ffApi';
|
||||
export * from './webkit/wkApi';
|
||||
|
|
|
|||
|
|
@ -16,5 +16,4 @@
|
|||
|
||||
export { CRBrowser as ChromiumBrowser } from './crBrowser';
|
||||
export { CRSession as ChromiumSession } from './crConnection';
|
||||
export { CRPlaywright as ChromiumPlaywright } from './crPlaywright';
|
||||
export { CRTarget as ChromiumTarget } from './crTarget';
|
||||
|
|
|
|||
|
|
@ -28,9 +28,16 @@ import * as browser from '../browser';
|
|||
import * as network from '../network';
|
||||
import * as types from '../types';
|
||||
import * as platform from '../platform';
|
||||
import { ConnectionTransport } from '../transport';
|
||||
import { ConnectionTransport, SlowMoTransport } from '../transport';
|
||||
import { readProtocolStream } from './crProtocolHelper';
|
||||
|
||||
export type CRConnectOptions = {
|
||||
slowMo?: number,
|
||||
browserWSEndpoint?: string;
|
||||
browserURL?: string;
|
||||
transport?: ConnectionTransport;
|
||||
};
|
||||
|
||||
export class CRBrowser extends browser.Browser {
|
||||
_connection: CRConnection;
|
||||
_client: CRSession;
|
||||
|
|
@ -42,10 +49,9 @@ export class CRBrowser extends browser.Browser {
|
|||
private _tracingPath = '';
|
||||
private _tracingClient: CRSession | undefined;
|
||||
|
||||
static async create(
|
||||
transport: ConnectionTransport) {
|
||||
static async connect(options: CRConnectOptions): Promise<CRBrowser> {
|
||||
const transport = await createTransport(options);
|
||||
const connection = new CRConnection(transport);
|
||||
|
||||
const { browserContextIds } = await connection.rootSession.send('Target.getBrowserContexts');
|
||||
const browser = new CRBrowser(connection, browserContextIds);
|
||||
await connection.rootSession.send('Target.setDiscoverTargets', { discover: true });
|
||||
|
|
@ -297,3 +303,25 @@ export class CRBrowser extends browser.Browser {
|
|||
return !this._connection._closed;
|
||||
}
|
||||
}
|
||||
|
||||
export async function createTransport(options: CRConnectOptions): Promise<ConnectionTransport> {
|
||||
assert(Number(!!options.browserWSEndpoint) + Number(!!options.browserURL) + Number(!!options.transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to playwright.connect');
|
||||
let transport: ConnectionTransport | undefined;
|
||||
let connectionURL: string = '';
|
||||
if (options.transport) {
|
||||
transport = options.transport;
|
||||
} else if (options.browserWSEndpoint) {
|
||||
connectionURL = options.browserWSEndpoint;
|
||||
transport = await platform.createWebSocketTransport(options.browserWSEndpoint);
|
||||
} else if (options.browserURL) {
|
||||
try {
|
||||
const data = await platform.fetchUrl(new URL('/json/version', options.browserURL).href);
|
||||
connectionURL = JSON.parse(data).webSocketDebuggerUrl;
|
||||
} catch (e) {
|
||||
e.message = `Failed to fetch browser webSocket url from ${options.browserURL}: ` + e.message;
|
||||
throw e;
|
||||
}
|
||||
transport = await platform.createWebSocketTransport(connectionURL);
|
||||
}
|
||||
return SlowMoTransport.wrap(transport, options.slowMo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,15 @@
|
|||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { FFBrowser } from './ffBrowser';
|
||||
import { BrowserFetcher, BrowserFetcherOptions } from '../browserFetcher';
|
||||
import { BrowserFetcher, BrowserFetcherOptions } from '../server/browserFetcher';
|
||||
import * as fs from 'fs';
|
||||
import * as util from 'util';
|
||||
import { assert } from '../helper';
|
||||
import { TimeoutError } from '../errors';
|
||||
import { WebSocketTransport, SlowMoTransport } from '../transport';
|
||||
import { launchProcess, waitForLine } from '../processLauncher';
|
||||
import { SlowMoTransport } from '../transport';
|
||||
import { launchProcess, waitForLine } from '../server/processLauncher';
|
||||
import { BrowserServer } from '../browser';
|
||||
import * as platform from '../platform';
|
||||
|
||||
const mkdtempAsync = util.promisify(fs.mkdtemp);
|
||||
const writeFileAsync = util.promisify(fs.writeFile);
|
||||
|
|
@ -122,7 +123,7 @@ export class FFLauncher {
|
|||
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Firefox!`);
|
||||
const match = await waitForLine(launchedProcess, launchedProcess.stdout, /^Juggler listening on (ws:\/\/.*)$/, timeout, timeoutError);
|
||||
const url = match[1];
|
||||
const transport = await WebSocketTransport.create(url);
|
||||
const transport = await platform.createWebSocketTransport(url);
|
||||
browser = await FFBrowser.create(SlowMoTransport.wrap(transport, slowMo));
|
||||
await browser._waitForTarget(t => t.type() === 'page');
|
||||
return new BrowserServer(browser, launchedProcess, url);
|
||||
|
|
|
|||
|
|
@ -17,12 +17,13 @@
|
|||
|
||||
import * as browsers from '../browser';
|
||||
import { FFBrowser } from './ffBrowser';
|
||||
import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../browserFetcher';
|
||||
import { WebSocketTransport, SlowMoTransport } from '../transport';
|
||||
import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../server/browserFetcher';
|
||||
import { SlowMoTransport } from '../transport';
|
||||
import { DeviceDescriptors } from '../deviceDescriptors';
|
||||
import * as Errors from '../errors';
|
||||
import * as types from '../types';
|
||||
import { FFLauncher, createBrowserFetcher } from './ffLauncher';
|
||||
import * as platform from '../platform';
|
||||
|
||||
export class FFPlaywright {
|
||||
private _projectRoot: string;
|
||||
|
|
@ -52,7 +53,7 @@ export class FFPlaywright {
|
|||
}
|
||||
|
||||
async connect(options: { slowMo?: number, browserWSEndpoint: string }): Promise<FFBrowser> {
|
||||
const transport = await WebSocketTransport.create(options.browserWSEndpoint);
|
||||
const transport = await platform.createWebSocketTransport(options.browserWSEndpoint);
|
||||
return FFBrowser.create(SlowMoTransport.wrap(transport, options.slowMo || 0));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@ import * as nodeBuffer from 'buffer';
|
|||
import * as mime from 'mime';
|
||||
import * as jpeg from 'jpeg-js';
|
||||
import * as png from 'pngjs';
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as NodeWebSocket from 'ws';
|
||||
|
||||
import { assert, helper } from './helper';
|
||||
import * as types from './types';
|
||||
import { ConnectionTransport } from './transport';
|
||||
|
||||
export const isNode = typeof process === 'object' && !!process && typeof process.versions === 'object' && !!process.versions && !!process.versions.node;
|
||||
|
||||
|
|
@ -219,3 +223,79 @@ export function pngToJpeg(buffer: Buffer): Buffer {
|
|||
assert(isNode, 'Converting from png to jpeg is only supported in Node.js');
|
||||
return jpeg.encode(png.PNG.sync.read(buffer)).data;
|
||||
}
|
||||
|
||||
function nodeFetch(url: string): Promise<string> {
|
||||
let resolve: (url: string) => void;
|
||||
let reject: (e: Error) => void;
|
||||
const promise = new Promise<string>((res, rej) => { resolve = res; reject = rej; });
|
||||
|
||||
const endpointURL = new URL(url);
|
||||
const protocol = endpointURL.protocol === 'https:' ? https : http;
|
||||
const request = protocol.request(endpointURL, res => {
|
||||
let data = '';
|
||||
if (res.statusCode !== 200) {
|
||||
// Consume response data to free up memory.
|
||||
res.resume();
|
||||
reject(new Error('HTTP ' + res.statusCode));
|
||||
return;
|
||||
}
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => resolve(data));
|
||||
});
|
||||
|
||||
request.on('error', reject);
|
||||
request.end();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
export function fetchUrl(url: string): Promise<string> {
|
||||
if (isNode)
|
||||
return nodeFetch(url);
|
||||
return fetch(url).then(response => {
|
||||
if (!response.ok)
|
||||
throw new Error('HTTP ' + response.status + ' ' + response.statusText);
|
||||
return response.text();
|
||||
});
|
||||
}
|
||||
|
||||
class WebSocketTransport implements ConnectionTransport {
|
||||
private _ws: WebSocket;
|
||||
|
||||
onmessage?: (message: string) => void;
|
||||
onclose?: () => void;
|
||||
|
||||
constructor(ws: WebSocket) {
|
||||
this._ws = ws;
|
||||
this._ws.addEventListener('message', event => {
|
||||
if (this.onmessage)
|
||||
this.onmessage.call(null, event.data);
|
||||
});
|
||||
this._ws.addEventListener('close', event => {
|
||||
if (this.onclose)
|
||||
this.onclose.call(null);
|
||||
});
|
||||
// Silently ignore all errors - we don't know what to do with them.
|
||||
this._ws.addEventListener('error', () => {});
|
||||
}
|
||||
|
||||
send(message: string) {
|
||||
this._ws.send(message);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
export function createWebSocketTransport(url: string): Promise<ConnectionTransport> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ws = (isNode ? new NodeWebSocket(url, [], {
|
||||
perMessageDeflate: false,
|
||||
maxPayload: 256 * 1024 * 1024, // 256Mb
|
||||
}) : new WebSocket(url)) as WebSocket;
|
||||
ws.addEventListener('open', () => resolve(new WebSocketTransport(ws)));
|
||||
ws.addEventListener('error', reject);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,20 @@ import * as extract from 'extract-zip';
|
|||
import * as fs from 'fs';
|
||||
import * as ProxyAgent from 'https-proxy-agent';
|
||||
import * as path from 'path';
|
||||
import * as platform from './platform';
|
||||
// @ts-ignore
|
||||
import * as platform from '../platform';
|
||||
import { getProxyForUrl } from 'proxy-from-env';
|
||||
import * as removeRecursive from 'rimraf';
|
||||
import * as URL from 'url';
|
||||
import { assert } from './helper';
|
||||
import { assert } from '../helper';
|
||||
|
||||
const readdirAsync = platform.promisify(fs.readdir.bind(fs));
|
||||
const mkdirAsync = platform.promisify(fs.mkdir.bind(fs));
|
||||
const unlinkAsync = platform.promisify(fs.unlink.bind(fs));
|
||||
const chmodAsync = platform.promisify(fs.chmod.bind(fs));
|
||||
|
||||
function existsAsync(filePath) {
|
||||
let fulfill = null;
|
||||
const promise = new Promise(x => fulfill = x);
|
||||
function existsAsync(filePath: string): Promise<boolean> {
|
||||
let fulfill: (exists: boolean) => void;
|
||||
const promise = new Promise<boolean>(x => fulfill = x);
|
||||
fs.access(filePath, err => fulfill(!err));
|
||||
return promise;
|
||||
}
|
||||
|
|
@ -15,25 +15,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as URL from 'url';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
import { BrowserFetcher, BrowserFetcherOptions, BrowserFetcherRevisionInfo, OnProgressCallback } from '../browserFetcher';
|
||||
import { BrowserFetcher, BrowserFetcherOptions, BrowserFetcherRevisionInfo, OnProgressCallback } from '../server/browserFetcher';
|
||||
import { DeviceDescriptors } from '../deviceDescriptors';
|
||||
import * as Errors from '../errors';
|
||||
import * as types from '../types';
|
||||
import { assert } from '../helper';
|
||||
import { ConnectionTransport, WebSocketTransport, SlowMoTransport, PipeTransport } from '../transport';
|
||||
import { CRBrowser } from './crBrowser';
|
||||
import { CRBrowser, CRConnectOptions, createTransport } from '../chromium/crBrowser';
|
||||
import * as platform from '../platform';
|
||||
import { TimeoutError } from '../errors';
|
||||
import { launchProcess, waitForLine } from '../processLauncher';
|
||||
import { launchProcess, waitForLine } from '../server/processLauncher';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { CRConnection } from './crConnection';
|
||||
import { CRConnection } from '../chromium/crConnection';
|
||||
import { PipeTransport } from './pipeTransport';
|
||||
|
||||
export type SlowMoOptions = {
|
||||
slowMo?: number,
|
||||
|
|
@ -58,24 +55,17 @@ export type LaunchOptions = ChromeArgOptions & SlowMoOptions & {
|
|||
pipe?: boolean,
|
||||
};
|
||||
|
||||
export type ConnectOptions = SlowMoOptions & {
|
||||
browserWSEndpoint?: string;
|
||||
browserURL?: string;
|
||||
transport?: ConnectionTransport;
|
||||
};
|
||||
|
||||
export class CRBrowserServer {
|
||||
private _process: ChildProcess;
|
||||
private _connectOptions: ConnectOptions;
|
||||
private _connectOptions: CRConnectOptions;
|
||||
|
||||
constructor(process: ChildProcess, connectOptions: ConnectOptions) {
|
||||
constructor(process: ChildProcess, connectOptions: CRConnectOptions) {
|
||||
this._process = process;
|
||||
this._connectOptions = connectOptions;
|
||||
}
|
||||
|
||||
async connect(): Promise<CRBrowser> {
|
||||
const transport = await createTransport(this._connectOptions);
|
||||
return CRBrowser.create(transport);
|
||||
return CRBrowser.connect(this._connectOptions);
|
||||
}
|
||||
|
||||
process(): ChildProcess {
|
||||
|
|
@ -86,7 +76,7 @@ export class CRBrowserServer {
|
|||
return this._connectOptions.browserWSEndpoint || null;
|
||||
}
|
||||
|
||||
connectOptions(): ConnectOptions {
|
||||
connectOptions(): CRConnectOptions {
|
||||
return this._connectOptions;
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +169,7 @@ export class CRPlaywright {
|
|||
|
||||
let server: CRBrowserServer | undefined;
|
||||
try {
|
||||
let connectOptions: ConnectOptions | undefined;
|
||||
let connectOptions: CRConnectOptions | undefined;
|
||||
let browserWSEndpoint: string = '';
|
||||
if (!usePipe) {
|
||||
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Chrome! The only Chrome revision guaranteed to work is r${this._revision}`);
|
||||
|
|
@ -199,9 +189,8 @@ export class CRPlaywright {
|
|||
}
|
||||
}
|
||||
|
||||
async connect(options: ConnectOptions): Promise<CRBrowser> {
|
||||
const transport = await createTransport(options);
|
||||
return CRBrowser.create(transport);
|
||||
async connect(options: CRConnectOptions): Promise<CRBrowser> {
|
||||
return CRBrowser.connect(options);
|
||||
}
|
||||
|
||||
executablePath(): string {
|
||||
|
|
@ -328,49 +317,3 @@ const DEFAULT_ARGS = [
|
|||
'--password-store=basic',
|
||||
'--use-mock-keychain',
|
||||
];
|
||||
|
||||
function getWSEndpoint(browserURL: string): Promise<string> {
|
||||
let resolve: (url: string) => void;
|
||||
let reject: (e: Error) => void;
|
||||
const promise = new Promise<string>((res, rej) => { resolve = res; reject = rej; });
|
||||
|
||||
const endpointURL = URL.resolve(browserURL, '/json/version');
|
||||
const protocol = endpointURL.startsWith('https') ? https : http;
|
||||
const requestOptions = Object.assign(URL.parse(endpointURL), { method: 'GET' });
|
||||
const request = protocol.request(requestOptions, res => {
|
||||
let data = '';
|
||||
if (res.statusCode !== 200) {
|
||||
// Consume response data to free up memory.
|
||||
res.resume();
|
||||
reject(new Error('HTTP ' + res.statusCode));
|
||||
return;
|
||||
}
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => resolve(JSON.parse(data).webSocketDebuggerUrl));
|
||||
});
|
||||
|
||||
request.on('error', reject);
|
||||
request.end();
|
||||
|
||||
return promise.catch(e => {
|
||||
e.message = `Failed to fetch browser webSocket url from ${endpointURL}: ` + e.message;
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
async function createTransport(options: ConnectOptions): Promise<ConnectionTransport> {
|
||||
assert(Number(!!options.browserWSEndpoint) + Number(!!options.browserURL) + Number(!!options.transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to playwright.connect');
|
||||
let transport: ConnectionTransport | undefined;
|
||||
let connectionURL: string = '';
|
||||
if (options.transport) {
|
||||
transport = options.transport;
|
||||
} else if (options.browserWSEndpoint) {
|
||||
connectionURL = options.browserWSEndpoint;
|
||||
transport = await WebSocketTransport.create(options.browserWSEndpoint);
|
||||
} else if (options.browserURL) {
|
||||
connectionURL = await getWSEndpoint(options.browserURL);
|
||||
transport = await WebSocketTransport.create(connectionURL);
|
||||
}
|
||||
return SlowMoTransport.wrap(transport, options.slowMo);
|
||||
}
|
||||
73
src/server/pipeTransport.ts
Normal file
73
src/server/pipeTransport.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
* Modifications 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 { debugError, helper, RegisteredListener } from '../helper';
|
||||
import { ConnectionTransport } from '../transport';
|
||||
|
||||
export class PipeTransport implements ConnectionTransport {
|
||||
private _pipeWrite: NodeJS.WritableStream;
|
||||
private _pendingMessage = '';
|
||||
private _eventListeners: RegisteredListener[];
|
||||
onmessage?: (message: string) => void;
|
||||
onclose?: () => void;
|
||||
|
||||
constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream) {
|
||||
this._pipeWrite = pipeWrite;
|
||||
this._eventListeners = [
|
||||
helper.addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)),
|
||||
helper.addEventListener(pipeRead, 'close', () => {
|
||||
if (this.onclose)
|
||||
this.onclose.call(null);
|
||||
}),
|
||||
helper.addEventListener(pipeRead, 'error', debugError),
|
||||
helper.addEventListener(pipeWrite, 'error', debugError),
|
||||
];
|
||||
this.onmessage = null;
|
||||
this.onclose = null;
|
||||
}
|
||||
|
||||
send(message: string) {
|
||||
this._pipeWrite.write(message);
|
||||
this._pipeWrite.write('\0');
|
||||
}
|
||||
|
||||
_dispatch(buffer: Buffer) {
|
||||
let end = buffer.indexOf('\0');
|
||||
if (end === -1) {
|
||||
this._pendingMessage += buffer.toString();
|
||||
return;
|
||||
}
|
||||
const message = this._pendingMessage + buffer.toString(undefined, 0, end);
|
||||
if (this.onmessage)
|
||||
this.onmessage.call(null, message);
|
||||
|
||||
let start = end + 1;
|
||||
end = buffer.indexOf('\0', start);
|
||||
while (end !== -1) {
|
||||
if (this.onmessage)
|
||||
this.onmessage.call(null, buffer.toString(undefined, start, end));
|
||||
start = end + 1;
|
||||
end = buffer.indexOf('\0', start);
|
||||
}
|
||||
this._pendingMessage = buffer.toString(undefined, start);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._pipeWrite = null;
|
||||
helper.removeEventListeners(this._eventListeners);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,10 +18,10 @@
|
|||
import * as childProcess from 'child_process';
|
||||
import * as stream from 'stream';
|
||||
import * as removeFolder from 'rimraf';
|
||||
import { helper } from './helper';
|
||||
import { helper } from '../helper';
|
||||
import * as readline from 'readline';
|
||||
import { TimeoutError } from './errors';
|
||||
import * as platform from './platform';
|
||||
import { TimeoutError } from '../errors';
|
||||
import * as platform from '../platform';
|
||||
|
||||
const removeFolderAsync = platform.promisify(removeFolder);
|
||||
|
||||
|
|
@ -15,9 +15,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as WebSocket from 'ws';
|
||||
import { debugError, helper, RegisteredListener } from './helper';
|
||||
|
||||
export interface ConnectionTransport {
|
||||
send(s: string): void;
|
||||
close(): void;
|
||||
|
|
@ -25,100 +22,6 @@ export interface ConnectionTransport {
|
|||
onclose?: () => void,
|
||||
}
|
||||
|
||||
export class WebSocketTransport implements ConnectionTransport {
|
||||
private _ws: WebSocket;
|
||||
|
||||
onmessage?: (message: string) => void;
|
||||
onclose?: () => void;
|
||||
|
||||
static create(url: string): Promise<WebSocketTransport> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ws = new WebSocket(url, [], {
|
||||
perMessageDeflate: false,
|
||||
maxPayload: 256 * 1024 * 1024, // 256Mb
|
||||
});
|
||||
ws.addEventListener('open', () => resolve(new WebSocketTransport(ws, url)));
|
||||
ws.addEventListener('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
constructor(ws: WebSocket, url: string) {
|
||||
this._ws = ws;
|
||||
this._ws.addEventListener('message', event => {
|
||||
if (this.onmessage)
|
||||
this.onmessage.call(null, event.data);
|
||||
});
|
||||
this._ws.addEventListener('close', event => {
|
||||
if (this.onclose)
|
||||
this.onclose.call(null);
|
||||
});
|
||||
// Silently ignore all errors - we don't know what to do with them.
|
||||
this._ws.addEventListener('error', () => {});
|
||||
}
|
||||
|
||||
send(message: string) {
|
||||
this._ws.send(message);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
export class PipeTransport implements ConnectionTransport {
|
||||
private _pipeWrite: NodeJS.WritableStream;
|
||||
private _pendingMessage = '';
|
||||
private _eventListeners: RegisteredListener[];
|
||||
onmessage?: (message: string) => void;
|
||||
onclose?: () => void;
|
||||
|
||||
constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream) {
|
||||
this._pipeWrite = pipeWrite;
|
||||
this._eventListeners = [
|
||||
helper.addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)),
|
||||
helper.addEventListener(pipeRead, 'close', () => {
|
||||
if (this.onclose)
|
||||
this.onclose.call(null);
|
||||
}),
|
||||
helper.addEventListener(pipeRead, 'error', debugError),
|
||||
helper.addEventListener(pipeWrite, 'error', debugError),
|
||||
];
|
||||
this.onmessage = null;
|
||||
this.onclose = null;
|
||||
}
|
||||
|
||||
send(message: string) {
|
||||
this._pipeWrite.write(message);
|
||||
this._pipeWrite.write('\0');
|
||||
}
|
||||
|
||||
_dispatch(buffer: Buffer) {
|
||||
let end = buffer.indexOf('\0');
|
||||
if (end === -1) {
|
||||
this._pendingMessage += buffer.toString();
|
||||
return;
|
||||
}
|
||||
const message = this._pendingMessage + buffer.toString(undefined, 0, end);
|
||||
if (this.onmessage)
|
||||
this.onmessage.call(null, message);
|
||||
|
||||
let start = end + 1;
|
||||
end = buffer.indexOf('\0', start);
|
||||
while (end !== -1) {
|
||||
if (this.onmessage)
|
||||
this.onmessage.call(null, buffer.toString(undefined, start, end));
|
||||
start = end + 1;
|
||||
end = buffer.indexOf('\0', start);
|
||||
}
|
||||
this._pendingMessage = buffer.toString(undefined, start);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._pipeWrite = null;
|
||||
helper.removeEventListeners(this._eventListeners);
|
||||
}
|
||||
}
|
||||
|
||||
export class SlowMoTransport {
|
||||
private readonly _delay: number;
|
||||
private readonly _delegate: ConnectionTransport;
|
||||
|
|
|
|||
|
|
@ -17,14 +17,15 @@
|
|||
|
||||
import { assert } from '../helper';
|
||||
import { WKBrowser } from './wkBrowser';
|
||||
import { BrowserFetcher, BrowserFetcherOptions } from '../browserFetcher';
|
||||
import { PipeTransport, SlowMoTransport } from '../transport';
|
||||
import { BrowserFetcher, BrowserFetcherOptions } from '../server/browserFetcher';
|
||||
import { SlowMoTransport } from '../transport';
|
||||
import { execSync } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
import * as os from 'os';
|
||||
import { launchProcess } from '../processLauncher';
|
||||
import { launchProcess } from '../server/processLauncher';
|
||||
import { BrowserServer } from '../browser';
|
||||
import { PipeTransport } from '../server/pipeTransport';
|
||||
|
||||
const DEFAULT_ARGS = [
|
||||
];
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
import * as browsers from '../browser';
|
||||
import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../browserFetcher';
|
||||
import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../server/browserFetcher';
|
||||
import { DeviceDescriptors } from '../deviceDescriptors';
|
||||
import * as Errors from '../errors';
|
||||
import * as types from '../types';
|
||||
|
|
|
|||
|
|
@ -98,11 +98,12 @@ function checkSources(sources) {
|
|||
excludeClasses.add(className);
|
||||
}
|
||||
}
|
||||
if (!node.getSourceFile().fileName.endsWith('platform.ts')) {
|
||||
const fileName = node.getSourceFile().fileName;
|
||||
if (!fileName.endsWith('platform.ts') && !fileName.includes('src/server/')) {
|
||||
// Only relative imports.
|
||||
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
||||
const module = node.moduleSpecifier.text;
|
||||
if (!module.startsWith('.')) {
|
||||
if (!module.startsWith('.') || path.resolve(path.dirname(fileName), module).includes('src/server')) {
|
||||
const lac = ts.getLineAndCharacterOfPosition(node.getSourceFile(), node.moduleSpecifier.pos);
|
||||
errors.push(`Disallowed import "${module}" at ${node.getSourceFile().fileName}:${lac.line + 1}`);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue