Skip to content

Commit 4753d01

Browse files
committed
address comments
1 parent 31fc4dd commit 4753d01

11 files changed

+393
-269
lines changed

testing/juggler/SimpleChannel.js

+22-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class SimpleChannel {
99
const channel = new SimpleChannel(name);
1010

1111
const messageListener = {
12-
receiveMessage: message => channel._onMessage(message)
12+
receiveMessage: message => channel._onMessage(message.data)
1313
};
1414
mm.addMessageListener(SIMPLE_CHANNEL_MESSAGE_NAME, messageListener);
1515

@@ -23,6 +23,7 @@ class SimpleChannel {
2323
constructor(name) {
2424
this._name = name;
2525
this._messageId = 0;
26+
this._connectorId = 0;
2627
this._pendingMessages = new Map();
2728
this._handlers = new Map();
2829
this.transport = {
@@ -39,24 +40,28 @@ class SimpleChannel {
3940
for (const {resolve, reject, methodName} of this._pendingMessages.values())
4041
reject(new Error(`Failed "${methodName}": ${this._name} is disposed.`));
4142
this._pendingMessages.clear();
43+
this._handlers.clear();
4244
this.transport.dispose();
4345
}
4446

47+
_rejectCallbacksFromConnector(connectorId) {
48+
for (const [messageId, callback] of this._pendingMessages) {
49+
if (callback.connectorId === connectorId) {
50+
callback.reject(new Error(`Failed "${callback.methodName}": connector for namespace "${callback.namespace}" in channel "${this._name}" is disposed.`));
51+
this._pendingMessages.delete(messageId);
52+
}
53+
}
54+
}
55+
4556
connect(namespace) {
57+
const connectorId = ++this._connectorId;
4658
return {
47-
send: (...args) => this._send(namespace, ...args),
48-
emit: (...args) => void this._send(namespace, ...args).catch(e => {}),
59+
send: (...args) => this._send(namespace, connectorId, ...args),
60+
emit: (...args) => void this._send(namespace, connectorId, ...args).catch(e => {}),
61+
dispose: () => this._rejectCallbacksFromConnector(connectorId),
4962
};
5063
}
5164

52-
handler(namespace) {
53-
return this._handlers.get(namespace);
54-
}
55-
56-
handlers() {
57-
return [...this._handlers.values()];
58-
}
59-
6065
register(namespace, handler) {
6166
if (this._handlers.has(namespace))
6267
throw new Error('ERROR: double-register for namespace ' + namespace);
@@ -69,23 +74,24 @@ class SimpleChannel {
6974
}
7075

7176
/**
72-
* @param {string} sessionId
77+
* @param {string} namespace
78+
* @param {number} connectorId
7379
* @param {string} methodName
74-
* @param {*} params
80+
* @param {...*} params
7581
* @return {!Promise<*>}
7682
*/
77-
async _send(namespace, methodName, ...params) {
83+
async _send(namespace, connectorId, methodName, ...params) {
7884
if (this._disposed)
7985
throw new Error(`ERROR: channel ${this._name} is already disposed! Cannot send "${methodName}" to "${namespace}"`);
8086
const id = ++this._messageId;
8187
const promise = new Promise((resolve, reject) => {
82-
this._pendingMessages.set(id, {resolve, reject, methodName});
88+
this._pendingMessages.set(id, {connectorId, resolve, reject, methodName, namespace});
8389
});
8490
this.transport.sendMessage({requestId: id, methodName, params, namespace});
8591
return promise;
8692
}
8793

88-
async _onMessage({data}) {
94+
async _onMessage(data) {
8995
if (data.responseId) {
9096
const {resolve, reject} = this._pendingMessages.get(data.responseId);
9197
this._pendingMessages.delete(data.responseId);

testing/juggler/TargetRegistry.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class PageTarget {
152152
this._browserContext = browserContext;
153153
this._openerId = opener ? opener.id() : undefined;
154154
this._url = tab.linkedBrowser.currentURI.spec;
155-
this._channel = SimpleChannel.createForMessageManager('browser::page', tab.linkedBrowser.messageManager);
155+
this._channel = SimpleChannel.createForMessageManager(`browser::page[${this._targetId}]`, tab.linkedBrowser.messageManager);
156156

157157
const navigationListener = {
158158
QueryInterface: ChromeUtils.generateQI([ Ci.nsIWebProgressListener]),

testing/juggler/content/FrameTree.js

+98
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Cr = Components.results;
44
const Cu = Components.utils;
55

66
const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
7+
const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js');
78
const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm');
89

910
const helper = new Helper();
@@ -17,6 +18,7 @@ class FrameTree {
1718
this._browsingContextGroup.__jugglerFrameTrees = new Set();
1819
this._browsingContextGroup.__jugglerFrameTrees.add(this);
1920

21+
this._workers = new Map();
2022
this._docShellToFrame = new Map();
2123
this._frameIdToFrame = new Map();
2224
this._pageReady = !waitForInitialNavigation;
@@ -30,6 +32,17 @@ class FrameTree {
3032
]);
3133
this._scriptsToEvaluateOnNewDocument = [];
3234

35+
this._wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].createInstance(Ci.nsIWorkerDebuggerManager);
36+
this._wdmListener = {
37+
QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerManagerListener]),
38+
onRegister: this._onWorkerCreated.bind(this),
39+
onUnregister: this._onWorkerDestroyed.bind(this),
40+
};
41+
this._wdm.addListener(this._wdmListener);
42+
for (const workerDebugger of this._wdm.getWorkerDebuggerEnumerator())
43+
this._onWorkerCreated(workerDebugger);
44+
45+
3346
const flags = Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT |
3447
Ci.nsIWebProgress.NOTIFY_FRAME_LOCATION;
3548
this._eventListeners = [
@@ -39,6 +52,41 @@ class FrameTree {
3952
];
4053
}
4154

55+
workers() {
56+
return [...this._workers.values()];
57+
}
58+
59+
_frameForWorker(workerDebugger) {
60+
if (workerDebugger.type !== Ci.nsIWorkerDebugger.TYPE_DEDICATED)
61+
return null;
62+
const docShell = workerDebugger.window.docShell;
63+
return this._docShellToFrame.get(docShell) || null;
64+
}
65+
66+
_onWorkerCreated(workerDebugger) {
67+
// Note: we do not interoperate with firefox devtools.
68+
if (workerDebugger.isInitialized)
69+
return;
70+
const frame = this._frameForWorker(workerDebugger);
71+
if (!frame)
72+
return;
73+
const worker = new Worker(frame, workerDebugger);
74+
this._workers.set(workerDebugger, worker);
75+
this.emit(FrameTree.Events.WorkerCreated, worker);
76+
}
77+
78+
_onWorkerDestroyed(workerDebugger) {
79+
const frame = this._frameForWorker(workerDebugger);
80+
if (!frame)
81+
return;
82+
const worker = this._workers.get(workerDebugger);
83+
if (!worker)
84+
return;
85+
worker.dispose();
86+
this._workers.delete(workerDebugger);
87+
this.emit(FrameTree.Events.WorkerDestroyed, worker);
88+
}
89+
4290
allFramesInBrowsingContextGroup(group) {
4391
const frames = [];
4492
for (const frameTree of (group.__jugglerFrameTrees || []))
@@ -84,6 +132,7 @@ class FrameTree {
84132

85133
dispose() {
86134
this._browsingContextGroup.__jugglerFrameTrees.delete(this);
135+
this._wdm.removeListener(this._wdmListener);
87136
helper.removeListeners(this._eventListeners);
88137
}
89138

@@ -192,6 +241,8 @@ class FrameTree {
192241
FrameTree.Events = {
193242
FrameAttached: 'frameattached',
194243
FrameDetached: 'framedetached',
244+
WorkerCreated: 'workercreated',
245+
WorkerDestroyed: 'workerdestroyed',
195246
NavigationStarted: 'navigationstarted',
196247
NavigationCommitted: 'navigationcommitted',
197248
NavigationAborted: 'navigationaborted',
@@ -268,6 +319,53 @@ class Frame {
268319
url() {
269320
return this._url;
270321
}
322+
323+
}
324+
325+
class Worker {
326+
constructor(frame, workerDebugger) {
327+
this._frame = frame;
328+
this._workerId = helper.generateId();
329+
this._workerDebugger = workerDebugger;
330+
331+
workerDebugger.initialize('chrome://juggler/content/content/WorkerMain.js');
332+
333+
this._channel = new SimpleChannel(`content::worker[${this._workerId}]`);
334+
this._channel.transport = {
335+
sendMessage: obj => workerDebugger.postMessage(JSON.stringify(obj)),
336+
dispose: () => {},
337+
};
338+
this._workerDebuggerListener = {
339+
QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerListener]),
340+
onMessage: msg => void this._channel._onMessage(JSON.parse(msg)),
341+
onClose: () => void this._channel.dispose(),
342+
onError: (filename, lineno, message) => {
343+
dump(`Error in worker: ${message} @${filename}:${lineno}\n`);
344+
},
345+
};
346+
workerDebugger.addListener(this._workerDebuggerListener);
347+
}
348+
349+
channel() {
350+
return this._channel;
351+
}
352+
353+
frame() {
354+
return this._frame;
355+
}
356+
357+
id() {
358+
return this._workerId;
359+
}
360+
361+
url() {
362+
return this._workerDebugger.url;
363+
}
364+
365+
dispose() {
366+
this._channel.dispose();
367+
this._workerDebugger.removeListener(this._workerDebuggerListener);
368+
}
271369
}
272370

273371
var EXPORTED_SYMBOLS = ['FrameTree'];

0 commit comments

Comments
 (0)