зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1713442 - [remote] Support events in windowglobal MessageHandlers r=webdriver-reviewers,whimboo
Differential Revision: https://phabricator.services.mozilla.com/D120640
This commit is contained in:
Родитель
1e11a69a62
Коммит
aed2bec56c
|
@ -88,6 +88,28 @@ class MessageHandler extends EventEmitter {
|
|||
this.emit("message-handler-destroyed", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a message-handler-event. Such events should bubble up to the root of
|
||||
* a MessageHandler network.
|
||||
*
|
||||
* @param {String} method
|
||||
* A string literal of the form [module name].[event name]. This is the
|
||||
* event name.
|
||||
* @param {Object} params
|
||||
* The event parameters.
|
||||
*/
|
||||
emitMessageHandlerEvent(method, params) {
|
||||
this.emit("message-handler-event", {
|
||||
// TODO: The messageHandlerInfo needs to be wrapped in the event so
|
||||
// that consumers can check the type/context. Once MessageHandlerRegistry
|
||||
// becomes context-specific (Bug 1722659), only the sessionId will be
|
||||
// required.
|
||||
messageHandlerInfo: this._messageHandlerInfo,
|
||||
method,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CommandDestination
|
||||
* @property {String} type - One of MessageHandler.type.
|
||||
|
|
|
@ -11,6 +11,8 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
EventEmitter: "resource://gre/modules/EventEmitter.jsm",
|
||||
|
||||
Log: "chrome://remote/content/shared/Log.jsm",
|
||||
MessageHandlerInfo:
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandlerInfo.jsm",
|
||||
|
@ -61,8 +63,10 @@ function getMessageHandlerClass(type) {
|
|||
*
|
||||
* Note: this is still created as a class, but exposed as a singleton.
|
||||
*/
|
||||
class MessageHandlerRegistryClass {
|
||||
class MessageHandlerRegistryClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* Map of all message handlers registered in this process.
|
||||
* Keys are based on session id, message handler type and message handler
|
||||
|
@ -75,6 +79,7 @@ class MessageHandlerRegistryClass {
|
|||
this._onMessageHandlerDestroyed = this._onMessageHandlerDestroyed.bind(
|
||||
this
|
||||
);
|
||||
this._onMessageHandlerEvent = this._onMessageHandlerEvent.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,6 +159,30 @@ class MessageHandlerRegistryClass {
|
|||
return messageHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an already registered RootMessageHandler instance matching the
|
||||
* provided sessionId.
|
||||
*
|
||||
* @param {String} sessionId
|
||||
* ID of the session the handler is used for.
|
||||
* @return {RootMessageHandler}
|
||||
* A RootMessageHandler instance.
|
||||
* @throws {Error}
|
||||
* If no root MessageHandler can be found for the provided session id.
|
||||
*/
|
||||
getRootMessageHandler(sessionId) {
|
||||
const rootMessageHandler = this.getExistingMessageHandler(
|
||||
sessionId,
|
||||
RootMessageHandler.type
|
||||
);
|
||||
if (!rootMessageHandler) {
|
||||
throw new Error(
|
||||
`Unable to find a root MessageHandler for session id ${sessionId}`
|
||||
);
|
||||
}
|
||||
return rootMessageHandler;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `[object ${this.constructor.name}]`;
|
||||
}
|
||||
|
@ -182,6 +211,7 @@ class MessageHandlerRegistryClass {
|
|||
"message-handler-destroyed",
|
||||
this._onMessageHandlerDestroyed
|
||||
);
|
||||
messageHandler.on("message-handler-event", this._onMessageHandlerEvent);
|
||||
return messageHandler;
|
||||
}
|
||||
|
||||
|
@ -198,13 +228,20 @@ class MessageHandlerRegistryClass {
|
|||
|
||||
// Event handlers
|
||||
|
||||
_onMessageHandlerDestroyed(evt, messageHandler) {
|
||||
_onMessageHandlerDestroyed(eventName, messageHandler) {
|
||||
messageHandler.off(
|
||||
"message-handler-destroyed",
|
||||
this._onMessageHandlerDestroyed
|
||||
);
|
||||
messageHandler.off("message-handler-event", this._onMessageHandlerEvent);
|
||||
this._unregisterMessageHandler(messageHandler);
|
||||
}
|
||||
|
||||
_onMessageHandlerEvent(eventName, messageHandlerEvent) {
|
||||
// The registry simply re-emits MessageHandler events so that consumers
|
||||
// don't have to attach listeners to individual MessageHandler instances.
|
||||
this.emit("message-handler-registry-event", messageHandlerEvent);
|
||||
}
|
||||
}
|
||||
|
||||
const MessageHandlerRegistry = new MessageHandlerRegistryClass();
|
||||
|
|
|
@ -6,37 +6,10 @@
|
|||
add_task(async function test_broadcasting_with_frames() {
|
||||
info("Navigate the initial tab to the test URL");
|
||||
const tab = gBrowser.selectedTab;
|
||||
|
||||
// Create a test page with 2 iframes:
|
||||
// - one with a different eTLD+1 (example.com)
|
||||
// - one with a nested iframe on a different eTLD+1 (example.net)
|
||||
//
|
||||
// Overall the document structure should look like:
|
||||
//
|
||||
// html (example.org)
|
||||
// iframe (example.org)
|
||||
// iframe (example.net)
|
||||
// iframe(example.com)
|
||||
//
|
||||
// Which means we should have 4 browsing contexts in total.
|
||||
|
||||
// Create the markup for an example.net frame nested in an example.com frame.
|
||||
const NESTED_FRAME_MARKUP = createFrameForUri(
|
||||
`http://example.org/document-builder.sjs?html=${createFrame("example.net")}`
|
||||
);
|
||||
|
||||
// Combine the nested frame markup created above with an example.com frame.
|
||||
const TEST_URI_MARKUP = `${NESTED_FRAME_MARKUP}${createFrame("example.com")}`;
|
||||
|
||||
// Create the test page URI on example.org.
|
||||
const TEST_URI = `http://example.org/document-builder.sjs?html=${encodeURI(
|
||||
TEST_URI_MARKUP
|
||||
)}`;
|
||||
|
||||
await loadURL(tab.linkedBrowser, TEST_URI);
|
||||
await loadURL(tab.linkedBrowser, createTestMarkupWithFrames());
|
||||
|
||||
const contexts = tab.linkedBrowser.browsingContext.getAllBrowsingContextsInSubtree();
|
||||
is(contexts.length, 4, "Test tab has 3 children contexts");
|
||||
is(contexts.length, 4, "Test tab has 3 children contexts (4 in total)");
|
||||
|
||||
const rootMessageHandler = createRootMessageHandler(
|
||||
"session-id-broadcasting_with_frames"
|
||||
|
@ -63,20 +36,3 @@ add_task(async function test_broadcasting_with_frames() {
|
|||
|
||||
rootMessageHandler.destroy();
|
||||
});
|
||||
|
||||
/**
|
||||
* Create inline markup for a simple iframe that can be used with
|
||||
* document-builder.sjs. The iframe will be served under the provided domain.
|
||||
*
|
||||
* @param {String} domain
|
||||
* A domain (eg "example.com"), compatible with build/pgo/server-locations.txt
|
||||
*/
|
||||
function createFrame(domain) {
|
||||
return createFrameForUri(
|
||||
`http://${domain}/document-builder.sjs?html=frame-${domain}`
|
||||
);
|
||||
}
|
||||
|
||||
function createFrameForUri(uri) {
|
||||
return `<iframe src="${encodeURI(uri)}"></iframe>`;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ support-files =
|
|||
prefs =
|
||||
remote.messagehandler.modulecache.useBrowserTestRoot=true
|
||||
|
||||
[browser_events.js]
|
||||
[browser_handle_command_errors.js]
|
||||
[browser_handle_simple_command.js]
|
||||
[browser_registry.js]
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { MessageHandlerRegistry } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandlerRegistry.jsm"
|
||||
);
|
||||
const { RootMessageHandler } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm"
|
||||
);
|
||||
const { WindowGlobalMessageHandler } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/WindowGlobalMessageHandler.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Emit an event from a WindowGlobal module triggered by a specific command.
|
||||
* Check that the event is emitted on the RootMessageHandler as well as on
|
||||
* the parent process MessageHandlerRegistry.
|
||||
*/
|
||||
add_task(async function test_event() {
|
||||
const tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"http://example.com/document-builder.sjs?html=tab"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
const browsingContext = tab.linkedBrowser.browsingContext;
|
||||
|
||||
const rootMessageHandler = createRootMessageHandler("session-id-event");
|
||||
|
||||
const onTestEvent = rootMessageHandler.once("message-handler-event");
|
||||
// MessageHandlerRegistry should forward all the message-handler-events.
|
||||
const onRegistryEvent = MessageHandlerRegistry.once(
|
||||
"message-handler-registry-event"
|
||||
);
|
||||
|
||||
callTestEmitEvent(rootMessageHandler, browsingContext.id);
|
||||
|
||||
const messageHandlerEvent = await onTestEvent;
|
||||
is(
|
||||
messageHandlerEvent.method,
|
||||
"event.testEvent",
|
||||
"Received event.testEvent on the ROOT MessageHandler"
|
||||
);
|
||||
is(
|
||||
messageHandlerEvent.params.text,
|
||||
`event from ${browsingContext.id}`,
|
||||
"Received the expected data in testEvent"
|
||||
);
|
||||
const registryEvent = await onRegistryEvent;
|
||||
is(
|
||||
registryEvent,
|
||||
messageHandlerEvent,
|
||||
"The event forwarded by the MessageHandlerRegistry is identical to the MessageHandler event"
|
||||
);
|
||||
|
||||
rootMessageHandler.destroy();
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Emit an event from a Root module triggered by a specific command.
|
||||
* Check that the event is emitted on the RootMessageHandler.
|
||||
*/
|
||||
add_task(async function test_root_event() {
|
||||
const rootMessageHandler = createRootMessageHandler("session-id-root_event");
|
||||
|
||||
const onTestEvent = rootMessageHandler.once("message-handler-event");
|
||||
rootMessageHandler.handleCommand({
|
||||
moduleName: "event",
|
||||
commandName: "testEmitRootEvent",
|
||||
destination: {
|
||||
type: RootMessageHandler.type,
|
||||
},
|
||||
});
|
||||
|
||||
const { method, params } = await onTestEvent;
|
||||
is(
|
||||
method,
|
||||
"event.testRootEvent",
|
||||
"Received event.testRootEvent on the ROOT MessageHandler"
|
||||
);
|
||||
is(
|
||||
params.text,
|
||||
"event from root",
|
||||
"Received the expected payload in testRootEvent"
|
||||
);
|
||||
|
||||
rootMessageHandler.destroy();
|
||||
});
|
||||
|
||||
/**
|
||||
* Emit an event from a windowglobal-in-root module triggered by a specific command.
|
||||
* Check that the event is emitted on the RootMessageHandler.
|
||||
*/
|
||||
add_task(async function test_windowglobal_in_root_event() {
|
||||
const tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"http://example.com/document-builder.sjs?html=tab"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
const browsingContext = tab.linkedBrowser.browsingContext;
|
||||
|
||||
const rootMessageHandler = createRootMessageHandler(
|
||||
"session-id-windowglobal_in_root_event"
|
||||
);
|
||||
|
||||
const onTestEvent = rootMessageHandler.once("message-handler-event");
|
||||
rootMessageHandler.handleCommand({
|
||||
moduleName: "event",
|
||||
commandName: "testEmitWindowGlobalInRootEvent",
|
||||
destination: {
|
||||
type: WindowGlobalMessageHandler.type,
|
||||
id: browsingContext.id,
|
||||
},
|
||||
});
|
||||
|
||||
const { method, params } = await onTestEvent;
|
||||
is(
|
||||
method,
|
||||
"event.testWindowGlobalInRootEvent",
|
||||
"Received event.testWindowGlobalInRoot on the ROOT MessageHandler"
|
||||
);
|
||||
is(
|
||||
params.text,
|
||||
`windowglobal-in-root event for ${browsingContext.id}`,
|
||||
"Received the expected payload in testWindowGlobalInRoot"
|
||||
);
|
||||
|
||||
rootMessageHandler.destroy();
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Emit an event from a windowglobal module, but from 2 different sessions.
|
||||
* Check that the event is emitted by the corresponding RootMessageHandler as
|
||||
* well as by the parent process MessageHandlerRegistry.
|
||||
*/
|
||||
add_task(async function test_event_multisession() {
|
||||
const tab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"http://example.com/document-builder.sjs?html=tab"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
const browsingContextId = tab.linkedBrowser.browsingContext.id;
|
||||
|
||||
const root1 = createRootMessageHandler("session-id-event_multisession-1");
|
||||
let root1Events = 0;
|
||||
const onRoot1Event = function(evtName, wrappedEvt) {
|
||||
if (wrappedEvt.method === "event.testEvent") {
|
||||
root1Events++;
|
||||
}
|
||||
};
|
||||
root1.on("message-handler-event", onRoot1Event);
|
||||
|
||||
const root2 = createRootMessageHandler("session-id-event_multisession-2");
|
||||
let root2Events = 0;
|
||||
const onRoot2Event = function(evtName, wrappedEvt) {
|
||||
if (wrappedEvt.method === "event.testEvent") {
|
||||
root2Events++;
|
||||
}
|
||||
};
|
||||
root2.on("message-handler-event", onRoot2Event);
|
||||
|
||||
let registryEvents = 0;
|
||||
const onRegistryEvent = function(evtName, wrappedEvt) {
|
||||
if (wrappedEvt.method === "event.testEvent") {
|
||||
registryEvents++;
|
||||
}
|
||||
};
|
||||
MessageHandlerRegistry.on("message-handler-registry-event", onRegistryEvent);
|
||||
|
||||
callTestEmitEvent(root1, browsingContextId);
|
||||
callTestEmitEvent(root2, browsingContextId);
|
||||
|
||||
info("Wait for root1 event to be received");
|
||||
await TestUtils.waitForCondition(() => root1Events === 1);
|
||||
info("Wait for root2 event to be received");
|
||||
await TestUtils.waitForCondition(() => root2Events === 1);
|
||||
|
||||
await TestUtils.waitForTick();
|
||||
is(root1Events, 1, "Session 1 only received 1 event");
|
||||
is(root2Events, 1, "Session 2 only received 1 event");
|
||||
is(
|
||||
registryEvents,
|
||||
2,
|
||||
"MessageHandlerRegistry forwarded events from both sessions"
|
||||
);
|
||||
|
||||
root1.off("message-handler-event", onRoot1Event);
|
||||
root2.off("message-handler-event", onRoot2Event);
|
||||
MessageHandlerRegistry.off("message-handler-registry-event", onRegistryEvent);
|
||||
root1.destroy();
|
||||
root2.destroy();
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that events can be emitted from individual frame contexts and that
|
||||
* events going through a shared content process MessageHandlerRegistry are not
|
||||
* duplicated.
|
||||
*/
|
||||
add_task(async function test_event_with_frames() {
|
||||
info("Navigate the initial tab to the test URL");
|
||||
const tab = gBrowser.selectedTab;
|
||||
await loadURL(tab.linkedBrowser, createTestMarkupWithFrames());
|
||||
|
||||
const contexts = tab.linkedBrowser.browsingContext.getAllBrowsingContextsInSubtree();
|
||||
is(contexts.length, 4, "Test tab has 3 children contexts (4 in total)");
|
||||
|
||||
const rootMessageHandler = createRootMessageHandler(
|
||||
"session-id-event_with_frames"
|
||||
);
|
||||
|
||||
let rootEvents = [];
|
||||
const onRootEvent = function(evtName, wrappedEvt) {
|
||||
if (wrappedEvt.method === "event.testEvent") {
|
||||
rootEvents.push(wrappedEvt.params.text);
|
||||
}
|
||||
};
|
||||
rootMessageHandler.on("message-handler-event", onRootEvent);
|
||||
|
||||
for (const context of contexts) {
|
||||
callTestEmitEvent(rootMessageHandler, context.id);
|
||||
info("Wait for root event to be received");
|
||||
await TestUtils.waitForCondition(() =>
|
||||
rootEvents.includes(`event from ${context.id}`)
|
||||
);
|
||||
}
|
||||
|
||||
info("Wait for a bit and check that we did not receive duplicated events");
|
||||
await TestUtils.waitForTick();
|
||||
is(rootEvents.length, 4, "Only received 4 events");
|
||||
|
||||
rootMessageHandler.off("message-handler-event", onRootEvent);
|
||||
rootMessageHandler.destroy();
|
||||
});
|
||||
|
||||
function callTestEmitEvent(rootMessageHandler, browsingContextId) {
|
||||
rootMessageHandler.handleCommand({
|
||||
moduleName: "event",
|
||||
commandName: "testEmitEvent",
|
||||
destination: {
|
||||
type: WindowGlobalMessageHandler.type,
|
||||
id: browsingContextId,
|
||||
},
|
||||
});
|
||||
}
|
|
@ -46,3 +46,47 @@ async function addTab(url) {
|
|||
});
|
||||
return tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create inline markup for a simple iframe that can be used with
|
||||
* document-builder.sjs. The iframe will be served under the provided domain.
|
||||
*
|
||||
* @param {String} domain
|
||||
* A domain (eg "example.com"), compatible with build/pgo/server-locations.txt
|
||||
*/
|
||||
function createFrame(domain) {
|
||||
return createFrameForUri(
|
||||
`http://${domain}/document-builder.sjs?html=frame-${domain}`
|
||||
);
|
||||
}
|
||||
|
||||
function createFrameForUri(uri) {
|
||||
return `<iframe src="${encodeURI(uri)}"></iframe>`;
|
||||
}
|
||||
|
||||
// Create a test page with 2 iframes:
|
||||
// - one with a different eTLD+1 (example.com)
|
||||
// - one with a nested iframe on a different eTLD+1 (example.net)
|
||||
//
|
||||
// Overall the document structure should look like:
|
||||
//
|
||||
// html (example.org)
|
||||
// iframe (example.org)
|
||||
// iframe (example.net)
|
||||
// iframe(example.com)
|
||||
//
|
||||
// Which means we should have 4 browsing contexts in total.
|
||||
function createTestMarkupWithFrames() {
|
||||
// Create the markup for an example.net frame nested in an example.com frame.
|
||||
const NESTED_FRAME_MARKUP = createFrameForUri(
|
||||
`http://example.org/document-builder.sjs?html=${createFrame("example.net")}`
|
||||
);
|
||||
|
||||
// Combine the nested frame markup created above with an example.com frame.
|
||||
const TEST_URI_MARKUP = `${NESTED_FRAME_MARKUP}${createFrame("example.com")}`;
|
||||
|
||||
// Create the test page URI on example.org.
|
||||
return `http://example.org/document-builder.sjs?html=${encodeURI(
|
||||
TEST_URI_MARKUP
|
||||
)}`;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["event"];
|
||||
|
||||
class Event {
|
||||
constructor(messageHandler) {
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
destroy() {}
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
|
||||
testEmitRootEvent() {
|
||||
this.messageHandler.emitMessageHandlerEvent("event.testRootEvent", {
|
||||
text: "event from root",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const event = Event;
|
|
@ -0,0 +1,28 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["event"];
|
||||
|
||||
class Event {
|
||||
constructor(messageHandler) {
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
destroy() {}
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
|
||||
testEmitWindowGlobalInRootEvent(params, destination) {
|
||||
this.messageHandler.emitMessageHandlerEvent(
|
||||
"event.testWindowGlobalInRootEvent",
|
||||
{ text: `windowglobal-in-root event for ${destination.id}` }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const event = Event;
|
|
@ -0,0 +1,28 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["event"];
|
||||
|
||||
class Event {
|
||||
constructor(messageHandler) {
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
destroy() {}
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
|
||||
testEmitEvent() {
|
||||
// Emit a payload including the contextId to check which context emitted
|
||||
// a specific event.
|
||||
const text = `event from ${this.messageHandler.contextId}`;
|
||||
this.messageHandler.emitMessageHandlerEvent("event.testEvent", { text });
|
||||
}
|
||||
}
|
||||
|
||||
const event = Event;
|
|
@ -26,6 +26,17 @@ class MessageHandlerFrameChild extends JSWindowActorChild {
|
|||
actorCreated() {
|
||||
this.type = WindowGlobalMessageHandler.type;
|
||||
this.context = this.manager.browsingContext;
|
||||
|
||||
this._onRegistryEvent = this._onRegistryEvent.bind(this);
|
||||
|
||||
// MessageHandlerFrameChild is responsible for forwarding events from
|
||||
// WindowGlobalMessageHandler to the parent process.
|
||||
// Such events are re-emitted on the MessageHandlerRegistry to avoid
|
||||
// setting up listeners on individual MessageHandler instances.
|
||||
MessageHandlerRegistry.on(
|
||||
"message-handler-registry-event",
|
||||
this._onRegistryEvent
|
||||
);
|
||||
}
|
||||
|
||||
receiveMessage(message) {
|
||||
|
@ -53,7 +64,31 @@ class MessageHandlerFrameChild extends JSWindowActorChild {
|
|||
);
|
||||
}
|
||||
|
||||
_onRegistryEvent(eventName, wrappedEvent) {
|
||||
const { messageHandlerInfo, method, params } = wrappedEvent;
|
||||
const { contextId, sessionId, type } = messageHandlerInfo;
|
||||
|
||||
// TODO: With a single MessageHandlerRegistry per process, we might receive
|
||||
// events intended for other contexts. Consequently we have to filter out
|
||||
// unrelevant events. Once Registry becomes context-specific (Bug 1722659)
|
||||
// this filtering should be removed.
|
||||
if (
|
||||
type === this.type &&
|
||||
contextId === WindowGlobalMessageHandler.getIdFromContext(this.context)
|
||||
) {
|
||||
this.sendAsyncMessage("MessageHandlerFrameChild:messageHandlerEvent", {
|
||||
method,
|
||||
params,
|
||||
sessionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
didDestroy() {
|
||||
MessageHandlerRegistry.contextDestroyed(this.context, this.type);
|
||||
MessageHandlerRegistry.off(
|
||||
"message-handler-registry-event",
|
||||
this._onRegistryEvent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,39 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["MessageHandlerFrameParent"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
MessageHandlerRegistry:
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandlerRegistry.jsm",
|
||||
});
|
||||
|
||||
/**
|
||||
* Parent actor for the MessageHandlerFrame JSWindowActor. The
|
||||
* MessageHandlerFrame actor is used by FrameTransport to communicate between
|
||||
* ROOT MessageHandlers and WINDOW_GLOBAL MessageHandlers.
|
||||
*/
|
||||
class MessageHandlerFrameParent extends JSWindowActorParent {
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "MessageHandlerFrameChild:messageHandlerEvent":
|
||||
const { method, params, sessionId } = message.data;
|
||||
|
||||
const messageHandler = MessageHandlerRegistry.getRootMessageHandler(
|
||||
sessionId
|
||||
);
|
||||
|
||||
// Re-emit the event on the RootMessageHandler.
|
||||
messageHandler.emitMessageHandlerEvent(method, params);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported message:" + message.name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the corresponding MessageHandlerFrameChild actor via a
|
||||
* JSWindowActor query.
|
||||
|
|
|
@ -211,7 +211,13 @@ class WebDriverSession {
|
|||
this._connections.clear();
|
||||
|
||||
// Destroy the dedicated MessageHandler instance if we created one.
|
||||
this._messageHandler?.destroy();
|
||||
if (this._messageHandler) {
|
||||
this._messageHandler.off(
|
||||
"message-handler-event",
|
||||
this._onMessageHandlerEvent
|
||||
);
|
||||
this._messageHandler.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
execute(module, command, params) {
|
||||
|
@ -242,6 +248,11 @@ class WebDriverSession {
|
|||
this.id,
|
||||
RootMessageHandler.type
|
||||
);
|
||||
this._onMessageHandlerEvent = this._onMessageHandlerEvent.bind(this);
|
||||
this._messageHandler.on(
|
||||
"message-handler-event",
|
||||
this._onMessageHandlerEvent
|
||||
);
|
||||
}
|
||||
|
||||
return this._messageHandler;
|
||||
|
@ -296,6 +307,13 @@ class WebDriverSession {
|
|||
this._connections.add(conn);
|
||||
}
|
||||
|
||||
_onMessageHandlerEvent(eventName, messageHandlerEvent) {
|
||||
const { method, params } = messageHandlerEvent;
|
||||
this._connections.forEach(connection =>
|
||||
connection.sendEvent(method, params)
|
||||
);
|
||||
}
|
||||
|
||||
// XPCOM
|
||||
|
||||
get QueryInterface() {
|
||||
|
|
|
@ -93,7 +93,9 @@ class WebDriverBiDiConnection extends WebSocketConnection {
|
|||
* @param {Object} params
|
||||
* A JSON-serializable object, which is the payload of this event.
|
||||
*/
|
||||
sendEvent(method, params) {}
|
||||
sendEvent(method, params) {
|
||||
this.send({ method, params });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the result of a call to a module's method back to the
|
||||
|
|
Загрузка…
Ссылка в новой задаче