networktester.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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 Definition of goog.net.NetworkTester.
  16. */
  17. goog.provide('goog.net.NetworkTester');
  18. goog.require('goog.Timer');
  19. goog.require('goog.Uri');
  20. goog.require('goog.log');
  21. /**
  22. * Creates an instance of goog.net.NetworkTester which can be used to test
  23. * for internet connectivity by seeing if an image can be loaded from
  24. * google.com. It can also be tested with other URLs.
  25. * @param {Function} callback Callback that is called when the test completes.
  26. * The callback takes a single boolean parameter. True indicates the URL
  27. * was reachable, false indicates it wasn't.
  28. * @param {Object=} opt_handler Handler object for the callback.
  29. * @param {goog.Uri=} opt_uri URI to use for testing.
  30. * @constructor @struct
  31. * @final
  32. */
  33. goog.net.NetworkTester = function(callback, opt_handler, opt_uri) {
  34. /**
  35. * Callback that is called when the test completes.
  36. * The callback takes a single boolean parameter. True indicates the URL was
  37. * reachable, false indicates it wasn't.
  38. * @type {Function}
  39. * @private
  40. */
  41. this.callback_ = callback;
  42. /**
  43. * Handler object for the callback.
  44. * @type {Object|undefined}
  45. * @private
  46. */
  47. this.handler_ = opt_handler;
  48. if (!opt_uri) {
  49. // set the default URI to be based on the cleardot image at google.com
  50. // We need to add a 'rand' to make sure the response is not fulfilled
  51. // by browser cache. Use protocol-relative URLs to avoid insecure content
  52. // warnings in IE.
  53. opt_uri = new goog.Uri('//www.google.com/images/cleardot.gif');
  54. opt_uri.makeUnique();
  55. }
  56. /**
  57. * Uri to use for test. Defaults to using an image off of google.com
  58. * @type {goog.Uri}
  59. * @private
  60. */
  61. this.uri_ = opt_uri;
  62. };
  63. /**
  64. * Default timeout
  65. * @type {number}
  66. */
  67. goog.net.NetworkTester.DEFAULT_TIMEOUT_MS = 10000;
  68. /**
  69. * Logger object
  70. * @type {goog.log.Logger}
  71. * @private
  72. */
  73. goog.net.NetworkTester.prototype.logger_ =
  74. goog.log.getLogger('goog.net.NetworkTester');
  75. /**
  76. * Timeout for test
  77. * @type {number}
  78. * @private
  79. */
  80. goog.net.NetworkTester.prototype.timeoutMs_ =
  81. goog.net.NetworkTester.DEFAULT_TIMEOUT_MS;
  82. /**
  83. * Whether we've already started running.
  84. * @type {boolean}
  85. * @private
  86. */
  87. goog.net.NetworkTester.prototype.running_ = false;
  88. /**
  89. * Number of retries to attempt
  90. * @type {number}
  91. * @private
  92. */
  93. goog.net.NetworkTester.prototype.retries_ = 0;
  94. /**
  95. * Attempt number we're on
  96. * @type {number}
  97. * @private
  98. */
  99. goog.net.NetworkTester.prototype.attempt_ = 0;
  100. /**
  101. * Pause between retries in milliseconds.
  102. * @type {number}
  103. * @private
  104. */
  105. goog.net.NetworkTester.prototype.pauseBetweenRetriesMs_ = 0;
  106. /**
  107. * Timer for timeouts.
  108. * @type {?number}
  109. * @private
  110. */
  111. goog.net.NetworkTester.prototype.timeoutTimer_ = null;
  112. /**
  113. * Timer for pauses between retries.
  114. * @type {?number}
  115. * @private
  116. */
  117. goog.net.NetworkTester.prototype.pauseTimer_ = null;
  118. /** @private {?Image} */
  119. goog.net.NetworkTester.prototype.image_;
  120. /**
  121. * Returns the timeout in milliseconds.
  122. * @return {number} Timeout in milliseconds.
  123. */
  124. goog.net.NetworkTester.prototype.getTimeout = function() {
  125. return this.timeoutMs_;
  126. };
  127. /**
  128. * Sets the timeout in milliseconds.
  129. * @param {number} timeoutMs Timeout in milliseconds.
  130. */
  131. goog.net.NetworkTester.prototype.setTimeout = function(timeoutMs) {
  132. this.timeoutMs_ = timeoutMs;
  133. };
  134. /**
  135. * Returns the numer of retries to attempt.
  136. * @return {number} Number of retries to attempt.
  137. */
  138. goog.net.NetworkTester.prototype.getNumRetries = function() {
  139. return this.retries_;
  140. };
  141. /**
  142. * Sets the timeout in milliseconds.
  143. * @param {number} retries Number of retries to attempt.
  144. */
  145. goog.net.NetworkTester.prototype.setNumRetries = function(retries) {
  146. this.retries_ = retries;
  147. };
  148. /**
  149. * Returns the pause between retries in milliseconds.
  150. * @return {number} Pause between retries in milliseconds.
  151. */
  152. goog.net.NetworkTester.prototype.getPauseBetweenRetries = function() {
  153. return this.pauseBetweenRetriesMs_;
  154. };
  155. /**
  156. * Sets the pause between retries in milliseconds.
  157. * @param {number} pauseMs Pause between retries in milliseconds.
  158. */
  159. goog.net.NetworkTester.prototype.setPauseBetweenRetries = function(pauseMs) {
  160. this.pauseBetweenRetriesMs_ = pauseMs;
  161. };
  162. /**
  163. * Returns the uri to use for the test.
  164. * @return {goog.Uri} The uri for the test.
  165. */
  166. goog.net.NetworkTester.prototype.getUri = function() {
  167. return this.uri_;
  168. };
  169. /**
  170. * Returns the current attempt count.
  171. * @return {number} The attempt count.
  172. */
  173. goog.net.NetworkTester.prototype.getAttemptCount = function() {
  174. return this.attempt_;
  175. };
  176. /**
  177. * Sets the uri to use for the test.
  178. * @param {goog.Uri} uri The uri for the test.
  179. */
  180. goog.net.NetworkTester.prototype.setUri = function(uri) {
  181. this.uri_ = uri;
  182. };
  183. /**
  184. * Returns whether the tester is currently running.
  185. * @return {boolean} True if it's running, false if it's not running.
  186. */
  187. goog.net.NetworkTester.prototype.isRunning = function() {
  188. return this.running_;
  189. };
  190. /**
  191. * Starts the process of testing the network.
  192. */
  193. goog.net.NetworkTester.prototype.start = function() {
  194. if (this.running_) {
  195. throw Error('NetworkTester.start called when already running');
  196. }
  197. this.running_ = true;
  198. goog.log.info(this.logger_, 'Starting');
  199. this.attempt_ = 0;
  200. this.startNextAttempt_();
  201. };
  202. /**
  203. * Stops the testing of the network. This is a noop if not running.
  204. */
  205. goog.net.NetworkTester.prototype.stop = function() {
  206. this.cleanupCallbacks_();
  207. this.running_ = false;
  208. };
  209. /**
  210. * Starts the next attempt to load an image.
  211. * @private
  212. */
  213. goog.net.NetworkTester.prototype.startNextAttempt_ = function() {
  214. this.attempt_++;
  215. if (goog.net.NetworkTester.getNavigatorOffline_()) {
  216. goog.log.info(this.logger_, 'Browser is set to work offline.');
  217. // Call in a timeout to make async like the rest.
  218. goog.Timer.callOnce(goog.bind(this.onResult, this, false), 0);
  219. } else {
  220. goog.log.info(
  221. this.logger_,
  222. 'Loading image (attempt ' + this.attempt_ + ') at ' + this.uri_);
  223. this.image_ = new Image();
  224. this.image_.onload = goog.bind(this.onImageLoad_, this);
  225. this.image_.onerror = goog.bind(this.onImageError_, this);
  226. this.image_.onabort = goog.bind(this.onImageAbort_, this);
  227. this.timeoutTimer_ =
  228. goog.Timer.callOnce(this.onImageTimeout_, this.timeoutMs_, this);
  229. this.image_.src = String(this.uri_);
  230. }
  231. };
  232. /**
  233. * @return {boolean} Whether navigator.onLine returns false.
  234. * @private
  235. */
  236. goog.net.NetworkTester.getNavigatorOffline_ = function() {
  237. return navigator !== null && 'onLine' in navigator && !navigator.onLine;
  238. };
  239. /**
  240. * Callback for the image successfully loading.
  241. * @private
  242. */
  243. goog.net.NetworkTester.prototype.onImageLoad_ = function() {
  244. goog.log.info(this.logger_, 'Image loaded');
  245. this.onResult(true);
  246. };
  247. /**
  248. * Callback for the image failing to load.
  249. * @private
  250. */
  251. goog.net.NetworkTester.prototype.onImageError_ = function() {
  252. goog.log.info(this.logger_, 'Image load error');
  253. this.onResult(false);
  254. };
  255. /**
  256. * Callback for the image load being aborted.
  257. * @private
  258. */
  259. goog.net.NetworkTester.prototype.onImageAbort_ = function() {
  260. goog.log.info(this.logger_, 'Image load aborted');
  261. this.onResult(false);
  262. };
  263. /**
  264. * Callback for the image load timing out.
  265. * @private
  266. */
  267. goog.net.NetworkTester.prototype.onImageTimeout_ = function() {
  268. goog.log.info(this.logger_, 'Image load timed out');
  269. this.onResult(false);
  270. };
  271. /**
  272. * Handles a successful or failed result.
  273. * @param {boolean} succeeded Whether the image load succeeded.
  274. */
  275. goog.net.NetworkTester.prototype.onResult = function(succeeded) {
  276. this.cleanupCallbacks_();
  277. if (succeeded) {
  278. this.running_ = false;
  279. this.callback_.call(this.handler_, true);
  280. } else {
  281. if (this.attempt_ <= this.retries_) {
  282. if (this.pauseBetweenRetriesMs_) {
  283. this.pauseTimer_ = goog.Timer.callOnce(
  284. this.onPauseFinished_, this.pauseBetweenRetriesMs_, this);
  285. } else {
  286. this.startNextAttempt_();
  287. }
  288. } else {
  289. this.running_ = false;
  290. this.callback_.call(this.handler_, false);
  291. }
  292. }
  293. };
  294. /**
  295. * Callback for the pause between retry timer.
  296. * @private
  297. */
  298. goog.net.NetworkTester.prototype.onPauseFinished_ = function() {
  299. this.pauseTimer_ = null;
  300. this.startNextAttempt_();
  301. };
  302. /**
  303. * Cleans up the handlers and timer associated with the image.
  304. * @private
  305. */
  306. goog.net.NetworkTester.prototype.cleanupCallbacks_ = function() {
  307. // clear handlers to avoid memory leaks
  308. // NOTE(user): Nullified individually to avoid compiler warnings
  309. // (BUG 658126)
  310. if (this.image_) {
  311. this.image_.onload = null;
  312. this.image_.onerror = null;
  313. this.image_.onabort = null;
  314. this.image_ = null;
  315. }
  316. if (this.timeoutTimer_) {
  317. goog.Timer.clear(this.timeoutTimer_);
  318. this.timeoutTimer_ = null;
  319. }
  320. if (this.pauseTimer_) {
  321. goog.Timer.clear(this.pauseTimer_);
  322. this.pauseTimer_ = null;
  323. }
  324. };