chore(rpc): move classes around, fix tests, respect dispatcher scopes (#2784)
This commit is contained in:
parent
87516cb3a3
commit
95538e73e7
|
|
@ -55,7 +55,6 @@ export interface BrowserChannel extends Channel {
|
||||||
|
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
newContext(params: { options?: types.BrowserContextOptions }): Promise<BrowserContextChannel>;
|
newContext(params: { options?: types.BrowserContextOptions }): Promise<BrowserContextChannel>;
|
||||||
newPage(params: { options?: types.BrowserContextOptions }): Promise<PageChannel>;
|
|
||||||
}
|
}
|
||||||
export type BrowserInitializer = {};
|
export type BrowserInitializer = {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import * as childProcess from 'child_process';
|
import * as childProcess from 'child_process';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { Connection } from './connection';
|
import { Connection } from './client/connection';
|
||||||
import { Transport } from './transport';
|
import { Transport } from './transport';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
@ -24,7 +24,7 @@ import { Transport } from './transport';
|
||||||
const transport = new Transport(spawnedProcess.stdin, spawnedProcess.stdout);
|
const transport = new Transport(spawnedProcess.stdin, spawnedProcess.stdout);
|
||||||
const connection = new Connection();
|
const connection = new Connection();
|
||||||
connection.onmessage = message => transport.send(message);
|
connection.onmessage = message => transport.send(message);
|
||||||
transport.onmessage = message => connection.send(message);
|
transport.onmessage = message => connection.dispatch(message);
|
||||||
|
|
||||||
const chromium = await connection.waitForObjectWithKnownName('chromium');
|
const chromium = await connection.waitForObjectWithKnownName('chromium');
|
||||||
const browser = await chromium.launch({ headless: false });
|
const browser = await chromium.launch({ headless: false });
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,13 @@ import { BrowserChannel, BrowserInitializer } from '../channels';
|
||||||
import { BrowserContext } from './browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
import { Page } from './page';
|
import { Page } from './page';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
|
|
||||||
export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||||
readonly _contexts = new Set<BrowserContext>();
|
readonly _contexts = new Set<BrowserContext>();
|
||||||
private _isConnected = true;
|
private _isConnected = true;
|
||||||
|
private _isClosedOrClosing = false;
|
||||||
|
|
||||||
|
|
||||||
static from(browser: BrowserChannel): Browser {
|
static from(browser: BrowserChannel): Browser {
|
||||||
|
|
@ -40,6 +41,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||||
channel.on('close', () => {
|
channel.on('close', () => {
|
||||||
this._isConnected = false;
|
this._isConnected = false;
|
||||||
this.emit(Events.Browser.Disconnected);
|
this.emit(Events.Browser.Disconnected);
|
||||||
|
this._isClosedOrClosing = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +71,9 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(): Promise<void> {
|
async close(): Promise<void> {
|
||||||
|
if (this._isClosedOrClosing)
|
||||||
|
return;
|
||||||
|
this._isClosedOrClosing = true;
|
||||||
await this._channel.close();
|
await this._channel.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { BrowserContextChannel, BrowserContextInitializer } from '../channels';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { helper } from '../../helper';
|
import { helper } from '../../helper';
|
||||||
import { Browser } from './browser';
|
import { Browser } from './browser';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
import { TimeoutSettings } from '../../timeoutSettings';
|
import { TimeoutSettings } from '../../timeoutSettings';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { ChildProcess } from 'child_process';
|
import { ChildProcess } from 'child_process';
|
||||||
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
|
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { BrowserTypeChannel, BrowserTypeInitializer } from '../channels';
|
||||||
import { Browser } from './browser';
|
import { Browser } from './browser';
|
||||||
import { BrowserContext } from './browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { BrowserServer } from './browserServer';
|
import { BrowserServer } from './browserServer';
|
||||||
|
|
||||||
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
|
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { Channel } from '../channels';
|
import { Channel } from '../channels';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
|
|
||||||
export abstract class ChannelOwner<T extends Channel, Initializer> extends EventEmitter {
|
export abstract class ChannelOwner<T extends Channel, Initializer> extends EventEmitter {
|
||||||
readonly _channel: T;
|
readonly _channel: T;
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EventEmitter } from 'ws';
|
import { EventEmitter } from 'ws';
|
||||||
import { Browser } from './client/browser';
|
import { Browser } from './browser';
|
||||||
import { BrowserContext } from './client/browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
import { BrowserType } from './client/browserType';
|
import { BrowserType } from './browserType';
|
||||||
import { ChannelOwner } from './client/channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { ElementHandle } from './client/elementHandle';
|
import { ElementHandle } from './elementHandle';
|
||||||
import { Frame } from './client/frame';
|
import { Frame } from './frame';
|
||||||
import { JSHandle } from './client/jsHandle';
|
import { JSHandle } from './jsHandle';
|
||||||
import { Request, Response, Route } from './client/network';
|
import { Request, Response, Route } from './network';
|
||||||
import { Page, BindingCall } from './client/page';
|
import { Page, BindingCall } from './page';
|
||||||
import { Worker } from './client/worker';
|
import { Worker } from './worker';
|
||||||
import debug = require('debug');
|
import debug = require('debug');
|
||||||
import { Channel } from './channels';
|
import { Channel } from '../channels';
|
||||||
import { ConsoleMessage } from './client/consoleMessage';
|
import { ConsoleMessage } from './consoleMessage';
|
||||||
import { Dialog } from './client/dialog';
|
import { Dialog } from './dialog';
|
||||||
import { Download } from './client/download';
|
import { Download } from './download';
|
||||||
import { parseError } from './serializers';
|
import { parseError } from '../serializers';
|
||||||
import { BrowserServer } from './client/browserServer';
|
import { BrowserServer } from './browserServer';
|
||||||
|
|
||||||
export class Connection {
|
export class Connection {
|
||||||
private _channels = new Map<string, Channel>();
|
private _channels = new Map<string, Channel>();
|
||||||
|
|
@ -122,7 +122,7 @@ export class Connection {
|
||||||
return new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject }));
|
return new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject }));
|
||||||
}
|
}
|
||||||
|
|
||||||
send(message: string) {
|
dispatch(message: string) {
|
||||||
const parsedMessage = JSON.parse(message);
|
const parsedMessage = JSON.parse(message);
|
||||||
const { id, guid, method, params, result, error } = parsedMessage;
|
const { id, guid, method, params, result, error } = parsedMessage;
|
||||||
if (id) {
|
if (id) {
|
||||||
|
|
@ -19,7 +19,7 @@ import { ConsoleMessageLocation } from '../../types';
|
||||||
import { JSHandle } from './jsHandle';
|
import { JSHandle } from './jsHandle';
|
||||||
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
|
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
|
|
||||||
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel, ConsoleMessageInitializer> {
|
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel, ConsoleMessageInitializer> {
|
||||||
static from(request: ConsoleMessageChannel): ConsoleMessage {
|
static from(request: ConsoleMessageChannel): ConsoleMessage {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DialogChannel, DialogInitializer } from '../channels';
|
import { DialogChannel, DialogInitializer } from '../channels';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
|
|
||||||
export class Dialog extends ChannelOwner<DialogChannel, DialogInitializer> {
|
export class Dialog extends ChannelOwner<DialogChannel, DialogInitializer> {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { DownloadChannel, DownloadInitializer } from '../channels';
|
import { DownloadChannel, DownloadInitializer } from '../channels';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import * as types from '../../types';
|
||||||
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
|
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
|
||||||
import { Frame } from './frame';
|
import { Frame } from './frame';
|
||||||
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
|
|
||||||
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||||
readonly _elementChannel: ElementHandleChannel;
|
readonly _elementChannel: ElementHandleChannel;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import { JSHandle, Func1, FuncOn, SmartHandle, serializeArgument, parseResult }
|
||||||
import * as network from './network';
|
import * as network from './network';
|
||||||
import { Response } from './network';
|
import { Response } from './network';
|
||||||
import { Page } from './page';
|
import { Page } from './page';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { normalizeFilePayloads } from '../serializers';
|
import { normalizeFilePayloads } from '../serializers';
|
||||||
|
|
||||||
export type GotoOptions = types.NavigateOptions & {
|
export type GotoOptions = types.NavigateOptions & {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
||||||
import { ElementHandle } from './elementHandle';
|
import { ElementHandle } from './elementHandle';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { serializeAsCallArgument, parseEvaluationResultValue } from '../../common/utilityScriptSerializers';
|
import { serializeAsCallArgument, parseEvaluationResultValue } from '../../common/utilityScriptSerializers';
|
||||||
|
|
||||||
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
|
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import * as types from '../../types';
|
||||||
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
|
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Frame } from './frame';
|
import { Frame } from './frame';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { normalizeFulfillParameters } from '../serializers';
|
import { normalizeFulfillParameters } from '../serializers';
|
||||||
|
|
||||||
export type NetworkCookie = {
|
export type NetworkCookie = {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { assert, assertMaxArguments, helper, Listener } from '../../helper';
|
||||||
import { TimeoutSettings } from '../../timeoutSettings';
|
import { TimeoutSettings } from '../../timeoutSettings';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { BindingCallChannel, BindingCallInitializer, Channel, PageChannel, PageInitializer } from '../channels';
|
import { BindingCallChannel, BindingCallInitializer, Channel, PageChannel, PageInitializer } from '../channels';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { parseError, serializeError } from '../serializers';
|
import { parseError, serializeError } from '../serializers';
|
||||||
import { Accessibility } from './accessibility';
|
import { Accessibility } from './accessibility';
|
||||||
import { BrowserContext } from './browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
import { assertMaxArguments } from '../../helper';
|
import { assertMaxArguments } from '../../helper';
|
||||||
import { WorkerChannel, WorkerInitializer } from '../channels';
|
import { WorkerChannel, WorkerInitializer } from '../channels';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from './connection';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Func1, JSHandle, parseResult, serializeArgument, SmartHandle } from './jsHandle';
|
import { Func1, JSHandle, parseResult, serializeArgument, SmartHandle } from './jsHandle';
|
||||||
import { Page } from './page';
|
import { Page } from './page';
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Transport } from './transport';
|
import { Transport } from './transport';
|
||||||
import { DispatcherScope } from './dispatcher';
|
import { DispatcherConnection } from './server/dispatcher';
|
||||||
import { Playwright } from '../server/playwright';
|
import { Playwright } from '../server/playwright';
|
||||||
import { BrowserTypeDispatcher } from './server/browserTypeDispatcher';
|
import { BrowserTypeDispatcher } from './server/browserTypeDispatcher';
|
||||||
|
|
||||||
const dispatcherScope = new DispatcherScope();
|
const dispatcherConnection = new DispatcherConnection();
|
||||||
const transport = new Transport(process.stdout, process.stdin);
|
const transport = new Transport(process.stdout, process.stdin);
|
||||||
transport.onmessage = message => dispatcherScope.send(message);
|
transport.onmessage = message => dispatcherConnection.dispatch(message);
|
||||||
dispatcherScope.onmessage = message => transport.send(message);
|
dispatcherConnection.onmessage = message => transport.send(message);
|
||||||
|
|
||||||
|
const dispatcherScope = dispatcherConnection.createScope();
|
||||||
const playwright = new Playwright(__dirname, require('../../browsers.json')['browsers']);
|
const playwright = new Playwright(__dirname, require('../../browsers.json')['browsers']);
|
||||||
new BrowserTypeDispatcher(dispatcherScope, playwright.chromium!);
|
new BrowserTypeDispatcher(dispatcherScope, playwright.chromium!);
|
||||||
new BrowserTypeDispatcher(dispatcherScope, playwright.firefox!);
|
new BrowserTypeDispatcher(dispatcherScope, playwright.firefox!);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { BrowserContextBase, BrowserContext } from '../../browserContext';
|
import { BrowserContextBase, BrowserContext } from '../../browserContext';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, lookupDispatcher } from '../dispatcher';
|
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, lookupDispatcher } from './dispatcher';
|
||||||
import { PageDispatcher, BindingCallDispatcher } from './pageDispatcher';
|
import { PageDispatcher, BindingCallDispatcher } from './pageDispatcher';
|
||||||
import { PageChannel, BrowserContextChannel, BrowserContextInitializer } from '../channels';
|
import { PageChannel, BrowserContextChannel, BrowserContextInitializer } from '../channels';
|
||||||
import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
|
import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
|
||||||
|
|
@ -34,6 +34,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, Browser
|
||||||
context.on(Events.BrowserContext.Page, page => this._dispatchEvent('page', PageDispatcher.from(this._scope, page)));
|
context.on(Events.BrowserContext.Page, page => this._dispatchEvent('page', PageDispatcher.from(this._scope, page)));
|
||||||
context.on(Events.BrowserContext.Close, () => {
|
context.on(Events.BrowserContext.Close, () => {
|
||||||
this._dispatchEvent('close');
|
this._dispatchEvent('close');
|
||||||
|
scope.dispose();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,25 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BrowserBase, Browser } from '../../browser';
|
import { Browser, BrowserBase } from '../../browser';
|
||||||
import { BrowserContextBase } from '../../browserContext';
|
import { BrowserContextBase } from '../../browserContext';
|
||||||
import * as types from '../../types';
|
|
||||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
|
||||||
import { BrowserChannel, BrowserContextChannel, PageChannel, BrowserInitializer } from '../channels';
|
|
||||||
import { Dispatcher, DispatcherScope, lookupDispatcher } from '../dispatcher';
|
|
||||||
import { PageDispatcher } from './pageDispatcher';
|
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
|
import * as types from '../../types';
|
||||||
|
import { BrowserChannel, BrowserContextChannel, BrowserInitializer } from '../channels';
|
||||||
|
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||||
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
|
|
||||||
export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> implements BrowserChannel {
|
export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> implements BrowserChannel {
|
||||||
constructor(scope: DispatcherScope, browser: BrowserBase) {
|
constructor(scope: DispatcherScope, browser: BrowserBase) {
|
||||||
super(scope, browser, 'browser', {});
|
super(scope, browser, 'browser', {});
|
||||||
browser.on(Events.Browser.Disconnected, () => this._dispatchEvent('close'));
|
browser.on(Events.Browser.Disconnected, () => {
|
||||||
|
this._dispatchEvent('close');
|
||||||
|
scope.dispose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async newContext(params: { options?: types.BrowserContextOptions }): Promise<BrowserContextChannel> {
|
async newContext(params: { options?: types.BrowserContextOptions }): Promise<BrowserContextChannel> {
|
||||||
return new BrowserContextDispatcher(this._scope, await this._object.newContext(params.options) as BrowserContextBase);
|
return new BrowserContextDispatcher(this._scope.createChild(), await this._object.newContext(params.options) as BrowserContextBase);
|
||||||
}
|
|
||||||
|
|
||||||
async newPage(params: { options?: types.BrowserContextOptions }): Promise<PageChannel> {
|
|
||||||
return lookupDispatcher<PageDispatcher>(await this._object.newPage(params.options))!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(): Promise<void> {
|
async close(): Promise<void> {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { BrowserServer } from '../../server/browserServer';
|
import { BrowserServer } from '../../server/browserServer';
|
||||||
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
|
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
|
|
||||||
export class BrowserServerDispatcher extends Dispatcher<BrowserServer, BrowserServerInitializer> implements BrowserServerChannel {
|
export class BrowserServerDispatcher extends Dispatcher<BrowserServer, BrowserServerInitializer> implements BrowserServerChannel {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { BrowserTypeBase, BrowserType } from '../../server/browserType';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { BrowserDispatcher } from './browserDispatcher';
|
import { BrowserDispatcher } from './browserDispatcher';
|
||||||
import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer, BrowserServerChannel } from '../channels';
|
import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer, BrowserServerChannel } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
import { BrowserContextBase } from '../../browserContext';
|
import { BrowserContextBase } from '../../browserContext';
|
||||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||||
import { BrowserServerDispatcher } from './browserServerDispatcher';
|
import { BrowserServerDispatcher } from './browserServerDispatcher';
|
||||||
|
|
@ -34,12 +34,12 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
||||||
|
|
||||||
async launch(params: { options?: types.LaunchOptions }): Promise<BrowserChannel> {
|
async launch(params: { options?: types.LaunchOptions }): Promise<BrowserChannel> {
|
||||||
const browser = await this._object.launch(params.options || undefined);
|
const browser = await this._object.launch(params.options || undefined);
|
||||||
return new BrowserDispatcher(this._scope, browser as BrowserBase);
|
return new BrowserDispatcher(this._scope.createChild(), browser as BrowserBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchPersistentContext(params: { userDataDir: string, options?: types.LaunchOptions & types.BrowserContextOptions }): Promise<BrowserContextChannel> {
|
async launchPersistentContext(params: { userDataDir: string, options?: types.LaunchOptions & types.BrowserContextOptions }): Promise<BrowserContextChannel> {
|
||||||
const browserContext = await this._object.launchPersistentContext(params.userDataDir, params.options);
|
const browserContext = await this._object.launchPersistentContext(params.userDataDir, params.options);
|
||||||
return new BrowserContextDispatcher(this._scope, browserContext as BrowserContextBase);
|
return new BrowserContextDispatcher(this._scope.createChild(), browserContext as BrowserContextBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchServer(params: { options?: types.LaunchServerOptions }): Promise<BrowserServerChannel> {
|
async launchServer(params: { options?: types.LaunchServerOptions }): Promise<BrowserServerChannel> {
|
||||||
|
|
@ -48,6 +48,6 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
||||||
|
|
||||||
async connect(params: { options: types.ConnectOptions }): Promise<BrowserChannel> {
|
async connect(params: { options: types.ConnectOptions }): Promise<BrowserChannel> {
|
||||||
const browser = await this._object.connect(params.options);
|
const browser = await this._object.connect(params.options);
|
||||||
return new BrowserDispatcher(this._scope, browser as BrowserBase);
|
return new BrowserDispatcher(this._scope.createChild(), browser as BrowserBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { ConsoleMessage } from '../../console';
|
import { ConsoleMessage } from '../../console';
|
||||||
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
|
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
import { createHandle } from './elementHandlerDispatcher';
|
import { createHandle } from './elementHandlerDispatcher';
|
||||||
|
|
||||||
export class ConsoleMessageDispatcher extends Dispatcher<ConsoleMessage, ConsoleMessageInitializer> implements ConsoleMessageChannel {
|
export class ConsoleMessageDispatcher extends Dispatcher<ConsoleMessage, ConsoleMessageInitializer> implements ConsoleMessageChannel {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { Dialog } from '../../dialog';
|
import { Dialog } from '../../dialog';
|
||||||
import { DialogChannel, DialogInitializer } from '../channels';
|
import { DialogChannel, DialogInitializer } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
|
|
||||||
export class DialogDispatcher extends Dispatcher<Dialog, DialogInitializer> implements DialogChannel {
|
export class DialogDispatcher extends Dispatcher<Dialog, DialogInitializer> implements DialogChannel {
|
||||||
constructor(scope: DispatcherScope, dialog: Dialog) {
|
constructor(scope: DispatcherScope, dialog: Dialog) {
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { helper, debugAssert } from '../helper';
|
import { helper, debugAssert } from '../../helper';
|
||||||
import { Channel } from './channels';
|
import { Channel } from '../channels';
|
||||||
import { serializeError } from './serializers';
|
import { serializeError } from '../serializers';
|
||||||
|
|
||||||
export const dispatcherSymbol = Symbol('dispatcher');
|
export const dispatcherSymbol = Symbol('dispatcher');
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ export class Dispatcher<Type, Initializer> extends EventEmitter implements Chann
|
||||||
this._guid = guid;
|
this._guid = guid;
|
||||||
this._object = object;
|
this._object = object;
|
||||||
this._scope = scope;
|
this._scope = scope;
|
||||||
scope.dispatchers.set(this._guid, this);
|
scope.bind(this._guid, this);
|
||||||
(object as any)[dispatcherSymbol] = this;
|
(object as any)[dispatcherSymbol] = this;
|
||||||
this._scope.sendMessageToClient(this._guid, '__create__', { type, initializer });
|
this._scope.sendMessageToClient(this._guid, '__create__', { type, initializer });
|
||||||
}
|
}
|
||||||
|
|
@ -58,17 +58,62 @@ export class Dispatcher<Type, Initializer> extends EventEmitter implements Chann
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DispatcherScope {
|
export class DispatcherScope {
|
||||||
readonly dispatchers = new Map<string, Dispatcher<any, any>>();
|
private _connection: DispatcherConnection;
|
||||||
onmessage = (message: string) => {};
|
private _dispatchers = new Map<string, Dispatcher<any, any>>();
|
||||||
|
private _parent: DispatcherScope | undefined;
|
||||||
|
private _childScopes = new Set<DispatcherScope>();
|
||||||
|
|
||||||
|
constructor(connection: DispatcherConnection, parent?: DispatcherScope) {
|
||||||
|
this._connection = connection;
|
||||||
|
this._parent = parent;
|
||||||
|
if (parent)
|
||||||
|
parent._childScopes.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
createChild(): DispatcherScope {
|
||||||
|
return new DispatcherScope(this._connection, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(guid: string, arg: Dispatcher<any, any>) {
|
||||||
|
this._dispatchers.set(guid, arg);
|
||||||
|
this._connection._dispatchers.set(guid, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
for (const child of [...this._childScopes])
|
||||||
|
child.dispose();
|
||||||
|
this._childScopes.clear();
|
||||||
|
for (const guid of this._dispatchers.keys())
|
||||||
|
this._connection._dispatchers.delete(guid);
|
||||||
|
if (this._parent)
|
||||||
|
this._parent._childScopes.delete(this);
|
||||||
|
}
|
||||||
|
|
||||||
async sendMessageToClient(guid: string, method: string, params: any): Promise<any> {
|
async sendMessageToClient(guid: string, method: string, params: any): Promise<any> {
|
||||||
|
this._connection._sendMessageToClient(guid, method, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DispatcherConnection {
|
||||||
|
readonly _dispatchers = new Map<string, Dispatcher<any, any>>();
|
||||||
|
onmessage = (message: string) => {};
|
||||||
|
|
||||||
|
async _sendMessageToClient(guid: string, method: string, params: any): Promise<any> {
|
||||||
this.onmessage(JSON.stringify({ guid, method, params: this._replaceDispatchersWithGuids(params) }));
|
this.onmessage(JSON.stringify({ guid, method, params: this._replaceDispatchersWithGuids(params) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(message: string) {
|
createScope(): DispatcherScope {
|
||||||
|
return new DispatcherScope(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async dispatch(message: string) {
|
||||||
const parsedMessage = JSON.parse(message);
|
const parsedMessage = JSON.parse(message);
|
||||||
const { id, guid, method, params } = parsedMessage;
|
const { id, guid, method, params } = parsedMessage;
|
||||||
const dispatcher = this.dispatchers.get(guid)!;
|
const dispatcher = this._dispatchers.get(guid);
|
||||||
|
if (!dispatcher) {
|
||||||
|
this.onmessage(JSON.stringify({ id, error: serializeError(new Error('Target browser or context has been closed')) }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const result = await (dispatcher as any)[method](this._replaceGuidsWithDispatchers(params));
|
const result = await (dispatcher as any)[method](this._replaceGuidsWithDispatchers(params));
|
||||||
this.onmessage(JSON.stringify({ id, result: this._replaceDispatchersWithGuids(result) }));
|
this.onmessage(JSON.stringify({ id, result: this._replaceDispatchersWithGuids(result) }));
|
||||||
|
|
@ -101,8 +146,8 @@ export class DispatcherScope {
|
||||||
return payload;
|
return payload;
|
||||||
if (Array.isArray(payload))
|
if (Array.isArray(payload))
|
||||||
return payload.map(p => this._replaceGuidsWithDispatchers(p));
|
return payload.map(p => this._replaceGuidsWithDispatchers(p));
|
||||||
if (payload.guid && this.dispatchers.has(payload.guid))
|
if (payload.guid && this._dispatchers.has(payload.guid))
|
||||||
return this.dispatchers.get(payload.guid);
|
return this._dispatchers.get(payload.guid);
|
||||||
// TODO: send base64
|
// TODO: send base64
|
||||||
if (payload instanceof Buffer)
|
if (payload instanceof Buffer)
|
||||||
return payload;
|
return payload;
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { Download } from '../../download';
|
import { Download } from '../../download';
|
||||||
import { DownloadChannel, DownloadInitializer } from '../channels';
|
import { DownloadChannel, DownloadInitializer } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
|
|
||||||
export class DownloadDispatcher extends Dispatcher<Download, DownloadInitializer> implements DownloadChannel {
|
export class DownloadDispatcher extends Dispatcher<Download, DownloadInitializer> implements DownloadChannel {
|
||||||
constructor(scope: DispatcherScope, download: Download) {
|
constructor(scope: DispatcherScope, download: Download) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import { ElementHandle } from '../../dom';
|
||||||
import * as js from '../../javascript';
|
import * as js from '../../javascript';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { ElementHandleChannel, FrameChannel } from '../channels';
|
import { ElementHandleChannel, FrameChannel } from '../channels';
|
||||||
import { DispatcherScope, lookupNullableDispatcher } from '../dispatcher';
|
import { DispatcherScope, lookupNullableDispatcher } from './dispatcher';
|
||||||
import { JSHandleDispatcher, serializeResult, parseArgument } from './jsHandleDispatcher';
|
import { JSHandleDispatcher, serializeResult, parseArgument } from './jsHandleDispatcher';
|
||||||
import { FrameDispatcher } from './frameDispatcher';
|
import { FrameDispatcher } from './frameDispatcher';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import { Frame } from '../../frames';
|
import { Frame } from '../../frames';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { ElementHandleChannel, FrameChannel, FrameInitializer, JSHandleChannel, ResponseChannel } from '../channels';
|
import { ElementHandleChannel, FrameChannel, FrameInitializer, JSHandleChannel, ResponseChannel } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from '../dispatcher';
|
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher';
|
||||||
import { convertSelectOptionValues, ElementHandleDispatcher, createHandle } from './elementHandlerDispatcher';
|
import { convertSelectOptionValues, ElementHandleDispatcher, createHandle } from './elementHandlerDispatcher';
|
||||||
import { parseArgument, serializeResult } from './jsHandleDispatcher';
|
import { parseArgument, serializeResult } from './jsHandleDispatcher';
|
||||||
import { ResponseDispatcher } from './networkDispatchers';
|
import { ResponseDispatcher } from './networkDispatchers';
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import * as js from '../../javascript';
|
import * as js from '../../javascript';
|
||||||
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||||
import { parseEvaluationResultValue, serializeAsCallArgument } from '../../common/utilityScriptSerializers';
|
import { parseEvaluationResultValue, serializeAsCallArgument } from '../../common/utilityScriptSerializers';
|
||||||
import { createHandle } from './elementHandlerDispatcher';
|
import { createHandle } from './elementHandlerDispatcher';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import { Request, Response, Route } from '../../network';
|
import { Request, Response, Route } from '../../network';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary } from '../channels';
|
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from '../dispatcher';
|
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher';
|
||||||
import { FrameDispatcher } from './frameDispatcher';
|
import { FrameDispatcher } from './frameDispatcher';
|
||||||
|
|
||||||
export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> implements RequestChannel {
|
export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> implements RequestChannel {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { Request } from '../../network';
|
||||||
import { Page, Worker } from '../../page';
|
import { Page, Worker } from '../../page';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary } from '../channels';
|
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope, lookupDispatcher, lookupNullableDispatcher, existingDispatcher } from '../dispatcher';
|
import { Dispatcher, DispatcherScope, lookupDispatcher, lookupNullableDispatcher, existingDispatcher } from './dispatcher';
|
||||||
import { parseError, serializeError } from '../serializers';
|
import { parseError, serializeError } from '../serializers';
|
||||||
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
|
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
|
||||||
import { DialogDispatcher } from './dialogDispatcher';
|
import { DialogDispatcher } from './dialogDispatcher';
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const rm = require('rimraf').sync;
|
const rm = require('rimraf').sync;
|
||||||
const {TestServer} = require('../utils/testserver/');
|
const {TestServer} = require('../utils/testserver/');
|
||||||
const { DispatcherScope } = require('../lib/rpc/dispatcher');
|
const { DispatcherConnection } = require('../lib/rpc/server/dispatcher');
|
||||||
const { Connection } = require('../lib/rpc/connection');
|
const { Connection } = require('../lib/rpc/client/connection');
|
||||||
const { BrowserTypeDispatcher } = require('../lib/rpc/server/browserTypeDispatcher');
|
const { BrowserTypeDispatcher } = require('../lib/rpc/server/browserTypeDispatcher');
|
||||||
|
|
||||||
class ServerEnvironment {
|
class ServerEnvironment {
|
||||||
|
|
@ -172,17 +172,17 @@ class BrowserTypeEnvironment {
|
||||||
// Channel substitute
|
// Channel substitute
|
||||||
let overridenBrowserType = this._browserType;
|
let overridenBrowserType = this._browserType;
|
||||||
if (process.env.PWCHANNEL) {
|
if (process.env.PWCHANNEL) {
|
||||||
const dispatcherScope = new DispatcherScope();
|
const dispatcherConnection = new DispatcherConnection();
|
||||||
const connection = new Connection();
|
const connection = new Connection();
|
||||||
dispatcherScope.onmessage = async message => {
|
dispatcherConnection.onmessage = async message => {
|
||||||
setImmediate(() => connection.send(message));
|
setImmediate(() => connection.dispatch(message));
|
||||||
};
|
};
|
||||||
connection.onmessage = async message => {
|
connection.onmessage = async message => {
|
||||||
const result = await dispatcherScope.send(message);
|
const result = await dispatcherConnection.dispatch(message);
|
||||||
await new Promise(f => setImmediate(f));
|
await new Promise(f => setImmediate(f));
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
new BrowserTypeDispatcher(dispatcherScope, this._browserType);
|
new BrowserTypeDispatcher(dispatcherConnection.createScope(), this._browserType);
|
||||||
overridenBrowserType = await connection.waitForObjectWithKnownName(this._browserType.name());
|
overridenBrowserType = await connection.waitForObjectWithKnownName(this._browserType.name());
|
||||||
}
|
}
|
||||||
state.browserType = overridenBrowserType;
|
state.browserType = overridenBrowserType;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue