WorkerManager.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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. * @constructor
  32. * @extends {WebInspector.Object}
  33. */
  34. WebInspector.WorkerManager = function()
  35. {
  36. this._workerIdToWindow = {};
  37. InspectorBackend.registerWorkerDispatcher(new WebInspector.WorkerDispatcher(this));
  38. }
  39. WebInspector.WorkerManager.isWorkerFrontend = function()
  40. {
  41. return !!WebInspector.queryParamsObject["dedicatedWorkerId"] ||
  42. !!WebInspector.queryParamsObject["isSharedWorker"];
  43. }
  44. WebInspector.WorkerManager.isDedicatedWorkerFrontend = function()
  45. {
  46. return !!WebInspector.queryParamsObject["dedicatedWorkerId"];
  47. }
  48. WebInspector.WorkerManager.loaded = function()
  49. {
  50. var workerId = WebInspector.queryParamsObject["dedicatedWorkerId"];
  51. if (workerId)
  52. WebInspector.WorkerManager._initializeDedicatedWorkerFrontend(workerId);
  53. else
  54. WebInspector.workerManager = new WebInspector.WorkerManager();
  55. }
  56. WebInspector.WorkerManager.loadCompleted = function()
  57. {
  58. // Make sure script execution of dedicated worker is resumed and then paused
  59. // on the first script statement in case we autoattached to it.
  60. if (WebInspector.queryParamsObject["workerPaused"]) {
  61. DebuggerAgent.pause();
  62. RuntimeAgent.run(calculateTitle);
  63. } else if (WebInspector.WorkerManager.isWorkerFrontend())
  64. calculateTitle();
  65. function calculateTitle()
  66. {
  67. WebInspector.WorkerManager._calculateWorkerInspectorTitle();
  68. }
  69. if (WebInspector.workerManager)
  70. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, WebInspector.workerManager._mainFrameNavigated, WebInspector.workerManager);
  71. }
  72. WebInspector.WorkerManager._initializeDedicatedWorkerFrontend = function(workerId)
  73. {
  74. function receiveMessage(event)
  75. {
  76. var message = event.data;
  77. InspectorBackend.dispatch(message);
  78. }
  79. window.addEventListener("message", receiveMessage, true);
  80. InspectorBackend.sendMessageObjectToBackend = function(message)
  81. {
  82. window.opener.postMessage({workerId: workerId, command: "sendMessageToBackend", message: message}, "*");
  83. }
  84. }
  85. WebInspector.WorkerManager._calculateWorkerInspectorTitle = function()
  86. {
  87. var expression = "location.href";
  88. if (WebInspector.queryParamsObject["isSharedWorker"])
  89. expression += " + (this.name ? ' (' + this.name + ')' : '')";
  90. RuntimeAgent.evaluate.invoke({expression:expression, doNotPauseOnExceptionsAndMuteConsole:true, returnByValue: true}, evalCallback.bind(this));
  91. /**
  92. * @param {?Protocol.Error} error
  93. * @param {RuntimeAgent.RemoteObject} result
  94. * @param {boolean=} wasThrown
  95. */
  96. function evalCallback(error, result, wasThrown)
  97. {
  98. if (error || wasThrown) {
  99. console.error(error);
  100. return;
  101. }
  102. InspectorFrontendHost.inspectedURLChanged(result.value);
  103. }
  104. }
  105. WebInspector.WorkerManager.Events = {
  106. WorkerAdded: "worker-added",
  107. WorkerRemoved: "worker-removed",
  108. WorkersCleared: "workers-cleared",
  109. }
  110. WebInspector.WorkerManager.prototype = {
  111. _workerCreated: function(workerId, url, inspectorConnected)
  112. {
  113. if (inspectorConnected)
  114. this._openInspectorWindow(workerId, true);
  115. this.dispatchEventToListeners(WebInspector.WorkerManager.Events.WorkerAdded, {workerId: workerId, url: url, inspectorConnected: inspectorConnected});
  116. },
  117. _workerTerminated: function(workerId)
  118. {
  119. this.closeWorkerInspector(workerId);
  120. this.dispatchEventToListeners(WebInspector.WorkerManager.Events.WorkerRemoved, workerId);
  121. },
  122. _sendMessageToWorkerInspector: function(workerId, message)
  123. {
  124. var workerInspectorWindow = this._workerIdToWindow[workerId];
  125. if (workerInspectorWindow)
  126. workerInspectorWindow.postMessage(message, "*");
  127. },
  128. openWorkerInspector: function(workerId)
  129. {
  130. var existingInspector = this._workerIdToWindow[workerId];
  131. if (existingInspector) {
  132. existingInspector.focus();
  133. return;
  134. }
  135. this._openInspectorWindow(workerId, false);
  136. WorkerAgent.connectToWorker(workerId);
  137. },
  138. _openInspectorWindow: function(workerId, workerIsPaused)
  139. {
  140. var search = window.location.search;
  141. var hash = window.location.hash;
  142. var url = window.location.href;
  143. // Make sure hash is in rear
  144. url = url.replace(hash, "");
  145. url += (search ? "&dedicatedWorkerId=" : "?dedicatedWorkerId=") + workerId;
  146. if (workerIsPaused)
  147. url += "&workerPaused=true";
  148. url = url.replace("docked=true&", "");
  149. url += hash;
  150. var width = WebInspector.settings.workerInspectorWidth.get();
  151. var height = WebInspector.settings.workerInspectorHeight.get();
  152. // Set location=0 just to make sure the front-end will be opened in a separate window, not in new tab.
  153. var workerInspectorWindow = window.open(url, undefined, "location=0,width=" + width + ",height=" + height);
  154. workerInspectorWindow.addEventListener("resize", this._onWorkerInspectorResize.bind(this, workerInspectorWindow), false);
  155. this._workerIdToWindow[workerId] = workerInspectorWindow;
  156. workerInspectorWindow.addEventListener("beforeunload", this._workerInspectorClosing.bind(this, workerId), true);
  157. // Listen to beforeunload in detached state and to the InspectorClosing event in case of attached inspector.
  158. window.addEventListener("beforeunload", this._pageInspectorClosing.bind(this), true);
  159. WebInspector.notifications.addEventListener(WebInspector.Events.InspectorClosing, this._pageInspectorClosing, this);
  160. },
  161. closeWorkerInspector: function(workerId)
  162. {
  163. var workerInspectorWindow = this._workerIdToWindow[workerId];
  164. if (workerInspectorWindow)
  165. workerInspectorWindow.close();
  166. },
  167. _mainFrameNavigated: function(event)
  168. {
  169. for (var workerId in this._workerIdToWindow)
  170. this.closeWorkerInspector(workerId);
  171. this.dispatchEventToListeners(WebInspector.WorkerManager.Events.WorkersCleared);
  172. },
  173. _pageInspectorClosing: function()
  174. {
  175. this._ignoreWorkerInspectorClosing = true;
  176. for (var workerId in this._workerIdToWindow) {
  177. this._workerIdToWindow[workerId].close();
  178. WorkerAgent.disconnectFromWorker(parseInt(workerId, 10));
  179. }
  180. },
  181. _onWorkerInspectorResize: function(workerInspectorWindow)
  182. {
  183. var doc = workerInspectorWindow.document;
  184. WebInspector.settings.workerInspectorWidth.set(doc.width);
  185. WebInspector.settings.workerInspectorHeight.set(doc.height);
  186. },
  187. _workerInspectorClosing: function(workerId, event)
  188. {
  189. if (event.target.location.href === "about:blank")
  190. return;
  191. if (this._ignoreWorkerInspectorClosing)
  192. return;
  193. delete this._workerIdToWindow[workerId];
  194. WorkerAgent.disconnectFromWorker(workerId);
  195. },
  196. _disconnectedFromWorker: function()
  197. {
  198. var screen = new WebInspector.WorkerTerminatedScreen();
  199. WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, screen.hide, screen);
  200. screen.showModal();
  201. },
  202. __proto__: WebInspector.Object.prototype
  203. }
  204. /**
  205. * @constructor
  206. * @implements {WorkerAgent.Dispatcher}
  207. */
  208. WebInspector.WorkerDispatcher = function(workerManager)
  209. {
  210. this._workerManager = workerManager;
  211. window.addEventListener("message", this._receiveMessage.bind(this), true);
  212. }
  213. WebInspector.WorkerDispatcher.prototype = {
  214. _receiveMessage: function(event)
  215. {
  216. var workerId = event.data["workerId"];
  217. workerId = parseInt(workerId, 10);
  218. var command = event.data.command;
  219. var message = event.data.message;
  220. if (command == "sendMessageToBackend")
  221. WorkerAgent.sendMessageToWorker(workerId, message);
  222. },
  223. workerCreated: function(workerId, url, inspectorConnected)
  224. {
  225. this._workerManager._workerCreated(workerId, url, inspectorConnected);
  226. },
  227. workerTerminated: function(workerId)
  228. {
  229. this._workerManager._workerTerminated(workerId);
  230. },
  231. dispatchMessageFromWorker: function(workerId, message)
  232. {
  233. this._workerManager._sendMessageToWorkerInspector(workerId, message);
  234. },
  235. disconnectedFromWorker: function()
  236. {
  237. this._workerManager._disconnectedFromWorker();
  238. }
  239. }
  240. /**
  241. * @constructor
  242. * @extends {WebInspector.HelpScreen}
  243. */
  244. WebInspector.WorkerTerminatedScreen = function()
  245. {
  246. WebInspector.HelpScreen.call(this, WebInspector.UIString("Inspected worker terminated"));
  247. var p = this.contentElement.createChild("p");
  248. p.addStyleClass("help-section");
  249. p.textContent = WebInspector.UIString("Inspected worker has terminated. Once it restarts we will attach to it automatically.");
  250. }
  251. WebInspector.WorkerTerminatedScreen.prototype = {
  252. /**
  253. * @override
  254. */
  255. willHide: function()
  256. {
  257. WebInspector.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this.hide, this);
  258. WebInspector.HelpScreen.prototype.willHide.call(this);
  259. },
  260. __proto__: WebInspector.HelpScreen.prototype
  261. }