| // Copyright 2015 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| function DebuggerClient() { |
| this.DEBUGGER_DETACHED = 0; |
| this.DEBUGGER_ATTACHING = 1; |
| this.DEBUGGER_ATTACHED = 2; |
| this.DEBUGGER_DISABLED = 3; |
| this.scripts = []; |
| this.attachState = this.DEBUGGER_DETACHED; |
| this.onAttachCallback = this.onAttach.bind(this); |
| this.onEventCallback = this.onEvent.bind(this); |
| this.executionContext = undefined; |
| } |
| |
| // Attaches to the debugger and listens for debug events. |
| // Enables the domains we care about here. |
| DebuggerClient.prototype.attach = function () { |
| if (this.attachState == this.DEBUGGER_DETACHED) { |
| this.attachState = this.DEBUGGER_ATTACHING; |
| printToMessageLog(MessageLog.INTERACTIVE, |
| 'Attempting to attach to debugger...'); |
| this.scripts = []; |
| debugHub.onEvent.addListener(this.onEventCallback); |
| debugHub.attach(this.onAttachCallback); |
| this.sendCommand('Console.enable'); |
| this.sendCommand('Log.enable'); |
| this.sendCommand('Runtime.enable'); |
| } else if (this.attachState == this.DEBUGGER_ATTACHING) { |
| printToMessageLog(MessageLog.INTERACTIVE, |
| 'Still attempting to attach to debugger...'); |
| } |
| } |
| |
| // Local method to list the parsed scripts the client has been notified of |
| // via the |Debugger.scriptParsed| event. Maps the possibly very long script id |
| // from the debug dispatcher to a more human-readable 0-based index. |
| DebuggerClient.prototype.getScripts = function (scriptId) { |
| for (var i in this.scripts) { |
| var index = this.pad(i, 3); |
| var scriptUrl = this.scripts[i].url; |
| printToMessageLog(MessageLog.INTERACTIVE, index + ': ' + scriptUrl); |
| } |
| } |
| |
| //--- Commands. |
| |
| // Each debugger command has an associated callback to get the result. |
| |
| DebuggerClient.prototype.getScriptSource = function (scriptId) { |
| // If the id looks like an index into the local script array, look it up there. |
| if (scriptId >= 0 && scriptId < this.scripts.length) { |
| scriptId = this.scripts[scriptId].scriptId; |
| } |
| |
| var method = 'Debugger.getScriptSource'; |
| var params = { 'scriptId': scriptId.toString() }; |
| var callback = this.getScriptSourceCallback.bind(this); |
| this.sendCommand(method, params, callback); |
| } |
| |
| DebuggerClient.prototype.getScriptSourceCallback = function (result) { |
| var scriptSource = result.scriptSource; |
| var lines = scriptSource.split('\n'); |
| for (var i = 0; i < lines.length; i++) { |
| var index = this.pad(i + 1, 4); |
| printToMessageLog(MessageLog.INFO, index + ': ' + lines[i]); |
| } |
| } |
| |
| DebuggerClient.prototype.evaluate = function (expression, callback) { |
| var method = 'Runtime.evaluate'; |
| var params = {}; |
| params.contextId = this.executionContext; |
| params.expression = expression; |
| params.generatePreview = true; |
| params.includeCommandLineAPI = true; |
| params.objectGroup = 'console'; |
| params.returnByValue = false; |
| this.sendCommand(method, params, callback); |
| } |
| |
| // All debugger commands are routed through this method. Converts the command |
| // parameters into a JSON string to pass to the debug dispatcher. |
| DebuggerClient.prototype.sendCommand = function (method, commandParams, |
| callback) { |
| var jsonParams = JSON.stringify(commandParams); |
| var responseCallback = this.responseCallback.bind(this, method, callback); |
| debugHub.sendCommand(method, jsonParams, responseCallback); |
| } |
| |
| // All command responses are routed through this method. Parses the JSON |
| // response from the debug dispatcher, checks for errors and passes on to the |
| // command-specific callback to handle the result. |
| DebuggerClient.prototype.responseCallback = function (method, callback, |
| responseString) { |
| var response = JSON.parse(responseString); |
| |
| if (response && response.error) { |
| printToMessageLog( |
| MessageLog.ERROR, |
| '[ERROR(' + response.error.code + '):' + method + '] ' + |
| response.error.message); |
| } else if (callback) { |
| if (response) { |
| callback(response.result); |
| } else { |
| callback(null); |
| } |
| } |
| } |
| |
| //-- Events. |
| |
| DebuggerClient.prototype.onAttach = function () { |
| if (debugHub.lastError) { |
| printToMessageLog(MessageLog.WARNING, 'Could not attach to debugger.'); |
| this.attachState = this.DEBUGGER_DISABLED; |
| } else { |
| printToMessageLog(MessageLog.INTERACTIVE, 'Debugger attached.'); |
| this.attachState = this.DEBUGGER_ATTACHED; |
| } |
| } |
| |
| // All events generated by the debug dispatcher are routed through this method. |
| // Parses the JSON string and passes on to the appropriate handler according to |
| // the method name. |
| DebuggerClient.prototype.onEvent = function (method, paramString) { |
| var params = JSON.parse(paramString); |
| if (method == 'Console.messageAdded') { |
| this.onConsoleMessageAdded(params) |
| } else if (method == 'Debugger.scriptParsed') { |
| this.onScriptParsed(params); |
| } else if (method == 'Inspector.detached') { |
| this.onDetached(params); |
| } else if (method == 'Log.browserEntryAdded' || method == 'Log.entryAdded') { |
| this.onLogEntryAdded(params); |
| } else if (method == 'Runtime.consoleAPICalled') { |
| this.onConsoleApiCalled(params); |
| } else if (method == 'Runtime.executionContextCreated') { |
| this.onExecutionContextCreated(params); |
| } |
| } |
| |
| DebuggerClient.prototype.onDetached = function () { |
| printToMessageLog(MessageLog.INTERACTIVE, 'Debugger detached.'); |
| this.attachState = this.DEBUGGER_DETACHED; |
| } |
| |
| DebuggerClient.prototype.onExecutionContextCreated = function (params) { |
| this.executionContext = params.context.id; |
| printToMessageLog(MessageLog.INFO, |
| 'Execution context created: ' + this.executionContext); |
| } |
| |
| DebuggerClient.prototype.onLogEntryAdded = function (params) { |
| printToMessageLog(params.entry.level, params.entry.text); |
| } |
| |
| |
| DebuggerClient.prototype.onConsoleMessageAdded = function (params) { |
| // Translate Console.messageAdded params to Runtime.consoleAPICalled params. |
| var consoleApiParams = { |
| type: params.message.level, |
| args: [{ type: 'string', value: params.message.text }] |
| }; |
| this.onConsoleApiCalled(consoleApiParams); |
| } |
| |
| DebuggerClient.prototype.onConsoleApiCalled = function (params) { |
| var severity = params.type; |
| if (severity === "assert") { |
| severity = MessageLog.ERROR; |
| } else if (severity === "log") { |
| severity = MessageLog.INFO; |
| } |
| |
| var message = ''; |
| if (params.args.length) { |
| var arg = params.args[0]; |
| if (arg.unserializableValue) { |
| message = arg.unserializableValue; |
| } else if (typeof arg.value !== 'object' || arg.value === null) { |
| message = arg.value + ''; |
| } else if (arg.description) { |
| message = arg.description; |
| } |
| } |
| |
| printToMessageLog(MessageLog.CONSOLE + severity, message); |
| } |
| |
| DebuggerClient.prototype.onScriptParsed = function (params) { |
| this.scripts.push(params); |
| } |
| |
| //--- Utils. |
| |
| DebuggerClient.prototype.pad = function (number, minLength) { |
| var result = number.toString(); |
| while (result.length < minLength) { |
| result = ' ' + result; |
| } |
| return result; |
| } |