Skip to content

Commit b6fd4dc

Browse files
authored
feat(rpc): merge ChannelOwner and ConnectionScope (#2911)
1 parent 54f9a0d commit b6fd4dc

18 files changed

+148
-158
lines changed

src/rpc/client/browser.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { BrowserChannel, BrowserInitializer } from '../channels';
1919
import { BrowserContext } from './browserContext';
2020
import { Page } from './page';
2121
import { ChannelOwner } from './channelOwner';
22-
import { ConnectionScope } from './connection';
2322
import { Events } from '../../events';
2423
import { CDPSession } from './cdpSession';
2524

@@ -37,13 +36,13 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
3736
return browser ? Browser.from(browser) : null;
3837
}
3938

40-
constructor(scope: ConnectionScope, guid: string, initializer: BrowserInitializer) {
41-
super(scope, guid, initializer, true);
39+
constructor(parent: ChannelOwner, guid: string, initializer: BrowserInitializer) {
40+
super(parent, guid, initializer, true);
4241
this._channel.on('close', () => {
4342
this._isConnected = false;
4443
this.emit(Events.Browser.Disconnected);
4544
this._isClosedOrClosing = true;
46-
this._scope.dispose();
45+
this._dispose();
4746
});
4847
this._closedPromise = new Promise(f => this.once(Events.Browser.Disconnected, f));
4948
}

src/rpc/client/browserContext.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import { BrowserContextChannel, BrowserContextInitializer } from '../channels';
2323
import { ChannelOwner } from './channelOwner';
2424
import { helper } from '../../helper';
2525
import { Browser } from './browser';
26-
import { ConnectionScope } from './connection';
2726
import { Events } from '../../events';
2827
import { TimeoutSettings } from '../../timeoutSettings';
2928
import { CDPSession } from './cdpSession';
@@ -51,8 +50,8 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
5150
return context ? BrowserContext.from(context) : null;
5251
}
5352

54-
constructor(scope: ConnectionScope, guid: string, initializer: BrowserContextInitializer) {
55-
super(scope, guid, initializer, true);
53+
constructor(parent: ChannelOwner, guid: string, initializer: BrowserContextInitializer) {
54+
super(parent, guid, initializer, true);
5655
initializer.pages.forEach(p => {
5756
const page = Page.from(p);
5857
this._pages.add(page);
@@ -225,7 +224,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
225224
}
226225
this._pendingWaitForEvents.clear();
227226
this.emit(Events.BrowserContext.Close);
228-
this._scope.dispose();
227+
this._dispose();
229228
}
230229

231230
async close(): Promise<void> {

src/rpc/client/browserServer.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import { ChildProcess } from 'child_process';
1818
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
19-
import { ConnectionScope } from './connection';
2019
import { ChannelOwner } from './channelOwner';
2120
import { Events } from '../../events';
2221

@@ -25,8 +24,8 @@ export class BrowserServer extends ChannelOwner<BrowserServerChannel, BrowserSer
2524
return (server as any)._object;
2625
}
2726

28-
constructor(scope: ConnectionScope, guid: string, initializer: BrowserServerInitializer) {
29-
super(scope, guid, initializer);
27+
constructor(parent: ChannelOwner, guid: string, initializer: BrowserServerInitializer) {
28+
super(parent, guid, initializer);
3029
this._channel.on('close', () => this.emit(Events.BrowserServer.Close));
3130
}
3231

src/rpc/client/browserType.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { BrowserTypeChannel, BrowserTypeInitializer } from '../channels';
1919
import { Browser } from './browser';
2020
import { BrowserContext } from './browserContext';
2121
import { ChannelOwner } from './channelOwner';
22-
import { ConnectionScope } from './connection';
2322
import { BrowserServer } from './browserServer';
2423

2524
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
@@ -28,8 +27,8 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
2827
return (browserTyep as any)._object;
2928
}
3029

31-
constructor(scope: ConnectionScope, guid: string, initializer: BrowserTypeInitializer) {
32-
super(scope, guid, initializer);
30+
constructor(parent: ChannelOwner, guid: string, initializer: BrowserTypeInitializer) {
31+
super(parent, guid, initializer);
3332
}
3433

3534
executablePath(): string {

src/rpc/client/cdpSession.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
import { CDPSessionChannel, CDPSessionInitializer } from '../channels';
18-
import { ConnectionScope } from './connection';
1918
import { ChannelOwner } from './channelOwner';
2019
import { Protocol } from '../../chromium/protocol';
2120

@@ -30,11 +29,11 @@ export class CDPSession extends ChannelOwner<CDPSessionChannel, CDPSessionInitia
3029
removeListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
3130
once: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
3231

33-
constructor(scope: ConnectionScope, guid: string, initializer: CDPSessionInitializer) {
34-
super(scope, guid, initializer, true);
32+
constructor(parent: ChannelOwner, guid: string, initializer: CDPSessionInitializer) {
33+
super(parent, guid, initializer, true);
3534

3635
this._channel.on('event', ({ method, params }) => this.emit(method, params));
37-
this._channel.on('disconnected', () => this._scope.dispose());
36+
this._channel.on('disconnected', () => this._dispose());
3837

3938
this.on = super.on;
4039
this.addListener = super.addListener;

src/rpc/client/channelOwner.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,33 @@
1616

1717
import { EventEmitter } from 'events';
1818
import { Channel } from '../channels';
19-
import { ConnectionScope } from './connection';
19+
import { Connection } from './connection';
20+
import { assert } from '../../helper';
2021

21-
export abstract class ChannelOwner<T extends Channel, Initializer> extends EventEmitter {
22+
export abstract class ChannelOwner<T extends Channel = Channel, Initializer = {}> extends EventEmitter {
23+
private _connection: Connection;
24+
private _isScope: boolean;
25+
// Parent is always "isScope".
26+
private _parent: ChannelOwner | undefined;
27+
// Only "isScope" channel owners have registered objects inside.
28+
private _objects = new Map<string, ChannelOwner>();
29+
30+
readonly _guid: string;
2231
readonly _channel: T;
2332
readonly _initializer: Initializer;
24-
readonly _scope: ConnectionScope;
25-
readonly guid: string;
2633

27-
constructor(scope: ConnectionScope, guid: string, initializer: Initializer, isScope?: boolean) {
34+
constructor(parent: ChannelOwner | Connection, guid: string, initializer: Initializer, isScope?: boolean) {
2835
super();
29-
this.guid = guid;
30-
this._scope = isScope ? scope.createChild(guid) : scope;
36+
37+
this._connection = parent instanceof Connection ? parent : parent._connection;
38+
this._guid = guid;
39+
this._isScope = !!isScope;
40+
this._parent = parent instanceof Connection ? undefined : parent;
41+
42+
this._connection._objects.set(guid, this);
43+
if (this._parent)
44+
this._parent._objects.set(guid, this);
45+
3146
const base = new EventEmitter();
3247
this._channel = new Proxy(base, {
3348
get: (obj: any, prop) => {
@@ -45,10 +60,35 @@ export abstract class ChannelOwner<T extends Channel, Initializer> extends Event
4560
return obj.addListener;
4661
if (prop === 'removeEventListener')
4762
return obj.removeListener;
48-
return (params: any) => scope.sendMessageToServer({ guid, method: String(prop), params });
63+
return (params: any) => this._connection.sendMessageToServer({ guid, method: String(prop), params });
4964
},
5065
});
5166
(this._channel as any)._object = this;
5267
this._initializer = initializer;
5368
}
69+
70+
_dispose() {
71+
assert(this._isScope);
72+
73+
// Clean up from parent and connection.
74+
if (this._parent)
75+
this._parent._objects.delete(this._guid);
76+
this._connection._objects.delete(this._guid);
77+
78+
// Dispose all children.
79+
for (const [guid, object] of [...this._objects]) {
80+
if (object._isScope)
81+
object._dispose();
82+
else
83+
this._connection._objects.delete(guid);
84+
}
85+
this._objects.clear();
86+
}
87+
88+
_debugScopeState(): any {
89+
return {
90+
_guid: this._guid,
91+
objects: this._isScope ? Array.from(this._objects.values()).map(o => o._debugScopeState()) : undefined,
92+
};
93+
}
5494
}

0 commit comments

Comments
 (0)