diff options
Diffstat (limited to 'devtools/server/actors/director-registry.js')
-rw-r--r-- | devtools/server/actors/director-registry.js | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/devtools/server/actors/director-registry.js b/devtools/server/actors/director-registry.js new file mode 100644 index 000000000..54584bcde --- /dev/null +++ b/devtools/server/actors/director-registry.js @@ -0,0 +1,254 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 protocol = require("devtools/shared/protocol"); + +const {DebuggerServer} = require("devtools/server/main"); + +const {directorRegistrySpec} = require("devtools/shared/specs/director-registry"); + +/** + * Error Messages + */ + +const ERR_DIRECTOR_INSTALL_TWICE = "Trying to install a director-script twice"; +const ERR_DIRECTOR_INSTALL_EMPTY = "Trying to install an empty director-script"; +const ERR_DIRECTOR_UNINSTALL_UNKNOWN = "Trying to uninstall an unkown director-script"; + +const ERR_DIRECTOR_PARENT_UNKNOWN_METHOD = "Unknown parent process method"; +const ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD = "Unexpected call to notImplemented method"; +const ERR_DIRECTOR_CHILD_MULTIPLE_REPLIES = "Unexpected multiple replies to called parent method"; +const ERR_DIRECTOR_CHILD_NO_REPLY = "Unexpected no reply to called parent method"; + +/** + * Director Registry + */ + +// Map of director scripts ids to director script definitions +var gDirectorScripts = Object.create(null); + +const DirectorRegistry = exports.DirectorRegistry = { + /** + * Register a Director Script with the debugger server. + * @param id string + * The ID of a director script. + * @param directorScriptDef object + * The definition of a director script. + */ + install: function (id, scriptDef) { + if (id in gDirectorScripts) { + console.error(ERR_DIRECTOR_INSTALL_TWICE, id); + return false; + } + + if (!scriptDef) { + console.error(ERR_DIRECTOR_INSTALL_EMPTY, id); + return false; + } + + gDirectorScripts[id] = scriptDef; + + return true; + }, + + /** + * Unregister a Director Script with the debugger server. + * @param id string + * The ID of a director script. + */ + uninstall: function (id) { + if (id in gDirectorScripts) { + delete gDirectorScripts[id]; + + return true; + } + + console.error(ERR_DIRECTOR_UNINSTALL_UNKNOWN, id); + + return false; + }, + + /** + * Returns true if a director script id has been registered. + * @param id string + * The ID of a director script. + */ + checkInstalled: function (id) { + return (this.list().indexOf(id) >= 0); + }, + + /** + * Returns a registered director script definition by id. + * @param id string + * The ID of a director script. + */ + get: function (id) { + return gDirectorScripts[id]; + }, + + /** + * Returns an array of registered director script ids. + */ + list: function () { + return Object.keys(gDirectorScripts); + }, + + /** + * Removes all the registered director scripts. + */ + clear: function () { + gDirectorScripts = Object.create(null); + } +}; + +/** + * E10S parent/child setup helpers + */ + +exports.setupParentProcess = function setupParentProcess({ mm, prefix }) { + // listen for director-script requests from the child process + setMessageManager(mm); + + /* parent process helpers */ + + function handleChildRequest(msg) { + switch (msg.json.method) { + case "get": + return DirectorRegistry.get(msg.json.args[0]); + case "list": + return DirectorRegistry.list(); + default: + console.error(ERR_DIRECTOR_PARENT_UNKNOWN_METHOD, msg.json.method); + throw new Error(ERR_DIRECTOR_PARENT_UNKNOWN_METHOD); + } + } + + function setMessageManager(newMM) { + if (mm) { + mm.removeMessageListener("debug:director-registry-request", handleChildRequest); + } + mm = newMM; + if (mm) { + mm.addMessageListener("debug:director-registry-request", handleChildRequest); + } + } + + return { + onBrowserSwap: setMessageManager, + onDisconnected: () => setMessageManager(null), + }; +}; + +/** + * The DirectorRegistry Actor is a global actor which manages install/uninstall of + * director scripts definitions. + */ +const DirectorRegistryActor = exports.DirectorRegistryActor = protocol.ActorClassWithSpec(directorRegistrySpec, { + /* init & destroy methods */ + initialize: function (conn, parentActor) { + protocol.Actor.prototype.initialize.call(this, conn); + this.maybeSetupChildProcess(conn); + }, + destroy: function (conn) { + protocol.Actor.prototype.destroy.call(this, conn); + this.finalize(); + }, + + finalize: function () { + // nothing to cleanup + }, + + maybeSetupChildProcess(conn) { + // skip child setup if this actor module is not running in a child process + if (!DebuggerServer.isInChildProcess) { + return; + } + + const { sendSyncMessage } = conn.parentMessageManager; + + conn.setupInParent({ + module: "devtools/server/actors/director-registry", + setupParent: "setupParentProcess" + }); + + DirectorRegistry.install = notImplemented.bind(null, "install"); + DirectorRegistry.uninstall = notImplemented.bind(null, "uninstall"); + DirectorRegistry.clear = notImplemented.bind(null, "clear"); + + DirectorRegistry.get = callParentProcess.bind(null, "get"); + DirectorRegistry.list = callParentProcess.bind(null, "list"); + + /* child process helpers */ + + function notImplemented(method) { + console.error(ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD, method); + throw Error(ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD); + } + + function callParentProcess(method, ...args) { + var reply = sendSyncMessage("debug:director-registry-request", { + method: method, + args: args + }); + + if (reply.length === 0) { + console.error(ERR_DIRECTOR_CHILD_NO_REPLY); + throw Error(ERR_DIRECTOR_CHILD_NO_REPLY); + } else if (reply.length > 1) { + console.error(ERR_DIRECTOR_CHILD_MULTIPLE_REPLIES); + throw Error(ERR_DIRECTOR_CHILD_MULTIPLE_REPLIES); + } + + return reply[0]; + } + }, + + /** + * Install a new director-script definition. + * + * @param String id + * The director-script definition identifier. + * @param String scriptCode + * The director-script javascript source. + * @param Object scriptOptions + * The director-script option object. + */ + install: function (id, { scriptCode, scriptOptions }) { + // TODO: add more checks on id format? + if (!id || id.length === 0) { + throw Error("director-script id is mandatory"); + } + + if (!scriptCode) { + throw Error("director-script scriptCode is mandatory"); + } + + return DirectorRegistry.install(id, { + scriptId: id, + scriptCode: scriptCode, + scriptOptions: scriptOptions + }); + }, + + /** + * Uninstall a director-script definition. + * + * @param String id + * The identifier of the director-script definition to be removed + */ + uninstall: function (id) { + return DirectorRegistry.uninstall(id); + }, + + /** + * Retrieves the list of installed director-scripts. + */ + list: function () { + return DirectorRegistry.list(); + } +}); |