Skip to content

Commit

Permalink
chore: target wip
Browse files Browse the repository at this point in the history
  • Loading branch information
OrKoN committed Aug 11, 2023
1 parent 6d7ea9e commit 14e54ba
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 15 deletions.
4 changes: 4 additions & 0 deletions packages/puppeteer-core/src/api/Target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export enum TargetType {
BROWSER = 'browser',
WEBVIEW = 'webview',
OTHER = 'other',
/**
* @internal
*/
TAB = 'tab',
}

/**
Expand Down
10 changes: 8 additions & 2 deletions packages/puppeteer-core/src/common/Browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,9 @@ export class CDPBrowser extends BrowserBase {
url: 'about:blank',
browserContextId: contextId || undefined,
});
const target = this.#targetManager.getAvailableTargets().get(targetId);
const target = (await this.waitForTarget(t => {
return (t as CDPTarget)._targetId === targetId;
})) as CDPTarget;
if (!target) {
throw new Error(`Missing target for page (id = ${targetId})`);
}
Expand Down Expand Up @@ -577,7 +579,11 @@ export class CDPBrowserContext extends BrowserContext {
options: {timeout?: number} = {}
): Promise<Target> {
return this.#browser.waitForTarget(target => {
return target.browserContext() === this && predicate(target);
return (
target.browserContext() === this &&
target.type() !== 'tab' &&
predicate(target)
);
}, options);
}

Expand Down
45 changes: 40 additions & 5 deletions packages/puppeteer-core/src/common/ChromeTargetManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
#initializeDeferred = Deferred.create<void>();
#targetsIdsForInit = new Set<string>();

#tabMode = true;
#discoveryFilter = this.#tabMode ? [{}] : [{type: 'tab', exclude: true}, {}];

constructor(
connection: Connection,
targetFactory: TargetFactory,
Expand All @@ -104,7 +107,7 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
this.#connection
.send('Target.setDiscoverTargets', {
discover: true,
filter: [{type: 'tab', exclude: true}, {}],
filter: this.#discoveryFilter,
})
.then(this.#storeExistingTargetsForInit)
.catch(debugError);
Expand Down Expand Up @@ -137,6 +140,15 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
waitForDebuggerOnStart: true,
flatten: true,
autoAttach: true,
filter: this.#tabMode
? [
{
type: 'page',
exclude: true,
},
...this.#discoveryFilter,
]
: this.#discoveryFilter,
});
this.#finishInitializationIfReady();
await this.#initializeDeferred.valueOrThrow();
Expand All @@ -152,7 +164,13 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
}

getAvailableTargets(): Map<string, CDPTarget> {
return this.#attachedTargetsByTargetId;
const result = new Map<string, CDPTarget>();
for (const [id, target] of this.#attachedTargetsByTargetId.entries()) {
if (target.type() !== 'tab' && !target._subtype()) {
result.set(id, target);
}
}
return result;
}

addTargetInterceptor(
Expand Down Expand Up @@ -279,6 +297,16 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
const wasInitialized =
target._initializedDeferred.value() === InitializationStatus.SUCCESS;

if (target._subtype() && !event.targetInfo.subtype) {
const target = this.#attachedTargetsByTargetId.get(
event.targetInfo.targetId
);
const session = target?._session();
if (session) {
session.parentSession()?.emit('sessionswapped', session);
}
}

target._targetInfoChanged(event.targetInfo);

if (wasInitialized && previousURL !== target.url()) {
Expand Down Expand Up @@ -344,7 +372,11 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {

const target = existingTarget
? this.#attachedTargetsByTargetId.get(targetInfo.targetId)!
: this.#targetFactory(targetInfo, session);
: this.#targetFactory(
targetInfo,
session,
parentSession instanceof CDPSession ? parentSession : undefined
);

if (this.#targetFilterCallback && !this.#targetFilterCallback(target)) {
this.#ignoredTargets.add(targetInfo.targetId);
Expand Down Expand Up @@ -385,7 +417,7 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
}

this.#targetsIdsForInit.delete(target._targetId);
if (!existingTarget) {
if (!existingTarget && target.type() !== 'tab' && !target._subtype()) {
this.emit(TargetManagerEmittedEvents.TargetAvailable, target);
}
this.#finishInitializationIfReady();
Expand All @@ -397,6 +429,7 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
waitForDebuggerOnStart: true,
flatten: true,
autoAttach: true,
filter: this.#discoveryFilter,
}),
session.send('Runtime.runIfWaitingForDebugger'),
]).catch(debugError);
Expand All @@ -422,6 +455,8 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
}

this.#attachedTargetsByTargetId.delete(target._targetId);
this.emit(TargetManagerEmittedEvents.TargetGone, target);
if (target.type() !== 'tab') {
this.emit(TargetManagerEmittedEvents.TargetGone, target);
}
};
}
18 changes: 17 additions & 1 deletion packages/puppeteer-core/src/common/Connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {ConnectionTransport} from './ConnectionTransport.js';
import {debug} from './Debug.js';
import {TargetCloseError, ProtocolError} from './Errors.js';
import {EventEmitter} from './EventEmitter.js';
import {CDPTarget} from './Target.js';
import {debugError} from './util.js';

const debugProtocolSend = debug('puppeteer:protocol:SEND ►');
Expand Down Expand Up @@ -307,6 +308,7 @@ export class Connection extends EventEmitter {
const object = JSON.parse(message);
if (object.method === 'Target.attachedToTarget') {
const sessionId = object.params.sessionId;
const parentSession = this.#sessions.get(object.sessionId);
const session = new CDPSessionImpl(
this,
object.params.targetInfo.type,
Expand All @@ -315,7 +317,6 @@ export class Connection extends EventEmitter {
);
this.#sessions.set(sessionId, session);
this.emit('sessionattached', session);
const parentSession = this.#sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessionattached', session);
}
Expand Down Expand Up @@ -515,6 +516,7 @@ export class CDPSessionImpl extends CDPSession {
#callbacks = new CallbackRegistry();
#connection?: Connection;
#parentSessionId?: string;
#target?: CDPTarget;

/**
* @internal
Expand All @@ -532,6 +534,20 @@ export class CDPSessionImpl extends CDPSession {
this.#parentSessionId = parentSessionId;
}

/**
* @internal
*/
_setTarget(target: CDPTarget): void {
this.#target = target;
}

/**
* @internal
*/
_target(): CDPTarget | undefined {
return this.#target;
}

override connection(): Connection | undefined {
return this.#connection;
}
Expand Down
7 changes: 7 additions & 0 deletions packages/puppeteer-core/src/common/FirefoxTargetManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ export class FirefoxTargetManager
this.setupAttachmentListeners(this.#connection);
}

/**
* @internal
*/
_tabTargetBySession(_session?: CDPSession): CDPSession | undefined {
return undefined;
}

addTargetInterceptor(
client: CDPSession | Connection,
interceptor: TargetInterceptor
Expand Down
10 changes: 10 additions & 0 deletions packages/puppeteer-core/src/common/Frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const FrameEmittedEvents = {
LifecycleEvent: Symbol('Frame.LifecycleEvent'),
FrameNavigatedWithinDocument: Symbol('Frame.FrameNavigatedWithinDocument'),
FrameDetached: Symbol('Frame.FrameDetached'),
FrameSwappedByActivation: Symbol('Frame.FrameSwappedByActivation'),
};

/**
Expand Down Expand Up @@ -82,6 +83,15 @@ export class Frame extends BaseFrame {
this._loaderId = '';

this.updateClient(client);

this.on(FrameEmittedEvents.FrameSwappedByActivation, () => {
this._onLoadingStarted();
this._onLoadingStopped();
});
}

updateId(id: string): void {
this._id = id;
}

updateClient(client: CDPSession): void {
Expand Down
41 changes: 38 additions & 3 deletions packages/puppeteer-core/src/common/FrameManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import {Protocol} from 'devtools-protocol';

import {Page} from '../api/Page.js';
import {assert} from '../util/assert.js';
import {Deferred} from '../util/Deferred.js';
import {isErrorLike} from '../util/ErrorLike.js';

import {
CDPSession,
CDPSessionEmittedEvents,
CDPSessionImpl,
isTargetClosedError,
} from './Connection.js';
import {DeviceRequestPromptManager} from './DeviceRequestPrompt.js';
Expand Down Expand Up @@ -112,14 +114,47 @@ export class FrameManager extends EventEmitter {
this.#networkManager = new NetworkManager(client, ignoreHTTPSErrors, this);
this.#timeoutSettings = timeoutSettings;
this.setupEventListeners(this.#client);
client.once(CDPSessionEmittedEvents.Disconnected, () => {
client.once(CDPSessionEmittedEvents.Disconnected, async () => {
const mainFrame = this._frameTree.getMainFrame();
if (mainFrame) {
this.#removeFramesRecursively(mainFrame);
if (!mainFrame) {
return;
}
const swapped = Deferred.create<void>({
timeout: 100,
message: 'Frame was not swapped',
});
mainFrame.once(FrameEmittedEvents.FrameSwappedByActivation, () => {
swapped.resolve();
});
try {
await swapped.valueOrThrow();
for (const child of mainFrame.childFrames()) {
this.#removeFramesRecursively(child);
}
} catch (err) {
if (mainFrame) {
this.#removeFramesRecursively(mainFrame);
}
}
});
}

async swapFrameTree(client: CDPSession): Promise<void> {
this.#onExecutionContextsCleared(this.#client);

this.#client = client;
const frame = this._frameTree.getMainFrame();
if (frame) {
this._frameTree.removeFrame(frame);
frame.updateId((this.#client as CDPSessionImpl)._target()!._targetId);
}
this.setupEventListeners(client);
await this.initialize(client);
if (frame) {
frame.emit(FrameEmittedEvents.FrameSwappedByActivation);
}
}

private setupEventListeners(session: CDPSession) {
session.on('Page.frameAttached', event => {
this.#onFrameAttached(session, event.frameId, event.parentFrameId);
Expand Down
10 changes: 10 additions & 0 deletions packages/puppeteer-core/src/common/LifecycleWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ export class LifecycleWatcher {
FrameEmittedEvents.FrameSwapped,
this.#frameSwapped.bind(this)
),
addEventListener(
frame,
FrameEmittedEvents.FrameSwappedByActivation,
this.#frameSwappedByActivation.bind(this)
),
addEventListener(
frame,
FrameEmittedEvents.FrameDetached,
Expand Down Expand Up @@ -222,6 +227,11 @@ export class LifecycleWatcher {
this.#checkLifecycleComplete();
}

#frameSwappedByActivation(): void {
this.#swapped = true;
this.#checkLifecycleComplete();
}

#checkLifecycleComplete(): void {
// We expect navigation to commit.
if (!checkLifecycle(this.#frame, this.#expectedLifecycle)) {
Expand Down
11 changes: 11 additions & 0 deletions packages/puppeteer-core/src/common/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {Binding} from './Binding.js';
import {
CDPSession,
CDPSessionEmittedEvents,
CDPSessionImpl,
isTargetClosedError,
} from './Connection.js';
import {ConsoleMessage, ConsoleMessageType} from './ConsoleMessage.js';
Expand Down Expand Up @@ -127,6 +128,7 @@ export class CDPPage extends Page {

#closed = false;
#client: CDPSession;
#tabSession: CDPSession | undefined;
#target: CDPTarget;
#keyboard: CDPKeyboard;
#mouse: CDPMouse;
Expand Down Expand Up @@ -289,6 +291,7 @@ export class CDPPage extends Page {
) {
super();
this.#client = client;
this.#tabSession = client.parentSession();
this.#target = target;
this.#keyboard = new CDPKeyboard(client);
this.#mouse = new CDPMouse(client, this.#keyboard);
Expand All @@ -307,6 +310,14 @@ export class CDPPage extends Page {
this.#viewport = null;

this.#setupEventListeners();

this.#tabSession?.on('sessionswapped', async newSession => {
this.#client = newSession;
this.#target = (this.#client as CDPSessionImpl)._target()!;
assert(this.#target, 'Missing target on swap');
await this.#frameManager.swapFrameTree(newSession);
this.#setupEventListeners();
});
}

#setupEventListeners() {
Expand Down

0 comments on commit 14e54ba

Please sign in to comment.