1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31/** 32 * @constructor 33 */ 34function InspectorBackendClass() 35{ 36 this._connection = null; 37 this._agentPrototypes = {}; 38 this._dispatcherPrototypes = {}; 39 this._initialized = false; 40 this._enums = {}; 41 this._initProtocolAgentsConstructor(); 42} 43 44InspectorBackendClass.prototype = { 45 46 _initProtocolAgentsConstructor: function() 47 { 48 window.Protocol = {}; 49 50 /** 51 * @constructor 52 * @param {!Object.<string, !Object>} agentsMap 53 */ 54 window.Protocol.Agents = function(agentsMap) { 55 this._agentsMap = agentsMap; 56 }; 57 }, 58 59 /** 60 * @param {string} domain 61 */ 62 _addAgentGetterMethodToProtocolAgentsPrototype: function(domain) 63 { 64 var upperCaseLength = 0; 65 while (upperCaseLength < domain.length && domain[upperCaseLength].toLowerCase() !== domain[upperCaseLength]) 66 ++upperCaseLength; 67 68 var methodName = domain.substr(0, upperCaseLength).toLowerCase() + domain.slice(upperCaseLength) + "Agent"; 69 70 /** 71 * @this {Protocol.Agents} 72 */ 73 function agentGetter() 74 { 75 return this._agentsMap[domain]; 76 } 77 78 window.Protocol.Agents.prototype[methodName] = agentGetter; 79 80 /** 81 * @this {Protocol.Agents} 82 */ 83 function registerDispatcher(dispatcher) 84 { 85 this.registerDispatcher(domain, dispatcher) 86 } 87 88 window.Protocol.Agents.prototype["register" + domain + "Dispatcher"] = registerDispatcher; 89 }, 90 91 /** 92 * @return {!InspectorBackendClass.Connection} 93 */ 94 connection: function() 95 { 96 if (!this._connection) 97 throw "Main connection was not initialized"; 98 return this._connection; 99 }, 100 101 /** 102 * @param {!InspectorBackendClass.MainConnection} connection 103 */ 104 setConnection: function(connection) 105 { 106 this._connection = connection; 107 108 this._connection.registerAgentsOn(window); 109 for (var type in this._enums) { 110 var domainAndMethod = type.split("."); 111 window[domainAndMethod[0] + "Agent"][domainAndMethod[1]] = this._enums[type]; 112 } 113 }, 114 115 /** 116 * @param {string} domain 117 * @return {!InspectorBackendClass.AgentPrototype} 118 */ 119 _agentPrototype: function(domain) 120 { 121 if (!this._agentPrototypes[domain]) { 122 this._agentPrototypes[domain] = new InspectorBackendClass.AgentPrototype(domain); 123 this._addAgentGetterMethodToProtocolAgentsPrototype(domain); 124 } 125 126 return this._agentPrototypes[domain]; 127 }, 128 129 /** 130 * @param {string} domain 131 * @return {!InspectorBackendClass.DispatcherPrototype} 132 */ 133 _dispatcherPrototype: function(domain) 134 { 135 if (!this._dispatcherPrototypes[domain]) 136 this._dispatcherPrototypes[domain] = new InspectorBackendClass.DispatcherPrototype(); 137 return this._dispatcherPrototypes[domain]; 138 }, 139 140 /** 141 * @param {string} method 142 * @param {!Array.<!Object>} signature 143 * @param {!Array.<string>} replyArgs 144 * @param {boolean} hasErrorData 145 */ 146 registerCommand: function(method, signature, replyArgs, hasErrorData) 147 { 148 var domainAndMethod = method.split("."); 149 this._agentPrototype(domainAndMethod[0]).registerCommand(domainAndMethod[1], signature, replyArgs, hasErrorData); 150 this._initialized = true; 151 }, 152 153 /** 154 * @param {string} type 155 * @param {!Object} values 156 */ 157 registerEnum: function(type, values) 158 { 159 this._enums[type] = values; 160 this._initialized = true; 161 }, 162 163 /** 164 * @param {string} eventName 165 * @param {!Object} params 166 */ 167 registerEvent: function(eventName, params) 168 { 169 var domain = eventName.split(".")[0]; 170 this._dispatcherPrototype(domain).registerEvent(eventName, params); 171 this._initialized = true; 172 }, 173 174 /** 175 * @param {string} domain 176 * @param {!Object} dispatcher 177 */ 178 registerDomainDispatcher: function(domain, dispatcher) 179 { 180 this._connection.registerDispatcher(domain, dispatcher); 181 }, 182 183 /** 184 * @param {string} jsonUrl 185 */ 186 loadFromJSONIfNeeded: function(jsonUrl) 187 { 188 if (this._initialized) 189 return; 190 191 var xhr = new XMLHttpRequest(); 192 xhr.open("GET", jsonUrl, false); 193 xhr.send(null); 194 195 var schema = JSON.parse(xhr.responseText); 196 var code = InspectorBackendClass._generateCommands(schema); 197 eval(code); 198 }, 199 200 /** 201 * @param {function(T)} clientCallback 202 * @param {string} errorPrefix 203 * @param {function(new:T,S)=} constructor 204 * @param {T=} defaultValue 205 * @return {function(?string, S)} 206 * @template T,S 207 */ 208 wrapClientCallback: function(clientCallback, errorPrefix, constructor, defaultValue) 209 { 210 /** 211 * @param {?string} error 212 * @param {S} value 213 * @template S 214 */ 215 function callbackWrapper(error, value) 216 { 217 if (error) { 218 console.error(errorPrefix + error); 219 clientCallback(defaultValue); 220 return; 221 } 222 if (constructor) 223 clientCallback(new constructor(value)); 224 else 225 clientCallback(value); 226 } 227 return callbackWrapper; 228 } 229} 230 231/** 232 * @param {*} schema 233 * @return {string} 234 */ 235InspectorBackendClass._generateCommands = function(schema) { 236 var jsTypes = { integer: "number", array: "object" }; 237 var rawTypes = {}; 238 var result = []; 239 240 var domains = schema["domains"] || []; 241 for (var i = 0; i < domains.length; ++i) { 242 var domain = domains[i]; 243 for (var j = 0; domain.types && j < domain.types.length; ++j) { 244 var type = domain.types[j]; 245 rawTypes[domain.domain + "." + type.id] = jsTypes[type.type] || type.type; 246 } 247 } 248 249 function toUpperCase(groupIndex, group0, group1) 250 { 251 return [group0, group1][groupIndex].toUpperCase(); 252 } 253 function generateEnum(enumName, items) 254 { 255 var members = [] 256 for (var m = 0; m < items.length; ++m) { 257 var value = items[m]; 258 var name = value.replace(/-(\w)/g, toUpperCase.bind(null, 1)).toTitleCase(); 259 name = name.replace(/HTML|XML|WML|API/ig, toUpperCase.bind(null, 0)); 260 members.push(name + ": \"" + value +"\""); 261 } 262 return "InspectorBackend.registerEnum(\"" + enumName + "\", {" + members.join(", ") + "});"; 263 } 264 265 for (var i = 0; i < domains.length; ++i) { 266 var domain = domains[i]; 267 268 var types = domain["types"] || []; 269 for (var j = 0; j < types.length; ++j) { 270 var type = types[j]; 271 if ((type["type"] === "string") && type["enum"]) 272 result.push(generateEnum(domain.domain + "." + type.id, type["enum"])); 273 else if (type["type"] === "object") { 274 var properties = type["properties"] || []; 275 for (var k = 0; k < properties.length; ++k) { 276 var property = properties[k]; 277 if ((property["type"] === "string") && property["enum"]) 278 result.push(generateEnum(domain.domain + "." + type.id + property["name"].toTitleCase(), property["enum"])); 279 } 280 } 281 } 282 283 var commands = domain["commands"] || []; 284 for (var j = 0; j < commands.length; ++j) { 285 var command = commands[j]; 286 var parameters = command["parameters"]; 287 var paramsText = []; 288 for (var k = 0; parameters && k < parameters.length; ++k) { 289 var parameter = parameters[k]; 290 291 var type; 292 if (parameter.type) 293 type = jsTypes[parameter.type] || parameter.type; 294 else { 295 var ref = parameter["$ref"]; 296 if (ref.indexOf(".") !== -1) 297 type = rawTypes[ref]; 298 else 299 type = rawTypes[domain.domain + "." + ref]; 300 } 301 302 var text = "{\"name\": \"" + parameter.name + "\", \"type\": \"" + type + "\", \"optional\": " + (parameter.optional ? "true" : "false") + "}"; 303 paramsText.push(text); 304 } 305 306 var returnsText = []; 307 var returns = command["returns"] || []; 308 for (var k = 0; k < returns.length; ++k) { 309 var parameter = returns[k]; 310 returnsText.push("\"" + parameter.name + "\""); 311 } 312 var hasErrorData = String(Boolean(command.error)); 313 result.push("InspectorBackend.registerCommand(\"" + domain.domain + "." + command.name + "\", [" + paramsText.join(", ") + "], [" + returnsText.join(", ") + "], " + hasErrorData + ");"); 314 } 315 316 for (var j = 0; domain.events && j < domain.events.length; ++j) { 317 var event = domain.events[j]; 318 var paramsText = []; 319 for (var k = 0; event.parameters && k < event.parameters.length; ++k) { 320 var parameter = event.parameters[k]; 321 paramsText.push("\"" + parameter.name + "\""); 322 } 323 result.push("InspectorBackend.registerEvent(\"" + domain.domain + "." + event.name + "\", [" + paramsText.join(", ") + "]);"); 324 } 325 326 result.push("InspectorBackend.register" + domain.domain + "Dispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"" + domain.domain + "\");"); 327 } 328 return result.join("\n"); 329} 330 331/** 332 * @constructor 333 * @extends {WebInspector.Object} 334 */ 335InspectorBackendClass.Connection = function() 336{ 337 this._lastMessageId = 1; 338 this._pendingResponsesCount = 0; 339 this._agents = {}; 340 this._dispatchers = {}; 341 this._callbacks = {}; 342 this._initialize(InspectorBackend._agentPrototypes, InspectorBackend._dispatcherPrototypes); 343} 344 345InspectorBackendClass.Connection.Events = { 346 Disconnected: "Disconnected", 347} 348 349InspectorBackendClass.Connection.prototype = { 350 351 /** 352 * @param {!Object.<string, !InspectorBackendClass.AgentPrototype>} agentPrototypes 353 * @param {!Object.<string, !InspectorBackendClass.DispatcherPrototype>} dispatcherPrototypes 354 */ 355 _initialize: function(agentPrototypes, dispatcherPrototypes) 356 { 357 for (var domain in agentPrototypes) { 358 this._agents[domain] = Object.create(agentPrototypes[domain]); 359 this._agents[domain].setConnection(this); 360 } 361 362 for (var domain in dispatcherPrototypes) 363 this._dispatchers[domain] = Object.create(dispatcherPrototypes[domain]) 364 365 }, 366 367 /** 368 * @param {!Object} object 369 */ 370 registerAgentsOn: function(object) 371 { 372 for (var domain in this._agents) 373 object[domain + "Agent"] = this._agents[domain]; 374 }, 375 376 /** 377 * @return {number} 378 */ 379 nextMessageId: function() 380 { 381 return this._lastMessageId++; 382 }, 383 384 /** 385 * @param {string} domain 386 * @return {!InspectorBackendClass.AgentPrototype} 387 */ 388 agent: function(domain) 389 { 390 return this._agents[domain]; 391 }, 392 393 /** 394 * @return {!Object.<string, !Object>} 395 */ 396 agentsMap: function() 397 { 398 return this._agents; 399 }, 400 401 /** 402 * @param {string} domain 403 * @param {string} method 404 * @param {?Object} params 405 * @param {?function(*)} callback 406 * @private 407 */ 408 _wrapCallbackAndSendMessageObject: function(domain, method, params, callback) 409 { 410 var messageObject = {}; 411 412 var messageId = this.nextMessageId(); 413 messageObject.id = messageId; 414 415 messageObject.method = method; 416 if (params) 417 messageObject.params = params; 418 419 var wrappedCallback = this._wrap(callback, domain, method); 420 421 if (InspectorBackendClass.Options.dumpInspectorProtocolMessages) 422 this._dumpProtocolMessage("frontend: " + JSON.stringify(messageObject)); 423 424 this.sendMessage(messageObject); 425 ++this._pendingResponsesCount; 426 this._callbacks[messageId] = wrappedCallback; 427 }, 428 429 /** 430 * @param {?function(*)} callback 431 * @param {string} method 432 * @param {string} domain 433 * @return {!function(*)} 434 */ 435 _wrap: function(callback, domain, method) 436 { 437 if (!callback) 438 callback = function() {}; 439 440 callback.methodName = method; 441 callback.domain = domain; 442 if (InspectorBackendClass.Options.dumpInspectorTimeStats) 443 callback.sendRequestTime = Date.now(); 444 445 return callback; 446 }, 447 448 /** 449 * @param {!Object} messageObject 450 */ 451 sendMessage: function(messageObject) 452 { 453 throw "Not implemented"; 454 }, 455 456 /** 457 * @param {!Object} messageObject 458 */ 459 reportProtocolError: function(messageObject) 460 { 461 console.error("Protocol Error: the message with wrong id. Message = " + JSON.stringify(messageObject)); 462 }, 463 464 /** 465 * @param {!Object|string} message 466 */ 467 dispatch: function(message) 468 { 469 if (InspectorBackendClass.Options.dumpInspectorProtocolMessages) 470 this._dumpProtocolMessage("backend: " + ((typeof message === "string") ? message : JSON.stringify(message))); 471 472 var messageObject = /** @type {!Object} */ ((typeof message === "string") ? JSON.parse(message) : message); 473 474 if ("id" in messageObject) { // just a response for some request 475 476 var callback = this._callbacks[messageObject.id]; 477 if (!callback) { 478 this.reportProtocolError(messageObject); 479 return; 480 } 481 482 var processingStartTime; 483 if (InspectorBackendClass.Options.dumpInspectorTimeStats) 484 processingStartTime = Date.now(); 485 486 this.agent(callback.domain).dispatchResponse(messageObject.id, messageObject, callback.methodName, callback); 487 --this._pendingResponsesCount; 488 delete this._callbacks[messageObject.id]; 489 490 if (InspectorBackendClass.Options.dumpInspectorTimeStats) 491 console.log("time-stats: " + callback.methodName + " = " + (processingStartTime - callback.sendRequestTime) + " + " + (Date.now() - processingStartTime)); 492 493 if (this._scripts && !this._pendingResponsesCount) 494 this.runAfterPendingDispatches(); 495 return; 496 } else { 497 var method = messageObject.method.split("."); 498 var domainName = method[0]; 499 if (!(domainName in this._dispatchers)) { 500 console.error("Protocol Error: the message " + messageObject.method + " is for non-existing domain '" + domainName + "'"); 501 return; 502 } 503 504 this._dispatchers[domainName].dispatch(method[1], messageObject); 505 506 } 507 508 }, 509 510 /** 511 * @param {string} domain 512 * @param {!Object} dispatcher 513 */ 514 registerDispatcher: function(domain, dispatcher) 515 { 516 if (!this._dispatchers[domain]) 517 return; 518 519 this._dispatchers[domain].setDomainDispatcher(dispatcher); 520 }, 521 522 /** 523 * @param {string=} script 524 */ 525 runAfterPendingDispatches: function(script) 526 { 527 if (!this._scripts) 528 this._scripts = []; 529 530 if (script) 531 this._scripts.push(script); 532 533 if (!this._pendingResponsesCount) { 534 var scripts = this._scripts; 535 this._scripts = [] 536 for (var id = 0; id < scripts.length; ++id) 537 scripts[id].call(this); 538 } 539 }, 540 541 /** 542 * @param {string} reason 543 */ 544 fireDisconnected: function(reason) 545 { 546 this.dispatchEventToListeners(InspectorBackendClass.Connection.Events.Disconnected, {reason: reason}); 547 }, 548 549 _dumpProtocolMessage: function(message) 550 { 551 console.log(message); 552 }, 553 554 __proto__: WebInspector.Object.prototype 555 556} 557 558/** 559 * @constructor 560 * @extends {InspectorBackendClass.Connection} 561 * @param {!function(!InspectorBackendClass.Connection)} onConnectionReady 562 */ 563InspectorBackendClass.MainConnection = function(onConnectionReady) 564{ 565 InspectorBackendClass.Connection.call(this); 566 onConnectionReady(this); 567} 568 569InspectorBackendClass.MainConnection.prototype = { 570 571 /** 572 * @param {!Object} messageObject 573 */ 574 sendMessage: function(messageObject) 575 { 576 var message = JSON.stringify(messageObject); 577 InspectorFrontendHost.sendMessageToBackend(message); 578 }, 579 580 __proto__: InspectorBackendClass.Connection.prototype 581} 582 583/** 584 * @constructor 585 * @extends {InspectorBackendClass.Connection} 586 * @param {string} url 587 * @param {!function(!InspectorBackendClass.Connection)} onConnectionReady 588 */ 589InspectorBackendClass.WebSocketConnection = function(url, onConnectionReady) 590{ 591 InspectorBackendClass.Connection.call(this); 592 this._socket = new WebSocket(url); 593 this._socket.onmessage = this._onMessage.bind(this); 594 this._socket.onerror = this._onError.bind(this); 595 this._socket.onopen = onConnectionReady.bind(null, this); 596 this._socket.onclose = this.fireDisconnected.bind(this, "websocket_closed"); 597} 598 599InspectorBackendClass.WebSocketConnection.prototype = { 600 601 /** 602 * @param {!MessageEvent} message 603 */ 604 _onMessage: function(message) 605 { 606 var data = /** @type {string} */ (message.data) 607 this.dispatch(data); 608 }, 609 610 /** 611 * @param {!Event} error 612 */ 613 _onError: function(error) 614 { 615 console.error(error); 616 }, 617 618 /** 619 * @param {!Object} messageObject 620 */ 621 sendMessage: function(messageObject) 622 { 623 var message = JSON.stringify(messageObject); 624 this._socket.send(message); 625 }, 626 627 __proto__: InspectorBackendClass.Connection.prototype 628} 629 630 631/** 632 * @constructor 633 * @extends {InspectorBackendClass.Connection} 634 * @param {!function(!InspectorBackendClass.Connection)} onConnectionReady 635 */ 636InspectorBackendClass.StubConnection = function(onConnectionReady) 637{ 638 InspectorBackendClass.Connection.call(this); 639 onConnectionReady(this); 640} 641 642InspectorBackendClass.StubConnection.prototype = { 643 644 /** 645 * @param {!Object} messageObject 646 */ 647 sendMessage: function(messageObject) 648 { 649 var message = JSON.stringify(messageObject); 650 setTimeout(this._echoResponse.bind(this, messageObject), 0); 651 }, 652 653 /** 654 * @param {!Object} messageObject 655 */ 656 _echoResponse: function(messageObject) 657 { 658 this.dispatch(messageObject) 659 }, 660 661 __proto__: InspectorBackendClass.Connection.prototype 662} 663 664/** 665 * @constructor 666 * @param {string} domain 667 */ 668InspectorBackendClass.AgentPrototype = function(domain) 669{ 670 this._replyArgs = {}; 671 this._hasErrorData = {}; 672 this._domain = domain; 673} 674 675InspectorBackendClass.AgentPrototype.prototype = { 676 677 /** 678 * @param {!InspectorBackendClass.Connection} connection 679 */ 680 setConnection: function(connection) 681 { 682 this._connection = connection; 683 }, 684 685 /** 686 * @param {string} methodName 687 * @param {!Array.<!Object>} signature 688 * @param {!Array.<string>} replyArgs 689 * @param {boolean} hasErrorData 690 */ 691 registerCommand: function(methodName, signature, replyArgs, hasErrorData) 692 { 693 var domainAndMethod = this._domain + "." + methodName; 694 695 /** 696 * @this {InspectorBackendClass.AgentPrototype} 697 */ 698 function sendMessage(vararg) 699 { 700 var params = [domainAndMethod, signature].concat(Array.prototype.slice.call(arguments)); 701 InspectorBackendClass.AgentPrototype.prototype._sendMessageToBackend.apply(this, params); 702 } 703 704 this[methodName] = sendMessage; 705 706 /** 707 * @this {InspectorBackendClass.AgentPrototype} 708 */ 709 function invoke(vararg) 710 { 711 var params = [domainAndMethod].concat(Array.prototype.slice.call(arguments)); 712 InspectorBackendClass.AgentPrototype.prototype._invoke.apply(this, params); 713 } 714 715 this["invoke_" + methodName] = invoke; 716 717 this._replyArgs[domainAndMethod] = replyArgs; 718 if (hasErrorData) 719 this._hasErrorData[domainAndMethod] = true; 720 721 }, 722 723 /** 724 * @param {string} method 725 * @param {!Array.<!Object>} signature 726 * @param {*} vararg 727 * @private 728 */ 729 _sendMessageToBackend: function(method, signature, vararg) 730 { 731 var args = Array.prototype.slice.call(arguments, 2); 732 var callback = (args.length && typeof args[args.length - 1] === "function") ? args.pop() : null; 733 734 var params = {}; 735 var hasParams = false; 736 for (var i = 0; i < signature.length; ++i) { 737 var param = signature[i]; 738 var paramName = param["name"]; 739 var typeName = param["type"]; 740 var optionalFlag = param["optional"]; 741 742 if (!args.length && !optionalFlag) { 743 console.error("Protocol Error: Invalid number of arguments for method '" + method + "' call. It must have the following arguments '" + JSON.stringify(signature) + "'."); 744 return; 745 } 746 747 var value = args.shift(); 748 if (optionalFlag && typeof value === "undefined") { 749 continue; 750 } 751 752 if (typeof value !== typeName) { 753 console.error("Protocol Error: Invalid type of argument '" + paramName + "' for method '" + method + "' call. It must be '" + typeName + "' but it is '" + typeof value + "'."); 754 return; 755 } 756 757 params[paramName] = value; 758 hasParams = true; 759 } 760 761 if (args.length === 1 && !callback && (typeof args[0] !== "undefined")) { 762 console.error("Protocol Error: Optional callback argument for method '" + method + "' call must be a function but its type is '" + typeof args[0] + "'."); 763 return; 764 } 765 766 this._connection._wrapCallbackAndSendMessageObject(this._domain, method, hasParams ? params : null, callback); 767 }, 768 769 /** 770 * @param {string} method 771 * @param {?Object} args 772 * @param {?function(*)} callback 773 */ 774 _invoke: function(method, args, callback) 775 { 776 this._connection._wrapCallbackAndSendMessageObject(this._domain, method, args, callback); 777 }, 778 779 /** 780 * @param {number} messageId 781 * @param {!Object} messageObject 782 * @param {string} methodName 783 * @param {function(!Array.<*>)} callback 784 */ 785 dispatchResponse: function(messageId, messageObject, methodName, callback) 786 { 787 if (messageObject.error && messageObject.error.code !== -32000) 788 console.error("Request with id = " + messageObject.id + " failed. " + JSON.stringify(messageObject.error)); 789 790 var argumentsArray = []; 791 argumentsArray[0] = messageObject.error ? messageObject.error.message: null; 792 793 if (this._hasErrorData[methodName]) 794 argumentsArray[1] = messageObject.error ? messageObject.error.data : null; 795 796 if (messageObject.result) { 797 var paramNames = this._replyArgs[methodName] || []; 798 for (var i = 0; i < paramNames.length; ++i) 799 argumentsArray.push(messageObject.result[paramNames[i]]); 800 } 801 802 callback.apply(null, argumentsArray); 803 } 804} 805 806/** 807 * @constructor 808 */ 809InspectorBackendClass.DispatcherPrototype = function() 810{ 811 this._eventArgs = {}; 812 this._dispatcher = null; 813} 814 815InspectorBackendClass.DispatcherPrototype.prototype = { 816 817 /** 818 * @param {string} eventName 819 * @param {!Object} params 820 */ 821 registerEvent: function(eventName, params) 822 { 823 this._eventArgs[eventName] = params 824 }, 825 826 /** 827 * @param {!Object} dispatcher 828 */ 829 setDomainDispatcher: function(dispatcher) 830 { 831 this._dispatcher = dispatcher; 832 }, 833 834 /** 835 * @param {string} functionName 836 * @param {!Object} messageObject 837 */ 838 dispatch: function(functionName, messageObject) 839 { 840 if (!this._dispatcher) 841 return; 842 843 if (!(functionName in this._dispatcher)) { 844 console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.method + "'"); 845 return; 846 } 847 848 if (!this._eventArgs[messageObject.method]) { 849 console.error("Protocol Error: Attempted to dispatch an unspecified method '" + messageObject.method + "'"); 850 return; 851 } 852 853 var params = []; 854 if (messageObject.params) { 855 var paramNames = this._eventArgs[messageObject.method]; 856 for (var i = 0; i < paramNames.length; ++i) 857 params.push(messageObject.params[paramNames[i]]); 858 } 859 860 var processingStartTime; 861 if (InspectorBackendClass.Options.dumpInspectorTimeStats) 862 processingStartTime = Date.now(); 863 864 this._dispatcher[functionName].apply(this._dispatcher, params); 865 866 if (InspectorBackendClass.Options.dumpInspectorTimeStats) 867 console.log("time-stats: " + messageObject.method + " = " + (Date.now() - processingStartTime)); 868 } 869 870} 871 872InspectorBackendClass.Options = { 873 dumpInspectorTimeStats: false, 874 dumpInspectorProtocolMessages: false 875} 876 877InspectorBackend = new InspectorBackendClass(); 878