xpcdemo.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Contains application code for the XPC demo.
  16. * This script is used in both the container page and the iframe.
  17. *
  18. */
  19. goog.provide('xpcdemo');
  20. goog.require('goog.Uri');
  21. goog.require('goog.asserts');
  22. goog.require('goog.dom');
  23. goog.require('goog.dom.TagName');
  24. goog.require('goog.events');
  25. goog.require('goog.events.EventType');
  26. goog.require('goog.html.SafeHtml');
  27. goog.require('goog.json');
  28. goog.require('goog.log');
  29. goog.require('goog.log.Level');
  30. goog.require('goog.net.xpc.CfgFields');
  31. goog.require('goog.net.xpc.CrossPageChannel');
  32. /**
  33. * Global function to kick off initialization in the containing document.
  34. */
  35. goog.global.initOuter = function() {
  36. goog.events.listen(window, 'load', function() { xpcdemo.initOuter(); });
  37. };
  38. /**
  39. * Global function to kick off initialization in the iframe.
  40. */
  41. goog.global.initInner = function() {
  42. goog.events.listen(window, 'load', function() { xpcdemo.initInner(); });
  43. };
  44. /**
  45. * Initializes XPC in the containing page.
  46. */
  47. xpcdemo.initOuter = function() {
  48. // Build the configuration object.
  49. var cfg = {};
  50. var ownUri = new goog.Uri(window.location.href);
  51. var relayUri = ownUri.resolve(new goog.Uri('relay.html'));
  52. var pollUri = ownUri.resolve(new goog.Uri('blank.html'));
  53. // Determine the peer domain. Uses the value of the URI-parameter
  54. // 'peerdomain'. If that parameter is not present, it falls back to
  55. // the own domain so that the demo will work out of the box (but
  56. // communication will of course not cross domain-boundaries). For
  57. // real cross-domain communication, the easiest way is to point two
  58. // different host-names to the same webserver and then hit the
  59. // following URI:
  60. // http://host1.com/path/to/closure/demos/xpc/index.html?peerdomain=host2.com
  61. var peerDomain = ownUri.getParameterValue('peerdomain') || ownUri.getDomain();
  62. cfg[goog.net.xpc.CfgFields.LOCAL_RELAY_URI] = relayUri.toString();
  63. cfg[goog.net.xpc.CfgFields.PEER_RELAY_URI] =
  64. relayUri.setDomain(peerDomain).toString();
  65. cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = pollUri.toString();
  66. cfg[goog.net.xpc.CfgFields.PEER_POLL_URI] =
  67. pollUri.setDomain(peerDomain).toString();
  68. // Force transport to be used if tp-parameter is set.
  69. var tp = ownUri.getParameterValue('tp');
  70. if (tp) {
  71. cfg[goog.net.xpc.CfgFields.TRANSPORT] = parseInt(tp, 10);
  72. }
  73. // Construct the URI of the peer page.
  74. var peerUri =
  75. ownUri.resolve(new goog.Uri('inner.html')).setDomain(peerDomain);
  76. // Passthrough of verbose and compiled flags.
  77. if (goog.isDef(ownUri.getParameterValue('verbose'))) {
  78. peerUri.setParameterValue('verbose', '');
  79. }
  80. if (goog.isDef(ownUri.getParameterValue('compiled'))) {
  81. peerUri.setParameterValue('compiled', '');
  82. }
  83. cfg[goog.net.xpc.CfgFields.PEER_URI] = peerUri;
  84. // Instantiate the channel.
  85. xpcdemo.channel = new goog.net.xpc.CrossPageChannel(cfg);
  86. // Create the peer iframe.
  87. xpcdemo.peerIframe = xpcdemo.channel.createPeerIframe(
  88. goog.asserts.assert(goog.dom.getElement('iframeContainer')));
  89. xpcdemo.initCommon_();
  90. goog.dom.getElement('inactive').style.display = 'none';
  91. goog.dom.getElement('active').style.display = '';
  92. };
  93. /**
  94. * Initialization in the iframe.
  95. */
  96. xpcdemo.initInner = function() {
  97. // Get the channel configuration passed by the containing document.
  98. var cfg = goog.json.parse(
  99. (new goog.Uri(window.location.href)).getParameterValue('xpc'));
  100. xpcdemo.channel = new goog.net.xpc.CrossPageChannel(cfg);
  101. xpcdemo.initCommon_();
  102. };
  103. /**
  104. * Initializes the demo.
  105. * Registers service-handlers and connects the channel.
  106. * @private
  107. */
  108. xpcdemo.initCommon_ = function() {
  109. var xpcLogger = goog.log.getLogger(
  110. 'goog.net.xpc', window.location.href.match(/verbose/) ?
  111. goog.log.Level.ALL :
  112. goog.log.Level.INFO);
  113. goog.log.addHandler(xpcLogger, function(logRecord) {
  114. xpcdemo.log('[XPC] ' + logRecord.getMessage());
  115. });
  116. // Register services.
  117. // The functions will only receive strings but takes an optional third
  118. // parameter that causes the function to receive an Object to cast to the
  119. // expected type, but it would be better to change the API or add
  120. // overload support to the compiler.
  121. xpcdemo.channel.registerService(
  122. 'log',
  123. /** @type {function((!Object|string)): ?} */ (xpcdemo.log));
  124. xpcdemo.channel.registerService(
  125. 'ping',
  126. /** @type {function((!Object|string)): ?} */ (xpcdemo.pingHandler_));
  127. xpcdemo.channel.registerService(
  128. 'events',
  129. /** @type {function((!Object|string)): ?} */ (xpcdemo.eventsMsgHandler_));
  130. // Connect the channel.
  131. xpcdemo.channel.connect(function() {
  132. xpcdemo.channel.send('log', 'Hi from ' + window.location.host);
  133. goog.events.listen(
  134. goog.dom.getElement('clickfwd'), 'click', xpcdemo.mouseEventHandler_);
  135. });
  136. };
  137. /**
  138. * Kills the peer iframe and the disposes the channel.
  139. */
  140. xpcdemo.teardown = function() {
  141. goog.events.unlisten(
  142. goog.dom.getElement('clickfwd'), goog.events.EventType.CLICK,
  143. xpcdemo.mouseEventHandler_);
  144. xpcdemo.channel.dispose();
  145. delete xpcdemo.channel;
  146. goog.dom.removeNode(xpcdemo.peerIframe);
  147. xpcdemo.peerIframe = null;
  148. goog.dom.getElement('inactive').style.display = '';
  149. goog.dom.getElement('active').style.display = 'none';
  150. };
  151. /**
  152. * Logging function. Inserts log-message into element with it id 'console'.
  153. * @param {string} msgString The log-message.
  154. */
  155. xpcdemo.log = function(msgString) {
  156. xpcdemo.consoleElm || (xpcdemo.consoleElm = goog.dom.getElement('console'));
  157. var msgElm = goog.html.SafeHtml.create(
  158. goog.dom.TagName.DIV, {}, goog.html.SafeHtml.htmlEscape(msgString));
  159. xpcdemo.consoleElm.insertBefore(msgElm, xpcdemo.consoleElm.firstChild);
  160. };
  161. /**
  162. * Sends a ping request to the peer.
  163. */
  164. xpcdemo.ping = function() {
  165. // send current time
  166. xpcdemo.channel.send('ping', goog.now() + '');
  167. };
  168. /**
  169. * The handler function for incoming pings (messages sent to the service
  170. * called 'ping');
  171. * @param {string} payload The message payload.
  172. * @private
  173. */
  174. xpcdemo.pingHandler_ = function(payload) {
  175. // is the incoming message a response to a ping we sent?
  176. if (payload.charAt(0) == '#') {
  177. // calculate roundtrip time and log
  178. var dt = goog.now() - parseInt(payload.substring(1), 10);
  179. xpcdemo.log('roundtrip: ' + dt + 'ms');
  180. } else {
  181. // incoming message is a ping initiated from peer
  182. // -> prepend with '#' and send back
  183. xpcdemo.channel.send('ping', '#' + payload);
  184. xpcdemo.log('ping reply sent');
  185. }
  186. };
  187. /**
  188. * Counter for mousemove events.
  189. * @type {number}
  190. * @private
  191. */
  192. xpcdemo.mmCount_ = 0;
  193. /**
  194. * Holds timestamp when the last mousemove rate has been logged.
  195. * @type {number}
  196. * @private
  197. */
  198. xpcdemo.mmLastRateOutput_ = 0;
  199. /**
  200. * Start mousemove event forwarding. Registers a listener on the document which
  201. * sends them over the channel.
  202. */
  203. xpcdemo.startMousemoveForwarding = function() {
  204. goog.events.listen(
  205. document, goog.events.EventType.MOUSEMOVE, xpcdemo.mouseEventHandler_);
  206. xpcdemo.mmLastRateOutput_ = goog.now();
  207. };
  208. /**
  209. * Stop mousemove event forwarding.
  210. */
  211. xpcdemo.stopMousemoveForwarding = function() {
  212. goog.events.unlisten(
  213. document, goog.events.EventType.MOUSEMOVE, xpcdemo.mouseEventHandler_);
  214. };
  215. /**
  216. * Function to be used as handler for mouse-events.
  217. * @param {goog.events.BrowserEvent} e The mouse event.
  218. * @private
  219. */
  220. xpcdemo.mouseEventHandler_ = function(e) {
  221. xpcdemo.channel.send(
  222. 'events', [e.type, e.clientX, e.clientY, goog.now()].join(','));
  223. };
  224. /**
  225. * Handler for the 'events' service.
  226. * @param {string} payload The string returned from the xpcdemo.
  227. * @private
  228. */
  229. xpcdemo.eventsMsgHandler_ = function(payload) {
  230. var now = goog.now();
  231. var args = payload.split(',');
  232. var type = args[0];
  233. var pageX = args[1];
  234. var pageY = args[2];
  235. var time = parseInt(args[3], 10);
  236. var msg = type + ': (' + pageX + ',' + pageY + '), latency: ' + (now - time);
  237. xpcdemo.log(msg);
  238. if (type == goog.events.EventType.MOUSEMOVE) {
  239. xpcdemo.mmCount_++;
  240. var dt = now - xpcdemo.mmLastRateOutput_;
  241. if (dt > 1000) {
  242. msg = 'RATE (mousemove/s): ' + (1000 * xpcdemo.mmCount_ / dt);
  243. xpcdemo.log(msg);
  244. xpcdemo.mmLastRateOutput_ = now;
  245. xpcdemo.mmCount_ = 0;
  246. }
  247. }
  248. };
  249. /**
  250. * Send multiple messages.
  251. * @param {number} n The number of messages to send.
  252. */
  253. xpcdemo.sendN = function(n) {
  254. xpcdemo.count_ || (xpcdemo.count_ = 1);
  255. for (var i = 0; i < n; i++) {
  256. xpcdemo.channel.send('log', '' + xpcdemo.count_++);
  257. }
  258. };