refactor: move bidi CDPSession (#11833)

This commit is contained in:
jrandolf 2024-02-05 13:25:15 +01:00 committed by GitHub
parent 8d7d9f1f05
commit a69984e5db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 106 additions and 94 deletions

View File

@ -6,96 +6,14 @@
import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js';
import {CDPSession} from '../api/CDPSession.js';
import type {Connection as CdpConnection} from '../cdp/Connection.js';
import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js';
import type {CDPSession} from '../api/CDPSession.js';
import type {EventType} from '../common/EventEmitter.js';
import {debugError} from '../common/util.js';
import {Deferred} from '../util/Deferred.js';
import {BidiCdpSession} from './CDPSession.js';
import type {BidiConnection} from './Connection.js';
import {BidiRealm} from './Realm.js';
/**
* @internal
*/
export const cdpSessions = new Map<string, CdpSessionWrapper>();
/**
* @internal
*/
export class CdpSessionWrapper extends CDPSession {
#context: BrowsingContext;
#sessionId = Deferred.create<string>();
#detached = false;
constructor(context: BrowsingContext, sessionId?: string) {
super();
this.#context = context;
if (!this.#context.supportsCdp()) {
return;
}
if (sessionId) {
this.#sessionId.resolve(sessionId);
cdpSessions.set(sessionId, this);
} else {
context.connection
.send('cdp.getSession', {
context: context.id,
})
.then(session => {
this.#sessionId.resolve(session.result.session!);
cdpSessions.set(session.result.session!, this);
})
.catch(err => {
this.#sessionId.reject(err);
});
}
}
override connection(): CdpConnection | undefined {
return undefined;
}
override async send<T extends keyof ProtocolMapping.Commands>(
method: T,
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
): Promise<ProtocolMapping.Commands[T]['returnType']> {
if (!this.#context.supportsCdp()) {
throw new UnsupportedOperation(
'CDP support is required for this feature. The current browser does not support CDP.'
);
}
if (this.#detached) {
throw new TargetCloseError(
`Protocol error (${method}): Session closed. Most likely the page has been closed.`
);
}
const session = await this.#sessionId.valueOrThrow();
const {result} = await this.#context.connection.send('cdp.sendCommand', {
method: method,
params: paramArgs[0],
session,
});
return result.result;
}
override async detach(): Promise<void> {
cdpSessions.delete(this.id());
if (!this.#detached && this.#context.supportsCdp()) {
await this.#context.cdpSession.send('Target.detachFromTarget', {
sessionId: this.id(),
});
}
this.#detached = true;
}
override id(): string {
const val = this.#sessionId.value();
return val instanceof Error || val === undefined ? '' : val;
}
}
/**
* Internal events that the BrowsingContext class emits.
*
@ -142,7 +60,7 @@ export class BrowsingContext extends BidiRealm {
this.#url = info.url;
this.#parent = info.parent;
this.#browserName = browserName;
this.#cdpSession = new CdpSessionWrapper(this, undefined);
this.#cdpSession = new BidiCdpSession(this, undefined);
this.on('browsingContext.domContentLoaded', this.#updateUrl.bind(this));
this.on('browsingContext.fragmentNavigated', this.#updateUrl.bind(this));

View File

@ -0,0 +1,95 @@
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js';
import {CDPSession} from '../api/CDPSession.js';
import type {Connection as CdpConnection} from '../cdp/Connection.js';
import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js';
import {Deferred} from '../util/Deferred.js';
import type {BrowsingContext} from './BrowsingContext.js';
/**
* @internal
*/
export const cdpSessions = new Map<string, BidiCdpSession>();
/**
* @internal
*/
export class BidiCdpSession extends CDPSession {
#context: BrowsingContext;
#sessionId = Deferred.create<string>();
#detached = false;
constructor(context: BrowsingContext, sessionId?: string) {
super();
this.#context = context;
if (!this.#context.supportsCdp()) {
return;
}
if (sessionId) {
this.#sessionId.resolve(sessionId);
cdpSessions.set(sessionId, this);
} else {
context.connection
.send('cdp.getSession', {
context: context.id,
})
.then(session => {
this.#sessionId.resolve(session.result.session!);
cdpSessions.set(session.result.session!, this);
})
.catch(err => {
this.#sessionId.reject(err);
});
}
}
override connection(): CdpConnection | undefined {
return undefined;
}
override async send<T extends keyof ProtocolMapping.Commands>(
method: T,
params?: ProtocolMapping.Commands[T]['paramsType'][0]
): Promise<ProtocolMapping.Commands[T]['returnType']> {
if (!this.#context.supportsCdp()) {
throw new UnsupportedOperation(
'CDP support is required for this feature. The current browser does not support CDP.'
);
}
if (this.#detached) {
throw new TargetCloseError(
`Protocol error (${method}): Session closed. Most likely the page has been closed.`
);
}
const session = await this.#sessionId.valueOrThrow();
const {result} = await this.#context.connection.send('cdp.sendCommand', {
method: method,
params: params,
session,
});
return result.result;
}
override async detach(): Promise<void> {
cdpSessions.delete(this.id());
if (!this.#detached && this.#context.supportsCdp()) {
await this.#context.cdpSession.send('Target.detachFromTarget', {
sessionId: this.id(),
});
}
this.#detached = true;
}
override id(): string {
const val = this.#sessionId.value();
return val instanceof Error || val === undefined ? '' : val;
}
}

View File

@ -14,7 +14,8 @@ import {EventEmitter} from '../common/EventEmitter.js';
import {debugError} from '../common/util.js';
import {assert} from '../util/assert.js';
import {cdpSessions, type BrowsingContext} from './BrowsingContext.js';
import type {BrowsingContext} from './BrowsingContext.js';
import {cdpSessions} from './CDPSession.js';
import type {
BidiEvents,
Commands as BidiCommands,

View File

@ -58,11 +58,8 @@ import {isErrorLike} from '../util/ErrorLike.js';
import type {BidiBrowser} from './Browser.js';
import type {BidiBrowserContext} from './BrowserContext.js';
import {
BrowsingContextEvent,
CdpSessionWrapper,
type BrowsingContext,
} from './BrowsingContext.js';
import {BrowsingContextEvent, type BrowsingContext} from './BrowsingContext.js';
import {BidiCdpSession} from './CDPSession.js';
import type {BidiConnection} from './Connection.js';
import {BidiDeserializer} from './Deserializer.js';
import {BidiDialog} from './Dialog.js';
@ -714,7 +711,7 @@ export class BidiPage extends Page {
targetId: this.mainFrame()._id,
flatten: true,
});
return new CdpSessionWrapper(this.mainFrame().context(), sessionId);
return new BidiCdpSession(this.mainFrame().context(), sessionId);
}
override async bringToFront(): Promise<void> {

View File

@ -11,7 +11,8 @@ import {UnsupportedOperation} from '../common/Errors.js';
import type {BidiBrowser} from './Browser.js';
import type {BidiBrowserContext} from './BrowserContext.js';
import {type BrowsingContext, CdpSessionWrapper} from './BrowsingContext.js';
import type {BrowsingContext} from './BrowsingContext.js';
import {BidiCdpSession} from './CDPSession.js';
import {BidiPage} from './Page.js';
/**
@ -117,7 +118,7 @@ export class BiDiBrowsingContextTarget extends BidiTarget {
flatten: true,
}
);
return new CdpSessionWrapper(this._browsingContext, sessionId);
return new BidiCdpSession(this._browsingContext, sessionId);
}
override type(): TargetType {