| // Copyright 2015 Google Inc. 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.scripts = []; |
| this.attachState = this.DEBUGGER_DETACHED; |
| this.onAttachCallback = this.onAttach.bind(this); |
| this.onEventCallback = this.onEvent.bind(this); |
| this.executionContext = 0; |
| } |
| |
| // 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.debugger.onEvent.addListener(this.onEventCallback); |
| debugHub.debugger.attach(this.onAttachCallback); |
| this.sendCommand('Console.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 notifed of |
| // via the |Debugger.scriptParsed| event. Maps the possibly very long script id |
| // from the debug server 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) { |
| var callback = this.evaluateCallback.bind(this); |
| 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); |
| } |
| |
| DebuggerClient.prototype.evaluateCallback = function(result) { |
| if (result.wasThrown) { |
| printToMessageLog(messageLog.ERROR, |
| 'Uncaught ' + result.result.description); |
| } else if (result.result.preview) { |
| printToMessageLog(messageLog.INFO, result.result.preview.description); |
| if (result.result.preview.properties) { |
| for (var i = 0; i < result.result.preview.properties.length; ++i) { |
| var property = result.result.preview.properties[i]; |
| printToMessageLog(messageLog.INFO, |
| ' ' + property.name + ': ' + property.value); |
| } |
| } |
| if (result.result.preview.overflow) { |
| printToMessageLog(messageLog.INFO, ' ...'); |
| } |
| } else if (result.result.description) { |
| printToMessageLog(messageLog.INFO, result.result.description); |
| } |
| printToMessageLog(messageLog.INFO, ''); |
| } |
| |
| // All debugger commands are routed through this method. Converts the command |
| // parameters into a JSON string to pass to the debug server. |
| DebuggerClient.prototype.sendCommand = function(method, commandParams, |
| callback) { |
| var jsonParams = JSON.stringify(commandParams); |
| var commandCallback = this.commandCallback.bind(this, callback); |
| debugHub.debugger.sendCommand(method, jsonParams, commandCallback); |
| } |
| |
| // All command callbacks are routed through this method. Parses the JSON |
| // response from the debug server, checks for errors and passes on to the |
| // command-specific callback to handle the result. |
| DebuggerClient.prototype.commandCallback = function(callback, responseString) { |
| var response = JSON.parse(responseString); |
| |
| if (response && response.error) { |
| printToMessageLog(messageLog.ERROR, 'Error: ' + response.error.message); |
| } else if (callback) { |
| if (response) { |
| callback(response.result); |
| } else { |
| callback(null); |
| } |
| } |
| } |
| |
| //-- Events. |
| |
| DebuggerClient.prototype.onAttach = function() { |
| if (debugHub.debugger.lastError) { |
| printToMessageLog(messageLog.WARNING, 'Could not attach to debugger.'); |
| this.attachState = this.DEBUGGER_DETACHED; |
| } else { |
| printToMessageLog(messageLog.INTERACTIVE, 'Debugger attached.'); |
| this.attachState = this.DEBUGGER_ATTACHED; |
| } |
| } |
| |
| // All events generated by the debug server 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 == 'Debugger.scriptParsed') { |
| this.onScriptParsed(params); |
| } else if (method == 'Inspector.detached') { |
| this.onDetached(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.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; |
| } |