diff --git a/devtools.gypi b/devtools.gypi index e0d3abc157..8857ea3bf9 100644 --- a/devtools.gypi +++ b/devtools.gypi @@ -302,6 +302,7 @@ 'front_end/main/renderingOptions.css', 'front_end/main/targetCrashedScreen.css', 'front_end/main/AdvancedApp.js', + 'front_end/main/Connections.js', 'front_end/main/FrontendWebSocketAPI.js', 'front_end/main/Main.js', 'front_end/main/OverlayController.js', diff --git a/front_end/main/Connections.js b/front_end/main/Connections.js new file mode 100644 index 0000000000..01d15bfdde --- /dev/null +++ b/front_end/main/Connections.js @@ -0,0 +1,143 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @constructor + * @extends {InspectorBackendClass.Connection} + */ +WebInspector.MainConnection = function() +{ + InspectorBackendClass.Connection.call(this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.DispatchMessage, this._dispatchMessage, this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.DispatchMessageChunk, this._dispatchMessageChunk, this); +} + +WebInspector.MainConnection.prototype = { + /** + * @override + * @param {!Object} messageObject + */ + sendMessage: function(messageObject) + { + var message = JSON.stringify(messageObject); + InspectorFrontendHost.sendMessageToBackend(message); + }, + + /** + * @param {!WebInspector.Event} event + */ + _dispatchMessage: function(event) + { + this.dispatch(/** @type {string} */ (event.data)); + }, + + /** + * @param {!WebInspector.Event} event + */ + _dispatchMessageChunk: function(event) + { + var messageChunk = /** @type {string} */ (event.data["messageChunk"]); + var messageSize = /** @type {number} */ (event.data["messageSize"]); + if (messageSize) { + this._messageBuffer = ""; + this._messageSize = messageSize; + } + this._messageBuffer += messageChunk; + if (this._messageBuffer.length === this._messageSize) { + this.dispatch(this._messageBuffer); + this._messageBuffer = ""; + this._messageSize = 0; + } + }, + + __proto__: InspectorBackendClass.Connection.prototype +} + +/** + * @constructor + * @extends {InspectorBackendClass.Connection} + * @param {string} url + * @param {function(!InspectorBackendClass.Connection)} onConnectionReady + */ +WebInspector.WebSocketConnection = function(url, onConnectionReady) +{ + InspectorBackendClass.Connection.call(this); + this._socket = new WebSocket(url); + this._socket.onmessage = this._onMessage.bind(this); + this._socket.onerror = this._onError.bind(this); + this._socket.onopen = onConnectionReady.bind(null, this); + this._socket.onclose = this.connectionClosed.bind(this, "websocket_closed"); +} + +/** + * @param {string} url + * @param {function(!InspectorBackendClass.Connection)} onConnectionReady + */ +WebInspector.WebSocketConnection.Create = function(url, onConnectionReady) +{ + new WebInspector.WebSocketConnection(url, onConnectionReady); +} + +WebInspector.WebSocketConnection.prototype = { + + /** + * @param {!MessageEvent} message + */ + _onMessage: function(message) + { + var data = /** @type {string} */ (message.data); + this.dispatch(data); + }, + + /** + * @param {!Event} error + */ + _onError: function(error) + { + console.error(error); + }, + + /** + * @override + * @param {!Object} messageObject + */ + sendMessage: function(messageObject) + { + var message = JSON.stringify(messageObject); + this._socket.send(message); + }, + + __proto__: InspectorBackendClass.Connection.prototype +} + +/** + * @constructor + * @extends {InspectorBackendClass.Connection} + */ +WebInspector.StubConnection = function() +{ + InspectorBackendClass.Connection.call(this); +} + +WebInspector.StubConnection.prototype = { + /** + * @override + * @param {!Object} messageObject + */ + sendMessage: function(messageObject) + { + setTimeout(this._respondWithError.bind(this, messageObject), 0); + }, + + /** + * @param {!Object} messageObject + */ + _respondWithError: function(messageObject) + { + var error = { message: "This is a stub connection, can't dispatch message.", code: InspectorBackendClass.DevToolsStubErrorCode, data: messageObject }; + this.dispatch({ id: messageObject.id, error: error }); + }, + + __proto__: InspectorBackendClass.Connection.prototype +} \ No newline at end of file diff --git a/front_end/main/Main.js b/front_end/main/Main.js index 33c75572b5..70a4f3b590 100644 --- a/front_end/main/Main.js +++ b/front_end/main/Main.js @@ -281,16 +281,16 @@ WebInspector.Main.prototype = { if (Runtime.queryParam("ws")) { var ws = "ws://" + Runtime.queryParam("ws"); - InspectorBackendClass.WebSocketConnection.Create(ws, this._connectionEstablished.bind(this)); + WebInspector.WebSocketConnection.Create(ws, this._connectionEstablished.bind(this)); return; } if (!InspectorFrontendHost.isHostedMode()) { - this._connectionEstablished(new InspectorBackendClass.MainConnection()); + this._connectionEstablished(new WebInspector.MainConnection()); return; } - this._connectionEstablished(new InspectorBackendClass.StubConnection()); + this._connectionEstablished(new WebInspector.StubConnection()); }, /** @@ -780,7 +780,7 @@ WebInspector.Main._addWebSocketTarget = function(ws) { WebInspector.targetManager.createTarget(ws, WebInspector.Target.Type.Page, connection, null); } - new InspectorBackendClass.WebSocketConnection(ws, callback); + new WebInspector.WebSocketConnection(ws, callback); } /** diff --git a/front_end/main/module.json b/front_end/main/module.json index e82f50b5cc..c9ad6d98f7 100644 --- a/front_end/main/module.json +++ b/front_end/main/module.json @@ -326,6 +326,7 @@ "SimpleApp.js", "Tests.js", "OverlayController.js", + "Connections.js", "Main.js" ], "skip_compilation": [ diff --git a/front_end/sdk/InspectorBackend.js b/front_end/sdk/InspectorBackend.js index 4f31f00ca5..30381196fb 100644 --- a/front_end/sdk/InspectorBackend.js +++ b/front_end/sdk/InspectorBackend.js @@ -40,7 +40,7 @@ function InspectorBackendClass() } InspectorBackendClass._DevToolsErrorCode = -32000; -InspectorBackendClass._DevToolsStubErrorCode = -32015; +InspectorBackendClass.DevToolsStubErrorCode = -32015; /** * @param {string} error @@ -52,6 +52,13 @@ InspectorBackendClass.reportProtocolError = function(error, messageObject) } InspectorBackendClass.prototype = { + /** + * @return {boolean} + */ + isInitialized: function() + { + return this._initialized; + }, _initProtocolAgentsConstructor: function() { @@ -162,23 +169,6 @@ InspectorBackendClass.prototype = { this._initialized = true; }, - /** - * @param {string} jsonUrl - */ - loadFromJSONIfNeeded: function(jsonUrl) - { - if (this._initialized) - return; - - var xhr = new XMLHttpRequest(); - xhr.open("GET", jsonUrl, false); - xhr.send(null); - - var schema = JSON.parse(xhr.responseText); - var code = InspectorBackendClass._generateCommands(schema); - eval(code); - }, - /** * @param {function(T)} clientCallback * @param {string} errorPrefix @@ -210,104 +200,6 @@ InspectorBackendClass.prototype = { } } -/** - * @param {*} schema - * @return {string} - */ -InspectorBackendClass._generateCommands = function(schema) { - var jsTypes = { integer: "number", array: "object" }; - var rawTypes = {}; - var result = []; - - var domains = schema["domains"] || []; - for (var i = 0; i < domains.length; ++i) { - var domain = domains[i]; - for (var j = 0; domain.types && j < domain.types.length; ++j) { - var type = domain.types[j]; - rawTypes[domain.domain + "." + type.id] = jsTypes[type.type] || type.type; - } - } - - function toUpperCase(groupIndex, group0, group1) - { - return [group0, group1][groupIndex].toUpperCase(); - } - function generateEnum(enumName, items) - { - var members = []; - for (var m = 0; m < items.length; ++m) { - var value = items[m]; - var name = value.replace(/-(\w)/g, toUpperCase.bind(null, 1)).toTitleCase(); - name = name.replace(/HTML|XML|WML|API/ig, toUpperCase.bind(null, 0)); - members.push(name + ": \"" + value +"\""); - } - return "InspectorBackend.registerEnum(\"" + enumName + "\", {" + members.join(", ") + "});"; - } - - for (var i = 0; i < domains.length; ++i) { - var domain = domains[i]; - - var types = domain["types"] || []; - for (var j = 0; j < types.length; ++j) { - var type = types[j]; - if ((type["type"] === "string") && type["enum"]) - result.push(generateEnum(domain.domain + "." + type.id, type["enum"])); - else if (type["type"] === "object") { - var properties = type["properties"] || []; - for (var k = 0; k < properties.length; ++k) { - var property = properties[k]; - if ((property["type"] === "string") && property["enum"]) - result.push(generateEnum(domain.domain + "." + type.id + property["name"].toTitleCase(), property["enum"])); - } - } - } - - var commands = domain["commands"] || []; - for (var j = 0; j < commands.length; ++j) { - var command = commands[j]; - var parameters = command["parameters"]; - var paramsText = []; - for (var k = 0; parameters && k < parameters.length; ++k) { - var parameter = parameters[k]; - - var type; - if (parameter.type) - type = jsTypes[parameter.type] || parameter.type; - else { - var ref = parameter["$ref"]; - if (ref.indexOf(".") !== -1) - type = rawTypes[ref]; - else - type = rawTypes[domain.domain + "." + ref]; - } - - var text = "{\"name\": \"" + parameter.name + "\", \"type\": \"" + type + "\", \"optional\": " + (parameter.optional ? "true" : "false") + "}"; - paramsText.push(text); - } - - var returnsText = []; - var returns = command["returns"] || []; - for (var k = 0; k < returns.length; ++k) { - var parameter = returns[k]; - returnsText.push("\"" + parameter.name + "\""); - } - var hasErrorData = String(Boolean(command.error)); - result.push("InspectorBackend.registerCommand(\"" + domain.domain + "." + command.name + "\", [" + paramsText.join(", ") + "], [" + returnsText.join(", ") + "], " + hasErrorData + ");"); - } - - for (var j = 0; domain.events && j < domain.events.length; ++j) { - var event = domain.events[j]; - var paramsText = []; - for (var k = 0; event.parameters && k < event.parameters.length; ++k) { - var parameter = event.parameters[k]; - paramsText.push("\"" + parameter.name + "\""); - } - result.push("InspectorBackend.registerEvent(\"" + domain.domain + "." + event.name + "\", [" + paramsText.join(", ") + "]);"); - } - } - return result.join("\n"); -} - /** * @constructor * @extends {WebInspector.Object} @@ -328,7 +220,6 @@ InspectorBackendClass.Connection.Events = { } InspectorBackendClass.Connection.prototype = { - /** * @param {!Object.} agentPrototypes * @param {!Object.} dispatcherPrototypes @@ -342,7 +233,6 @@ InspectorBackendClass.Connection.prototype = { for (var domain in dispatcherPrototypes) this._dispatchers[domain] = Object.create(dispatcherPrototypes[domain]); - }, /** @@ -573,147 +463,6 @@ InspectorBackendClass.Connection.prototype = { } -/** - * @constructor - * @extends {InspectorBackendClass.Connection} - */ -InspectorBackendClass.MainConnection = function() -{ - InspectorBackendClass.Connection.call(this); - InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.DispatchMessage, this._dispatchMessage, this); - InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.DispatchMessageChunk, this._dispatchMessageChunk, this); -} - -InspectorBackendClass.MainConnection.prototype = { - /** - * @override - * @param {!Object} messageObject - */ - sendMessage: function(messageObject) - { - var message = JSON.stringify(messageObject); - InspectorFrontendHost.sendMessageToBackend(message); - }, - - /** - * @param {!WebInspector.Event} event - */ - _dispatchMessage: function(event) - { - this.dispatch(/** @type {string} */ (event.data)); - }, - - /** - * @param {!WebInspector.Event} event - */ - _dispatchMessageChunk: function(event) - { - var messageChunk = /** @type {string} */ (event.data["messageChunk"]); - var messageSize = /** @type {number} */ (event.data["messageSize"]); - if (messageSize) { - this._messageBuffer = ""; - this._messageSize = messageSize; - } - this._messageBuffer += messageChunk; - if (this._messageBuffer.length === this._messageSize) { - this.dispatch(this._messageBuffer); - this._messageBuffer = ""; - this._messageSize = 0; - } - }, - - __proto__: InspectorBackendClass.Connection.prototype -} - -/** - * @constructor - * @extends {InspectorBackendClass.Connection} - * @param {string} url - * @param {function(!InspectorBackendClass.Connection)} onConnectionReady - */ -InspectorBackendClass.WebSocketConnection = function(url, onConnectionReady) -{ - InspectorBackendClass.Connection.call(this); - this._socket = new WebSocket(url); - this._socket.onmessage = this._onMessage.bind(this); - this._socket.onerror = this._onError.bind(this); - this._socket.onopen = onConnectionReady.bind(null, this); - this._socket.onclose = this.connectionClosed.bind(this, "websocket_closed"); -} - -/** - * @param {string} url - * @param {function(!InspectorBackendClass.Connection)} onConnectionReady - */ -InspectorBackendClass.WebSocketConnection.Create = function(url, onConnectionReady) -{ - new InspectorBackendClass.WebSocketConnection(url, onConnectionReady); -} - -InspectorBackendClass.WebSocketConnection.prototype = { - - /** - * @param {!MessageEvent} message - */ - _onMessage: function(message) - { - var data = /** @type {string} */ (message.data); - this.dispatch(data); - }, - - /** - * @param {!Event} error - */ - _onError: function(error) - { - console.error(error); - }, - - /** - * @override - * @param {!Object} messageObject - */ - sendMessage: function(messageObject) - { - var message = JSON.stringify(messageObject); - this._socket.send(message); - }, - - __proto__: InspectorBackendClass.Connection.prototype -} - - -/** - * @constructor - * @extends {InspectorBackendClass.Connection} - */ -InspectorBackendClass.StubConnection = function() -{ - InspectorBackendClass.Connection.call(this); -} - -InspectorBackendClass.StubConnection.prototype = { - /** - * @override - * @param {!Object} messageObject - */ - sendMessage: function(messageObject) - { - setTimeout(this._respondWithError.bind(this, messageObject), 0); - }, - - /** - * @param {!Object} messageObject - */ - _respondWithError: function(messageObject) - { - var error = { message: "This is a stub connection, can't dispatch message.", code: InspectorBackendClass._DevToolsStubErrorCode, data: messageObject }; - this.dispatch({ id: messageObject.id, error: error }); - }, - - __proto__: InspectorBackendClass.Connection.prototype -} - /** * @constructor * @param {string} domain @@ -724,15 +473,6 @@ InspectorBackendClass.AgentPrototype = function(domain) this._hasErrorData = {}; this._domain = domain; this._suppressErrorLogging = false; - this._promisified = domain in InspectorBackendClass.AgentPrototype.PromisifiedDomains; -} - -InspectorBackendClass.AgentPrototype.PromisifiedDomains = { - "Accessibility": true, - "Animation": true, - "CSS": true, - "Emulation": true, - "Profiler": true } InspectorBackendClass.AgentPrototype.prototype = { @@ -754,16 +494,6 @@ InspectorBackendClass.AgentPrototype.prototype = { { var domainAndMethod = this._domain + "." + methodName; - /** - * @param {...*} vararg - * @this {InspectorBackendClass.AgentPrototype} - */ - function sendMessage(vararg) - { - var params = Array.prototype.slice.call(arguments); - InspectorBackendClass.AgentPrototype.prototype._sendMessageToBackend.call(this, domainAndMethod, signature, params); - } - /** * @param {...*} vararg * @this {InspectorBackendClass.AgentPrototype} @@ -772,10 +502,10 @@ InspectorBackendClass.AgentPrototype.prototype = { function sendMessagePromise(vararg) { var params = Array.prototype.slice.call(arguments); - return InspectorBackendClass.AgentPrototype.prototype._sendMessageToBackendPromise.call(this, domainAndMethod, signature, replyArgs, params); + return InspectorBackendClass.AgentPrototype.prototype._sendMessageToBackendPromise.call(this, domainAndMethod, signature, params); } - this[methodName] = this._promisified ? sendMessagePromise : sendMessage; + this[methodName] = sendMessagePromise; /** * @param {...*} vararg @@ -847,33 +577,9 @@ InspectorBackendClass.AgentPrototype.prototype = { * @param {string} method * @param {!Array.} signature * @param {!Array.<*>} args - */ - _sendMessageToBackend: function(method, signature, args) - { - var errorMessage; - /** - * @param {string} message - */ - function onError(message) - { - console.error(message) - errorMessage = message; - } - var callback = (args.length && typeof args.peekLast() === "function") ? args.pop() : null; - var params = this._prepareParameters(method, signature, args, !callback, onError); - if (errorMessage) - return; - this._connection._wrapCallbackAndSendMessageObject(this._domain, method, params, callback); - }, - - /** - * @param {string} method - * @param {!Array.} signature - * @param {!Array.} replyArgs - * @param {!Array.<*>} args * @return {!Promise.<*>} */ - _sendMessageToBackendPromise: function(method, signature, replyArgs, args) + _sendMessageToBackendPromise: function(method, signature, args) { var errorMessage; /** @@ -881,11 +587,11 @@ InspectorBackendClass.AgentPrototype.prototype = { */ function onError(message) { - console.error(message) + console.error(message); errorMessage = message; } var userCallback = (args.length && typeof args.peekLast() === "function") ? args.pop() : null; - var params = this._prepareParameters(method, signature, args, false, onError); + var params = this._prepareParameters(method, signature, args, !userCallback, onError); if (errorMessage) return Promise.reject(new Error(errorMessage)); else @@ -927,9 +633,9 @@ InspectorBackendClass.AgentPrototype.prototype = { */ dispatchResponse: function(messageObject, methodName, callback) { - if (messageObject.error && messageObject.error.code !== InspectorBackendClass._DevToolsErrorCode && messageObject.error.code !== InspectorBackendClass._DevToolsStubErrorCode && !InspectorBackendClass.Options.suppressRequestErrors && !this._suppressErrorLogging) { - var id = InspectorFrontendHost.isUnderTest() ? "##" : messageObject.id; - console.error("Request with id = " + id + " failed. " + JSON.stringify(messageObject.error)); + if (messageObject.error && messageObject.error.code !== InspectorBackendClass._DevToolsErrorCode && messageObject.error.code !== InspectorBackendClass.DevToolsStubErrorCode && !InspectorBackendClass.Options.suppressRequestErrors && !this._suppressErrorLogging) { + var id = InspectorBackendClass.Options.dumpInspectorProtocolMessages ? " with id = " + messageObject.id : ""; + console.error("Request " + methodName + id + " failed. " + JSON.stringify(messageObject.error)); } var argumentsArray = []; diff --git a/front_end/sdk/InspectorBackendHostedMode.js b/front_end/sdk/InspectorBackendHostedMode.js index 2471889f0d..8fe81ef267 100644 --- a/front_end/sdk/InspectorBackendHostedMode.js +++ b/front_end/sdk/InspectorBackendHostedMode.js @@ -3,4 +3,123 @@ // found in the LICENSE file. //This should be executed immediately after InspectorBackend and InspectorBackendCommands -InspectorBackend.loadFromJSONIfNeeded("../protocol.json"); \ No newline at end of file + +WebInspector.InspectorBackendHostedMode = {}; + +/** + * @param {string} jsonUrl + */ +WebInspector.InspectorBackendHostedMode.loadFromJSONIfNeeded = function(jsonUrl) +{ + if (InspectorBackend.isInitialized()) + return; + + var xhr = new XMLHttpRequest(); + xhr.open("GET", jsonUrl, false); + xhr.send(null); + + var schema = JSON.parse(xhr.responseText); + var code = WebInspector.InspectorBackendHostedMode.generateCommands(schema); + eval(code); +} + +/** + * @param {*} schema + * @return {string} + */ +WebInspector.InspectorBackendHostedMode.generateCommands = function(schema) +{ + var jsTypes = { integer: "number", array: "object" }; + var rawTypes = {}; + var result = []; + + var domains = schema["domains"] || []; + for (var i = 0; i < domains.length; ++i) { + var domain = domains[i]; + for (var j = 0; domain.types && j < domain.types.length; ++j) { + var type = domain.types[j]; + rawTypes[domain.domain + "." + type.id] = jsTypes[type.type] || type.type; + } + } + + function toUpperCase(groupIndex, group0, group1) + { + return [group0, group1][groupIndex].toUpperCase(); + } + function generateEnum(enumName, items) + { + var members = []; + for (var m = 0; m < items.length; ++m) { + var value = items[m]; + var name = value.replace(/-(\w)/g, toUpperCase.bind(null, 1)).toTitleCase(); + name = name.replace(/HTML|XML|WML|API/ig, toUpperCase.bind(null, 0)); + members.push(name + ": \"" + value +"\""); + } + return "InspectorBackend.registerEnum(\"" + enumName + "\", {" + members.join(", ") + "});"; + } + + for (var i = 0; i < domains.length; ++i) { + var domain = domains[i]; + + var types = domain["types"] || []; + for (var j = 0; j < types.length; ++j) { + var type = types[j]; + if ((type["type"] === "string") && type["enum"]) + result.push(generateEnum(domain.domain + "." + type.id, type["enum"])); + else if (type["type"] === "object") { + var properties = type["properties"] || []; + for (var k = 0; k < properties.length; ++k) { + var property = properties[k]; + if ((property["type"] === "string") && property["enum"]) + result.push(generateEnum(domain.domain + "." + type.id + property["name"].toTitleCase(), property["enum"])); + } + } + } + + var commands = domain["commands"] || []; + for (var j = 0; j < commands.length; ++j) { + var command = commands[j]; + var parameters = command["parameters"]; + var paramsText = []; + for (var k = 0; parameters && k < parameters.length; ++k) { + var parameter = parameters[k]; + + var type; + if (parameter.type) + type = jsTypes[parameter.type] || parameter.type; + else { + var ref = parameter["$ref"]; + if (ref.indexOf(".") !== -1) + type = rawTypes[ref]; + else + type = rawTypes[domain.domain + "." + ref]; + } + + var text = "{\"name\": \"" + parameter.name + "\", \"type\": \"" + type + "\", \"optional\": " + (parameter.optional ? "true" : "false") + "}"; + paramsText.push(text); + } + + var returnsText = []; + var returns = command["returns"] || []; + for (var k = 0; k < returns.length; ++k) { + var parameter = returns[k]; + returnsText.push("\"" + parameter.name + "\""); + } + var hasErrorData = String(Boolean(command.error)); + result.push("InspectorBackend.registerCommand(\"" + domain.domain + "." + command.name + "\", [" + paramsText.join(", ") + "], [" + returnsText.join(", ") + "], " + hasErrorData + ");"); + } + + for (var j = 0; domain.events && j < domain.events.length; ++j) { + var event = domain.events[j]; + var paramsText = []; + for (var k = 0; event.parameters && k < event.parameters.length; ++k) { + var parameter = event.parameters[k]; + paramsText.push("\"" + parameter.name + "\""); + } + result.push("InspectorBackend.registerEvent(\"" + domain.domain + "." + event.name + "\", [" + paramsText.join(", ") + "]);"); + } + } + return result.join("\n"); +} + +WebInspector.InspectorBackendHostedMode.loadFromJSONIfNeeded("../protocol.json");