Skip to content

Commit

Permalink
refactor: move to flatten protocol (#3827)
Browse files Browse the repository at this point in the history
DevTools protocol is dropping nested targets and switching to
flatten protocol. This patch adopts the new scheme.

Once this change lands, tip-of-tree Puppeteer will be incompatible
with Chromium below 72.0.3606.0. Chromium 72 goes stable on [Jan, 29](https://www.chromestatus.com/features/schedule) - the same time we release the
next version of Puppeteer, so this change won't hurt those clients who try using
tip-of-tree Puppeteer with stable chrome. 

For the record: the previous attempt to land this was #3524.
  • Loading branch information
aslushnikov committed Jan 22, 2019
1 parent 678b8e8 commit 89a5c39
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 71 deletions.
113 changes: 45 additions & 68 deletions lib/Connection.js
Expand Up @@ -16,7 +16,6 @@
const {helper, assert} = require('./helper');
const {Events} = require('./Events');
const debugProtocol = require('debug')('puppeteer:protocol');
const debugSession = require('debug')('puppeteer:session');
const EventEmitter = require('events');

class Connection extends EventEmitter {
Expand Down Expand Up @@ -46,11 +45,15 @@ class Connection extends EventEmitter {
* @return {!Connection}
*/
static fromSession(session) {
let connection = session._connection;
// TODO(lushnikov): move to flatten protocol to avoid this.
while (connection instanceof CDPSession)
connection = connection._connection;
return connection;
return session._connection;
}

/**
* @param {string} sessionId
* @return {?CDPSession}
*/
session(sessionId) {
return this._sessions.get(sessionId) || null;
}

/**
Expand All @@ -66,15 +69,24 @@ class Connection extends EventEmitter {
* @return {!Promise<?Object>}
*/
send(method, params = {}) {
const id = ++this._lastId;
const message = JSON.stringify({id, method, params});
debugProtocol('SEND ► ' + message);
this._transport.send(message);
const id = this._rawSend({method, params});
return new Promise((resolve, reject) => {
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
});
}

/**
* @param {*} message
* @return {number}
*/
_rawSend(message) {
const id = ++this._lastId;
message = JSON.stringify(Object.assign({}, message, {id}));
debugProtocol('SEND ► ' + message);
this._transport.send(message);
return id;
}

/**
* @param {string} message
*/
Expand All @@ -83,7 +95,22 @@ class Connection extends EventEmitter {
await new Promise(f => setTimeout(f, this._delay));
debugProtocol('◀ RECV ' + message);
const object = JSON.parse(message);
if (object.id) {
if (object.method === 'Target.attachedToTarget') {
const sessionId = object.params.sessionId;
const session = new CDPSession(this, object.params.targetInfo.type, sessionId);
this._sessions.set(sessionId, session);
} else if (object.method === 'Target.detachedFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session) {
session._onClosed();
this._sessions.delete(object.params.sessionId);
}
}
if (object.sessionId) {
const session = this._sessions.get(object.sessionId);
if (session)
session._onMessage(object);
} else if (object.id) {
const callback = this._callbacks.get(object.id);
// Callbacks could be all rejected if someone has called `.dispose()`.
if (callback) {
Expand All @@ -94,18 +121,7 @@ class Connection extends EventEmitter {
callback.resolve(object.result);
}
} else {
if (object.method === 'Target.receivedMessageFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session)
session._onMessage(object.params.message);
} else if (object.method === 'Target.detachedFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session)
session._onClosed();
this._sessions.delete(object.params.sessionId);
} else {
this.emit(object.method, object.params);
}
this.emit(object.method, object.params);
}
}

Expand Down Expand Up @@ -134,30 +150,24 @@ class Connection extends EventEmitter {
* @return {!Promise<!CDPSession>}
*/
async createSession(targetInfo) {
const {sessionId} = await this.send('Target.attachToTarget', {targetId: targetInfo.targetId});
const session = new CDPSession(this, targetInfo.type, sessionId);
this._sessions.set(sessionId, session);
return session;
const {sessionId} = await this.send('Target.attachToTarget', {targetId: targetInfo.targetId, flatten: true});
return this._sessions.get(sessionId);
}
}

class CDPSession extends EventEmitter {
/**
* @param {!Connection|!CDPSession} connection
* @param {!Connection} connection
* @param {string} targetType
* @param {string} sessionId
*/
constructor(connection, targetType, sessionId) {
super();
this._lastId = 0;
/** @type {!Map<number, {resolve: function, reject: function, error: !Error, method: string}>}*/
this._callbacks = new Map();
/** @type {null|Connection|CDPSession} */
this._connection = connection;
this._targetType = targetType;
this._sessionId = sessionId;
/** @type {!Map<string, !CDPSession>}*/
this._sessions = new Map();
}

/**
Expand All @@ -168,28 +178,16 @@ class CDPSession extends EventEmitter {
send(method, params = {}) {
if (!this._connection)
return Promise.reject(new Error(`Protocol error (${method}): Session closed. Most likely the ${this._targetType} has been closed.`));
const id = ++this._lastId;
const message = JSON.stringify({id, method, params});
debugSession('SEND ► ' + message);
this._connection.send('Target.sendMessageToTarget', {sessionId: this._sessionId, message}).catch(e => {
// The response from target might have been already dispatched.
if (!this._callbacks.has(id))
return;
const callback = this._callbacks.get(id);
this._callbacks.delete(id);
callback.reject(rewriteError(callback.error, e && e.message));
});
const id = this._connection._rawSend({sessionId: this._sessionId, method, params});
return new Promise((resolve, reject) => {
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
});
}

/**
* @param {string} message
* @param {{id?: number, method: string, params: Object, error: {message: string, data: any}, result?: *}} object
*/
_onMessage(message) {
debugSession('◀ RECV ' + message);
const object = JSON.parse(message);
_onMessage(object) {
if (object.id && this._callbacks.has(object.id)) {
const callback = this._callbacks.get(object.id);
this._callbacks.delete(object.id);
Expand All @@ -198,17 +196,6 @@ class CDPSession extends EventEmitter {
else
callback.resolve(object.result);
} else {
if (object.method === 'Target.receivedMessageFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session)
session._onMessage(object.params.message);
} else if (object.method === 'Target.detachedFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session) {
session._onClosed();
this._sessions.delete(object.params.sessionId);
}
}
assert(!object.id);
this.emit(object.method, object.params);
}
Expand All @@ -227,16 +214,6 @@ class CDPSession extends EventEmitter {
this._connection = null;
this.emit(Events.CDPSession.Disconnected);
}

/**
* @param {string} targetType
* @param {string} sessionId
*/
_createSession(targetType, sessionId) {
const session = new CDPSession(this, targetType, sessionId);
this._sessions.set(sessionId, session);
return session;
}
}

helper.tracePublicAPI(CDPSession);
Expand Down
6 changes: 3 additions & 3 deletions lib/Page.js
Expand Up @@ -18,6 +18,7 @@ const fs = require('fs');
const EventEmitter = require('events');
const mime = require('mime');
const {Events} = require('./Events');
const {Connection} = require('./Connection');
const {NetworkManager} = require('./NetworkManager');
const {Dialog} = require('./Dialog');
const {EmulationManager} = require('./EmulationManager');
Expand Down Expand Up @@ -47,7 +48,7 @@ class Page extends EventEmitter {
const page = new Page(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);

await Promise.all([
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false}),
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
client.send('Network.enable', {}),
client.send('Runtime.enable', {}).then(() => page._frameManager.ensureSecondaryDOMWorld()),
Expand Down Expand Up @@ -106,11 +107,10 @@ class Page extends EventEmitter {
}).catch(debugError);
return;
}
const session = client._createSession(event.targetInfo.type, event.sessionId);
const session = Connection.fromSession(client).session(event.sessionId);
const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
this._workers.set(event.sessionId, worker);
this.emit(Events.Page.WorkerCreated, worker);

});
client.on('Target.detachedFromTarget', event => {
const worker = this._workers.get(event.sessionId);
Expand Down

0 comments on commit 89a5c39

Please sign in to comment.