summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js432
1 files changed, 432 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js b/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
new file mode 100644
index 000000000..7fdc39ceb
--- /dev/null
+++ b/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2013, 2015, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+InspectorBackendClass = class InspectorBackendClass
+{
+ constructor()
+ {
+ this._agents = {};
+
+ this._customTracer = null;
+ this._defaultTracer = new WebInspector.LoggingProtocolTracer;
+ this._activeTracers = [this._defaultTracer];
+
+ this._dumpInspectorTimeStats = false;
+ this._workerSupportedDomains = [];
+
+ let setting = WebInspector.autoLogProtocolMessagesSetting = new WebInspector.Setting("auto-collect-protocol-messages", false);
+ setting.addEventListener(WebInspector.Setting.Event.Changed, this._startOrStopAutomaticTracing.bind(this));
+ this._startOrStopAutomaticTracing();
+
+ this.currentDispatchState = {
+ event: null,
+ request: null,
+ response: null,
+ };
+ }
+
+ // Public
+
+ get workerSupportedDomains() { return this._workerSupportedDomains; }
+
+ // It's still possible to set this flag on InspectorBackend to just
+ // dump protocol traffic as it happens. For more complex uses of
+ // protocol data, install a subclass of WebInspector.ProtocolTracer.
+ set dumpInspectorProtocolMessages(value)
+ {
+ // Implicitly cause automatic logging to start if it's allowed.
+ let setting = WebInspector.autoLogProtocolMessagesSetting;
+ setting.value = value;
+
+ this._defaultTracer.dumpMessagesToConsole = value;
+ }
+
+ get dumpInspectorProtocolMessages()
+ {
+ return WebInspector.autoLogProtocolMessagesSetting.value;
+ }
+
+ set dumpInspectorTimeStats(value)
+ {
+ this._dumpInspectorTimeStats = !!value;
+
+ if (!this.dumpInspectorProtocolMessages)
+ this.dumpInspectorProtocolMessages = true;
+
+ this._defaultTracer.dumpTimingDataToConsole = value;
+ }
+
+ get dumpInspectorTimeStats()
+ {
+ return this._dumpInspectorTimeStats;
+ }
+
+ set customTracer(tracer)
+ {
+ console.assert(!tracer || tracer instanceof WebInspector.ProtocolTracer, tracer);
+ console.assert(!tracer || tracer !== this._defaultTracer, tracer);
+
+ // Bail early if no state change is to be made.
+ if (!tracer && !this._customTracer)
+ return;
+
+ if (tracer === this._customTracer)
+ return;
+
+ if (tracer === this._defaultTracer)
+ return;
+
+ if (this._customTracer)
+ this._customTracer.logFinished();
+
+ this._customTracer = tracer;
+ this._activeTracers = [this._defaultTracer];
+
+ if (this._customTracer) {
+ this._customTracer.logStarted();
+ this._activeTracers.push(this._customTracer);
+ }
+ }
+
+ get activeTracers()
+ {
+ return this._activeTracers;
+ }
+
+ registerCommand(qualifiedName, callSignature, replySignature)
+ {
+ var [domainName, commandName] = qualifiedName.split(".");
+ var agent = this._agentForDomain(domainName);
+ agent.addCommand(InspectorBackend.Command.create(agent, qualifiedName, callSignature, replySignature));
+ }
+
+ registerEnum(qualifiedName, enumValues)
+ {
+ var [domainName, enumName] = qualifiedName.split(".");
+ var agent = this._agentForDomain(domainName);
+ agent.addEnum(enumName, enumValues);
+ }
+
+ registerEvent(qualifiedName, signature)
+ {
+ var [domainName, eventName] = qualifiedName.split(".");
+ var agent = this._agentForDomain(domainName);
+ agent.addEvent(new InspectorBackend.Event(eventName, signature));
+ }
+
+ registerDomainDispatcher(domainName, dispatcher)
+ {
+ var agent = this._agentForDomain(domainName);
+ agent.dispatcher = dispatcher;
+ }
+
+ dispatch(message)
+ {
+ InspectorBackend.mainConnection.dispatch(message);
+ }
+
+ runAfterPendingDispatches(script)
+ {
+ // FIXME: Should this respect pending dispatches in all connections?
+ InspectorBackend.mainConnection.runAfterPendingDispatches(script);
+ }
+
+ activateDomain(domainName, activationDebuggableType)
+ {
+ if (!activationDebuggableType || InspectorFrontendHost.debuggableType() === activationDebuggableType) {
+ var agent = this._agents[domainName];
+ agent.activate();
+ return agent;
+ }
+
+ return null;
+ }
+
+ workerSupportedDomain(domainName)
+ {
+ this._workerSupportedDomains.push(domainName);
+ }
+
+ // Private
+
+ _startOrStopAutomaticTracing()
+ {
+ this._defaultTracer.dumpMessagesToConsole = this.dumpInspectorProtocolMessages;
+ this._defaultTracer.dumpTimingDataToConsole = this.dumpTimingDataToConsole;
+ }
+
+ _agentForDomain(domainName)
+ {
+ if (this._agents[domainName])
+ return this._agents[domainName];
+
+ var agent = new InspectorBackend.Agent(domainName);
+ this._agents[domainName] = agent;
+ return agent;
+ }
+};
+
+InspectorBackend = new InspectorBackendClass;
+
+InspectorBackend.Agent = class InspectorBackendAgent
+{
+ constructor(domainName)
+ {
+ this._domainName = domainName;
+
+ // Default connection is the main connection.
+ this._connection = InspectorBackend.mainConnection;
+ this._dispatcher = null;
+
+ // Agents are always created, but are only useable after they are activated.
+ this._active = false;
+
+ // Commands are stored directly on the Agent instance using their unqualified
+ // method name as the property. Thus, callers can write: FooAgent.methodName().
+ // Enums are stored similarly based on the unqualified type name.
+ this._events = {};
+ }
+
+ // Public
+
+ get domainName()
+ {
+ return this._domainName;
+ }
+
+ get active()
+ {
+ return this._active;
+ }
+
+ get connection()
+ {
+ return this._connection;
+ }
+
+ set connection(connection)
+ {
+ this._connection = connection;
+ }
+
+ get dispatcher()
+ {
+ return this._dispatcher;
+ }
+
+ set dispatcher(value)
+ {
+ this._dispatcher = value;
+ }
+
+ addEnum(enumName, enumValues)
+ {
+ this[enumName] = enumValues;
+ }
+
+ addCommand(command)
+ {
+ this[command.commandName] = command;
+ }
+
+ addEvent(event)
+ {
+ this._events[event.eventName] = event;
+ }
+
+ getEvent(eventName)
+ {
+ return this._events[eventName];
+ }
+
+ hasEvent(eventName)
+ {
+ return eventName in this._events;
+ }
+
+ hasEventParameter(eventName, eventParameterName)
+ {
+ let event = this._events[eventName];
+ return event && event.parameterNames.includes(eventParameterName);
+ }
+
+ activate()
+ {
+ this._active = true;
+ window[this._domainName + "Agent"] = this;
+ }
+
+ dispatchEvent(eventName, eventArguments)
+ {
+ if (!(eventName in this._dispatcher)) {
+ console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + this._domainName + "." + eventName + "'");
+ return false;
+ }
+
+ this._dispatcher[eventName].apply(this._dispatcher, eventArguments);
+ return true;
+ }
+};
+
+// InspectorBackend.Command can't use ES6 classes because of its trampoline nature.
+// But we can use strict mode to get stricter handling of the code inside its functions.
+InspectorBackend.Command = function(agent, qualifiedName, callSignature, replySignature)
+{
+ "use strict";
+
+ this._agent = agent;
+ this._instance = this;
+
+ let [domainName, commandName] = qualifiedName.split(".");
+ this._qualifiedName = qualifiedName;
+ this._commandName = commandName;
+ this._callSignature = callSignature || [];
+ this._replySignature = replySignature || [];
+};
+
+InspectorBackend.Command.create = function(agent, commandName, callSignature, replySignature)
+{
+ "use strict";
+
+ let instance = new InspectorBackend.Command(agent, commandName, callSignature, replySignature);
+
+ function callable() {
+ console.assert(this instanceof InspectorBackend.Agent);
+ return instance._invokeWithArguments.call(instance, this, Array.from(arguments));
+ }
+
+ callable._instance = instance;
+ Object.setPrototypeOf(callable, InspectorBackend.Command.prototype);
+
+ return callable;
+};
+
+// As part of the workaround to make commands callable, these functions use |this._instance|.
+// |this| could refer to the callable trampoline, or the InspectorBackend.Command instance.
+InspectorBackend.Command.prototype = {
+ __proto__: Function.prototype,
+
+ // Public
+
+ get qualifiedName()
+ {
+ return this._instance._qualifiedName;
+ },
+
+ get commandName()
+ {
+ return this._instance._commandName;
+ },
+
+ get callSignature()
+ {
+ return this._instance._callSignature;
+ },
+
+ get replySignature()
+ {
+ return this._instance._replySignature;
+ },
+
+ invoke(commandArguments, callback, agent)
+ {
+ "use strict";
+
+ agent = agent || this._instance._agent;
+
+ if (typeof callback === "function")
+ agent._connection._sendCommandToBackendWithCallback(this._instance, commandArguments, callback);
+ else
+ return agent._connection._sendCommandToBackendExpectingPromise(this._instance, commandArguments);
+ },
+
+ supports(parameterName)
+ {
+ "use strict";
+
+ return this._instance.callSignature.some((parameter) => parameter["name"] === parameterName);
+ },
+
+ // Private
+
+ _invokeWithArguments(agent, commandArguments)
+ {
+ "use strict";
+
+ let instance = this._instance;
+ let callback = typeof commandArguments.lastValue === "function" ? commandArguments.pop() : null;
+
+ function deliverFailure(message) {
+ console.error(`Protocol Error: ${message}`);
+ if (callback)
+ setTimeout(callback.bind(null, message), 0);
+ else
+ return Promise.reject(new Error(message));
+ }
+
+ let parameters = {};
+ for (let parameter of instance.callSignature) {
+ let parameterName = parameter["name"];
+ let typeName = parameter["type"];
+ let optionalFlag = parameter["optional"];
+
+ if (!commandArguments.length && !optionalFlag)
+ return deliverFailure(`Invalid number of arguments for command '${instance.qualifiedName}'.`);
+
+ let value = commandArguments.shift();
+ if (optionalFlag && value === undefined)
+ continue;
+
+ if (typeof value !== typeName)
+ return deliverFailure(`Invalid type of argument '${parameterName}' for command '${instance.qualifiedName}' call. It must be '${typeName}' but it is '${typeof value}'.`);
+
+ parameters[parameterName] = value;
+ }
+
+ if (!callback && commandArguments.length === 1 && commandArguments[0] !== undefined)
+ return deliverFailure(`Protocol Error: Optional callback argument for command '${instance.qualifiedName}' call must be a function but its type is '${typeof commandArguments[0]}'.`);
+
+ if (callback)
+ agent._connection._sendCommandToBackendWithCallback(instance, parameters, callback);
+ else
+ return agent._connection._sendCommandToBackendExpectingPromise(instance, parameters);
+ }
+};
+
+InspectorBackend.Event = class Event
+{
+ constructor(eventName, parameterNames)
+ {
+ this.eventName = eventName;
+ this.parameterNames = parameterNames;
+ }
+};