PageRenderTime 61ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/socket.io.js

https://bitbucket.org/SunilMohan/gevent-socketio
JavaScript | 3704 lines | 2787 code | 323 blank | 594 comment | 213 complexity | 68ab83f032595ae63f738cce3c255bf5 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*! Socket.IO.js build:0.8.2, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
  2. /**
  3. * socket.io
  4. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  5. * MIT Licensed
  6. */
  7. (function (exports) {
  8. /**
  9. * IO namespace.
  10. *
  11. * @namespace
  12. */
  13. var io = exports;
  14. /**
  15. * Socket.IO version
  16. *
  17. * @api public
  18. */
  19. io.version = '0.8.2';
  20. /**
  21. * Protocol implemented.
  22. *
  23. * @api public
  24. */
  25. io.protocol = 1;
  26. /**
  27. * Available transports, these will be populated with the available transports
  28. *
  29. * @api public
  30. */
  31. io.transports = [];
  32. /**
  33. * Keep track of jsonp callbacks.
  34. *
  35. * @api private
  36. */
  37. io.j = [];
  38. /**
  39. * Keep track of our io.Sockets
  40. *
  41. * @api private
  42. */
  43. io.sockets = {};
  44. /**
  45. * Manages connections to hosts.
  46. *
  47. * @param {String} uri
  48. * @Param {Boolean} force creation of new socket (defaults to false)
  49. * @api public
  50. */
  51. io.connect = function (host, details) {
  52. var uri = io.util.parseUri(host)
  53. , uuri
  54. , socket;
  55. if ('undefined' != typeof document) {
  56. uri.protocol = uri.protocol || document.location.protocol.slice(0, -1);
  57. uri.host = uri.host || document.domain;
  58. uri.port = uri.port || document.location.port;
  59. }
  60. uuri = io.util.uniqueUri(uri);
  61. var options = {
  62. host: uri.host
  63. , secure: 'https' == uri.protocol
  64. , port: uri.port || ('https' == uri.protocol ? 443 : 80)
  65. , query: uri.query || ''
  66. };
  67. io.util.merge(options, details);
  68. if (options['force new connection'] || !io.sockets[uuri]) {
  69. socket = new io.Socket(options);
  70. }
  71. if (!options['force new connection'] && socket) {
  72. io.sockets[uuri] = socket;
  73. }
  74. socket = socket || io.sockets[uuri];
  75. // if path is different from '' or /
  76. return socket.of(uri.path.length > 1 ? uri.path : '');
  77. };
  78. })('object' === typeof module ? module.exports : (window.io = {}));
  79. /**
  80. * socket.io
  81. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  82. * MIT Licensed
  83. */
  84. (function (exports, global) {
  85. /**
  86. * Utilities namespace.
  87. *
  88. * @namespace
  89. */
  90. var util = exports.util = {};
  91. /**
  92. * Parses an URI
  93. *
  94. * @author Steven Levithan <stevenlevithan.com> (MIT license)
  95. * @api public
  96. */
  97. var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
  98. var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
  99. 'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
  100. 'anchor'];
  101. util.parseUri = function (str) {
  102. var m = re.exec(str || '')
  103. , uri = {}
  104. , i = 14;
  105. while (i--) {
  106. uri[parts[i]] = m[i] || '';
  107. }
  108. return uri;
  109. };
  110. /**
  111. * Produces a unique url that identifies a Socket.IO connection.
  112. *
  113. * @param {Object} uri
  114. * @api public
  115. */
  116. util.uniqueUri = function (uri) {
  117. var protocol = uri.protocol
  118. , host = uri.host
  119. , port = uri.port;
  120. if ('document' in global) {
  121. host = host || document.domain;
  122. port = port || (protocol == 'https'
  123. && document.location.protocol !== 'https:' ? 443 : document.location.port);
  124. } else {
  125. host = host || 'localhost';
  126. if (!port && protocol == 'https') {
  127. port = 443;
  128. }
  129. }
  130. return (protocol || 'http') + '://' + host + ':' + (port || 80);
  131. };
  132. /**
  133. * Mergest 2 query strings in to once unique query string
  134. *
  135. * @param {String} base
  136. * @param {String} addition
  137. * @api public
  138. */
  139. util.query = function (base, addition) {
  140. var query = util.chunkQuery(base || '')
  141. , components = [];
  142. util.merge(query, util.chunkQuery(addition || ''));
  143. for (var part in query) {
  144. if (query.hasOwnProperty(part)) {
  145. components.push(part + '=' + query[part]);
  146. }
  147. }
  148. return components.length ? '?' + components.join('&') : '';
  149. };
  150. /**
  151. * Transforms a querystring in to an object
  152. *
  153. * @param {String} qs
  154. * @api public
  155. */
  156. util.chunkQuery = function (qs) {
  157. var query = {}
  158. , params = qs.split('&')
  159. , i = 0
  160. , l = params.length
  161. , kv;
  162. for (; i < l; ++i) {
  163. kv = params[i].split('=');
  164. if (kv[0]) {
  165. query[kv[0]] = decodeURIComponent(kv[1]);
  166. }
  167. }
  168. return query;
  169. };
  170. /**
  171. * Executes the given function when the page is loaded.
  172. *
  173. * io.util.load(function () { console.log('page loaded'); });
  174. *
  175. * @param {Function} fn
  176. * @api public
  177. */
  178. var pageLoaded = false;
  179. util.load = function (fn) {
  180. if ('document' in global && document.readyState === 'complete' || pageLoaded) {
  181. return fn();
  182. }
  183. util.on(global, 'load', fn, false);
  184. };
  185. /**
  186. * Adds an event.
  187. *
  188. * @api private
  189. */
  190. util.on = function (element, event, fn, capture) {
  191. if (element.attachEvent) {
  192. element.attachEvent('on' + event, fn);
  193. } else if (element.addEventListener) {
  194. element.addEventListener(event, fn, capture);
  195. }
  196. };
  197. /**
  198. * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
  199. *
  200. * @param {Boolean} [xdomain] Create a request that can be used cross domain.
  201. * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
  202. * @api private
  203. */
  204. util.request = function (xdomain) {
  205. if ('undefined' != typeof window) {
  206. if (xdomain && window.XDomainRequest) {
  207. return new XDomainRequest();
  208. }
  209. if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
  210. return new XMLHttpRequest();
  211. }
  212. if (!xdomain) {
  213. try {
  214. return new window.ActiveXObject('Microsoft.XMLHTTP');
  215. } catch(e) { }
  216. }
  217. }
  218. return null;
  219. };
  220. /**
  221. * XHR based transport constructor.
  222. *
  223. * @constructor
  224. * @api public
  225. */
  226. /**
  227. * Change the internal pageLoaded value.
  228. */
  229. if ('undefined' != typeof window) {
  230. util.load(function () {
  231. pageLoaded = true;
  232. });
  233. }
  234. /**
  235. * Defers a function to ensure a spinner is not displayed by the browser
  236. *
  237. * @param {Function} fn
  238. * @api public
  239. */
  240. util.defer = function (fn) {
  241. if (!util.ua.webkit) {
  242. return fn();
  243. }
  244. util.load(function () {
  245. setTimeout(fn, 100);
  246. });
  247. };
  248. /**
  249. * Merges two objects.
  250. *
  251. * @api public
  252. */
  253. util.merge = function merge (target, additional, deep, lastseen) {
  254. var seen = lastseen || []
  255. , depth = typeof deep == 'undefined' ? 2 : deep
  256. , prop;
  257. for (prop in additional) {
  258. if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
  259. if (typeof target[prop] !== 'object' || !depth) {
  260. target[prop] = additional[prop];
  261. seen.push(additional[prop]);
  262. } else {
  263. util.merge(target[prop], additional[prop], depth - 1, seen);
  264. }
  265. }
  266. }
  267. return target;
  268. };
  269. /**
  270. * Merges prototypes from objects
  271. *
  272. * @api public
  273. */
  274. util.mixin = function (ctor, ctor2) {
  275. util.merge(ctor.prototype, ctor2.prototype);
  276. };
  277. /**
  278. * Shortcut for prototypical and static inheritance.
  279. *
  280. * @api private
  281. */
  282. util.inherit = function (ctor, ctor2) {
  283. function f() {};
  284. f.prototype = ctor2.prototype;
  285. ctor.prototype = new f;
  286. };
  287. /**
  288. * Checks if the given object is an Array.
  289. *
  290. * io.util.isArray([]); // true
  291. * io.util.isArray({}); // false
  292. *
  293. * @param Object obj
  294. * @api public
  295. */
  296. util.isArray = Array.isArray || function (obj) {
  297. return Object.prototype.toString.call(obj) === '[object Array]';
  298. };
  299. /**
  300. * Intersects values of two arrays into a third
  301. *
  302. * @api public
  303. */
  304. util.intersect = function (arr, arr2) {
  305. var ret = []
  306. , longest = arr.length > arr2.length ? arr : arr2
  307. , shortest = arr.length > arr2.length ? arr2 : arr;
  308. for (var i = 0, l = shortest.length; i < l; i++) {
  309. if (~util.indexOf(longest, shortest[i]))
  310. ret.push(shortest[i]);
  311. }
  312. return ret;
  313. }
  314. /**
  315. * Array indexOf compatibility.
  316. *
  317. * @see bit.ly/a5Dxa2
  318. * @api public
  319. */
  320. util.indexOf = function (arr, o, i) {
  321. if (Array.prototype.indexOf) {
  322. return Array.prototype.indexOf.call(arr, o, i);
  323. }
  324. for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
  325. i < j && arr[i] !== o; i++);
  326. return j <= i ? -1 : i;
  327. };
  328. /**
  329. * Converts enumerables to array.
  330. *
  331. * @api public
  332. */
  333. util.toArray = function (enu) {
  334. var arr = [];
  335. for (var i = 0, l = enu.length; i < l; i++)
  336. arr.push(enu[i]);
  337. return arr;
  338. };
  339. /**
  340. * UA / engines detection namespace.
  341. *
  342. * @namespace
  343. */
  344. util.ua = {};
  345. /**
  346. * Whether the UA supports CORS for XHR.
  347. *
  348. * @api public
  349. */
  350. util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest &&
  351. (function () {
  352. try {
  353. var a = new XMLHttpRequest();
  354. } catch (e) {
  355. return false;
  356. }
  357. return a.withCredentials != undefined;
  358. })();
  359. /**
  360. * Detect webkit.
  361. *
  362. * @api public
  363. */
  364. util.ua.webkit = 'undefined' != typeof navigator
  365. && /webkit/i.test(navigator.userAgent);
  366. })(
  367. 'undefined' != typeof window ? io : module.exports
  368. , this
  369. );
  370. /**
  371. * socket.io
  372. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  373. * MIT Licensed
  374. */
  375. (function (exports, io) {
  376. /**
  377. * Expose constructor.
  378. */
  379. exports.EventEmitter = EventEmitter;
  380. /**
  381. * Event emitter constructor.
  382. *
  383. * @api public.
  384. */
  385. function EventEmitter () {};
  386. /**
  387. * Adds a listener
  388. *
  389. * @api public
  390. */
  391. EventEmitter.prototype.on = function (name, fn) {
  392. if (!this.$events) {
  393. this.$events = {};
  394. }
  395. if (!this.$events[name]) {
  396. this.$events[name] = fn;
  397. } else if (io.util.isArray(this.$events[name])) {
  398. this.$events[name].push(fn);
  399. } else {
  400. this.$events[name] = [this.$events[name], fn];
  401. }
  402. return this;
  403. };
  404. EventEmitter.prototype.addListener = EventEmitter.prototype.on;
  405. /**
  406. * Adds a volatile listener.
  407. *
  408. * @api public
  409. */
  410. EventEmitter.prototype.once = function (name, fn) {
  411. var self = this;
  412. function on () {
  413. self.removeListener(name, on);
  414. fn.apply(this, arguments);
  415. };
  416. on.listener = fn;
  417. this.on(name, on);
  418. return this;
  419. };
  420. /**
  421. * Removes a listener.
  422. *
  423. * @api public
  424. */
  425. EventEmitter.prototype.removeListener = function (name, fn) {
  426. if (this.$events && this.$events[name]) {
  427. var list = this.$events[name];
  428. if (io.util.isArray(list)) {
  429. var pos = -1;
  430. for (var i = 0, l = list.length; i < l; i++) {
  431. if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
  432. pos = i;
  433. break;
  434. }
  435. }
  436. if (pos < 0) {
  437. return this;
  438. }
  439. list.splice(pos, 1);
  440. if (!list.length) {
  441. delete this.$events[name];
  442. }
  443. } else if (list === fn || (list.listener && list.listener === fn)) {
  444. delete this.$events[name];
  445. }
  446. }
  447. return this;
  448. };
  449. /**
  450. * Removes all listeners for an event.
  451. *
  452. * @api public
  453. */
  454. EventEmitter.prototype.removeAllListeners = function (name) {
  455. // TODO: enable this when node 0.5 is stable
  456. //if (name === undefined) {
  457. //this.$events = {};
  458. //return this;
  459. //}
  460. if (this.$events && this.$events[name]) {
  461. this.$events[name] = null;
  462. }
  463. return this;
  464. };
  465. /**
  466. * Gets all listeners for a certain event.
  467. *
  468. * @api publci
  469. */
  470. EventEmitter.prototype.listeners = function (name) {
  471. if (!this.$events) {
  472. this.$events = {};
  473. }
  474. if (!this.$events[name]) {
  475. this.$events[name] = [];
  476. }
  477. if (!io.util.isArray(this.$events[name])) {
  478. this.$events[name] = [this.$events[name]];
  479. }
  480. return this.$events[name];
  481. };
  482. /**
  483. * Emits an event.
  484. *
  485. * @api public
  486. */
  487. EventEmitter.prototype.emit = function (name) {
  488. if (!this.$events) {
  489. return false;
  490. }
  491. var handler = this.$events[name];
  492. if (!handler) {
  493. return false;
  494. }
  495. var args = Array.prototype.slice.call(arguments, 1);
  496. if ('function' == typeof handler) {
  497. handler.apply(this, args);
  498. } else if (io.util.isArray(handler)) {
  499. var listeners = handler.slice();
  500. for (var i = 0, l = listeners.length; i < l; i++) {
  501. listeners[i].apply(this, args);
  502. }
  503. } else {
  504. return false;
  505. }
  506. return true;
  507. };
  508. })(
  509. 'undefined' != typeof io ? io : module.exports
  510. , 'undefined' != typeof io ? io : module.parent.exports
  511. );
  512. /**
  513. * socket.io
  514. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  515. * MIT Licensed
  516. */
  517. /**
  518. * Based on JSON2 (http://www.JSON.org/js.html).
  519. */
  520. (function (exports, nativeJSON) {
  521. "use strict";
  522. // use native JSON if it's available
  523. if (nativeJSON && nativeJSON.parse){
  524. return exports.JSON = {
  525. parse: nativeJSON.parse
  526. , stringify: nativeJSON.stringify
  527. }
  528. }
  529. var JSON = exports.JSON = {};
  530. function f(n) {
  531. // Format integers to have at least two digits.
  532. return n < 10 ? '0' + n : n;
  533. }
  534. function date(d, key) {
  535. return isFinite(d.valueOf()) ?
  536. d.getUTCFullYear() + '-' +
  537. f(d.getUTCMonth() + 1) + '-' +
  538. f(d.getUTCDate()) + 'T' +
  539. f(d.getUTCHours()) + ':' +
  540. f(d.getUTCMinutes()) + ':' +
  541. f(d.getUTCSeconds()) + 'Z' : null;
  542. };
  543. var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  544. escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  545. gap,
  546. indent,
  547. meta = { // table of character substitutions
  548. '\b': '\\b',
  549. '\t': '\\t',
  550. '\n': '\\n',
  551. '\f': '\\f',
  552. '\r': '\\r',
  553. '"' : '\\"',
  554. '\\': '\\\\'
  555. },
  556. rep;
  557. function quote(string) {
  558. // If the string contains no control characters, no quote characters, and no
  559. // backslash characters, then we can safely slap some quotes around it.
  560. // Otherwise we must also replace the offending characters with safe escape
  561. // sequences.
  562. escapable.lastIndex = 0;
  563. return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
  564. var c = meta[a];
  565. return typeof c === 'string' ? c :
  566. '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  567. }) + '"' : '"' + string + '"';
  568. }
  569. function str(key, holder) {
  570. // Produce a string from holder[key].
  571. var i, // The loop counter.
  572. k, // The member key.
  573. v, // The member value.
  574. length,
  575. mind = gap,
  576. partial,
  577. value = holder[key];
  578. // If the value has a toJSON method, call it to obtain a replacement value.
  579. if (value instanceof Date) {
  580. value = date(key);
  581. }
  582. // If we were called with a replacer function, then call the replacer to
  583. // obtain a replacement value.
  584. if (typeof rep === 'function') {
  585. value = rep.call(holder, key, value);
  586. }
  587. // What happens next depends on the value's type.
  588. switch (typeof value) {
  589. case 'string':
  590. return quote(value);
  591. case 'number':
  592. // JSON numbers must be finite. Encode non-finite numbers as null.
  593. return isFinite(value) ? String(value) : 'null';
  594. case 'boolean':
  595. case 'null':
  596. // If the value is a boolean or null, convert it to a string. Note:
  597. // typeof null does not produce 'null'. The case is included here in
  598. // the remote chance that this gets fixed someday.
  599. return String(value);
  600. // If the type is 'object', we might be dealing with an object or an array or
  601. // null.
  602. case 'object':
  603. // Due to a specification blunder in ECMAScript, typeof null is 'object',
  604. // so watch out for that case.
  605. if (!value) {
  606. return 'null';
  607. }
  608. // Make an array to hold the partial results of stringifying this object value.
  609. gap += indent;
  610. partial = [];
  611. // Is the value an array?
  612. if (Object.prototype.toString.apply(value) === '[object Array]') {
  613. // The value is an array. Stringify every element. Use null as a placeholder
  614. // for non-JSON values.
  615. length = value.length;
  616. for (i = 0; i < length; i += 1) {
  617. partial[i] = str(i, value) || 'null';
  618. }
  619. // Join all of the elements together, separated with commas, and wrap them in
  620. // brackets.
  621. v = partial.length === 0 ? '[]' : gap ?
  622. '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
  623. '[' + partial.join(',') + ']';
  624. gap = mind;
  625. return v;
  626. }
  627. // If the replacer is an array, use it to select the members to be stringified.
  628. if (rep && typeof rep === 'object') {
  629. length = rep.length;
  630. for (i = 0; i < length; i += 1) {
  631. if (typeof rep[i] === 'string') {
  632. k = rep[i];
  633. v = str(k, value);
  634. if (v) {
  635. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  636. }
  637. }
  638. }
  639. } else {
  640. // Otherwise, iterate through all of the keys in the object.
  641. for (k in value) {
  642. if (Object.prototype.hasOwnProperty.call(value, k)) {
  643. v = str(k, value);
  644. if (v) {
  645. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  646. }
  647. }
  648. }
  649. }
  650. // Join all of the member texts together, separated with commas,
  651. // and wrap them in braces.
  652. v = partial.length === 0 ? '{}' : gap ?
  653. '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
  654. '{' + partial.join(',') + '}';
  655. gap = mind;
  656. return v;
  657. }
  658. }
  659. // If the JSON object does not yet have a stringify method, give it one.
  660. JSON.stringify = function (value, replacer, space) {
  661. // The stringify method takes a value and an optional replacer, and an optional
  662. // space parameter, and returns a JSON text. The replacer can be a function
  663. // that can replace values, or an array of strings that will select the keys.
  664. // A default replacer method can be provided. Use of the space parameter can
  665. // produce text that is more easily readable.
  666. var i;
  667. gap = '';
  668. indent = '';
  669. // If the space parameter is a number, make an indent string containing that
  670. // many spaces.
  671. if (typeof space === 'number') {
  672. for (i = 0; i < space; i += 1) {
  673. indent += ' ';
  674. }
  675. // If the space parameter is a string, it will be used as the indent string.
  676. } else if (typeof space === 'string') {
  677. indent = space;
  678. }
  679. // If there is a replacer, it must be a function or an array.
  680. // Otherwise, throw an error.
  681. rep = replacer;
  682. if (replacer && typeof replacer !== 'function' &&
  683. (typeof replacer !== 'object' ||
  684. typeof replacer.length !== 'number')) {
  685. throw new Error('JSON.stringify');
  686. }
  687. // Make a fake root object containing our value under the key of ''.
  688. // Return the result of stringifying the value.
  689. return str('', {'': value});
  690. };
  691. // If the JSON object does not yet have a parse method, give it one.
  692. JSON.parse = function (text, reviver) {
  693. // The parse method takes a text and an optional reviver function, and returns
  694. // a JavaScript value if the text is a valid JSON text.
  695. var j;
  696. function walk(holder, key) {
  697. // The walk method is used to recursively walk the resulting structure so
  698. // that modifications can be made.
  699. var k, v, value = holder[key];
  700. if (value && typeof value === 'object') {
  701. for (k in value) {
  702. if (Object.prototype.hasOwnProperty.call(value, k)) {
  703. v = walk(value, k);
  704. if (v !== undefined) {
  705. value[k] = v;
  706. } else {
  707. delete value[k];
  708. }
  709. }
  710. }
  711. }
  712. return reviver.call(holder, key, value);
  713. }
  714. // Parsing happens in four stages. In the first stage, we replace certain
  715. // Unicode characters with escape sequences. JavaScript handles many characters
  716. // incorrectly, either silently deleting them, or treating them as line endings.
  717. text = String(text);
  718. cx.lastIndex = 0;
  719. if (cx.test(text)) {
  720. text = text.replace(cx, function (a) {
  721. return '\\u' +
  722. ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  723. });
  724. }
  725. // In the second stage, we run the text against regular expressions that look
  726. // for non-JSON patterns. We are especially concerned with '()' and 'new'
  727. // because they can cause invocation, and '=' because it can cause mutation.
  728. // But just to be safe, we want to reject all unexpected forms.
  729. // We split the second stage into 4 regexp operations in order to work around
  730. // crippling inefficiencies in IE's and Safari's regexp engines. First we
  731. // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
  732. // replace all simple value tokens with ']' characters. Third, we delete all
  733. // open brackets that follow a colon or comma or that begin the text. Finally,
  734. // we look to see that the remaining characters are only whitespace or ']' or
  735. // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
  736. if (/^[\],:{}\s]*$/
  737. .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
  738. .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
  739. .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
  740. // In the third stage we use the eval function to compile the text into a
  741. // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
  742. // in JavaScript: it can begin a block or an object literal. We wrap the text
  743. // in parens to eliminate the ambiguity.
  744. j = eval('(' + text + ')');
  745. // In the optional fourth stage, we recursively walk the new structure, passing
  746. // each name/value pair to a reviver function for possible transformation.
  747. return typeof reviver === 'function' ?
  748. walk({'': j}, '') : j;
  749. }
  750. // If the text is not JSON parseable, then a SyntaxError is thrown.
  751. throw new SyntaxError('JSON.parse');
  752. };
  753. })(
  754. 'undefined' != typeof io ? io : module.exports
  755. , typeof JSON !== 'undefined' ? JSON : undefined
  756. );
  757. /**
  758. * socket.io
  759. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  760. * MIT Licensed
  761. */
  762. (function (exports, io) {
  763. /**
  764. * Parser namespace.
  765. *
  766. * @namespace
  767. */
  768. var parser = exports.parser = {};
  769. /**
  770. * Packet types.
  771. */
  772. var packets = parser.packets = [
  773. 'disconnect'
  774. , 'connect'
  775. , 'heartbeat'
  776. , 'message'
  777. , 'json'
  778. , 'event'
  779. , 'ack'
  780. , 'error'
  781. , 'noop'
  782. ];
  783. /**
  784. * Errors reasons.
  785. */
  786. var reasons = parser.reasons = [
  787. 'transport not supported'
  788. , 'client not handshaken'
  789. , 'unauthorized'
  790. ];
  791. /**
  792. * Errors advice.
  793. */
  794. var advice = parser.advice = [
  795. 'reconnect'
  796. ];
  797. /**
  798. * Shortcuts.
  799. */
  800. var JSON = io.JSON
  801. , indexOf = io.util.indexOf;
  802. /**
  803. * Encodes a packet.
  804. *
  805. * @api private
  806. */
  807. parser.encodePacket = function (packet) {
  808. var type = indexOf(packets, packet.type)
  809. , id = packet.id || ''
  810. , endpoint = packet.endpoint || ''
  811. , ack = packet.ack
  812. , data = null;
  813. switch (packet.type) {
  814. case 'error':
  815. var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
  816. , adv = packet.advice ? indexOf(advice, packet.advice) : '';
  817. if (reason !== '' || adv !== '')
  818. data = reason + (adv !== '' ? ('+' + adv) : '');
  819. break;
  820. case 'message':
  821. if (packet.data !== '')
  822. data = packet.data;
  823. break;
  824. case 'event':
  825. var ev = { name: packet.name };
  826. if (packet.args && packet.args.length) {
  827. ev.args = packet.args;
  828. }
  829. data = JSON.stringify(ev);
  830. break;
  831. case 'json':
  832. data = JSON.stringify(packet.data);
  833. break;
  834. case 'connect':
  835. if (packet.qs)
  836. data = packet.qs;
  837. break;
  838. case 'ack':
  839. data = packet.ackId
  840. + (packet.args && packet.args.length
  841. ? '+' + JSON.stringify(packet.args) : '');
  842. break;
  843. }
  844. // construct packet with required fragments
  845. var encoded = [
  846. type
  847. , id + (ack == 'data' ? '+' : '')
  848. , endpoint
  849. ];
  850. // data fragment is optional
  851. if (data !== null && data !== undefined)
  852. encoded.push(data);
  853. return encoded.join(':');
  854. };
  855. /**
  856. * Encodes multiple messages (payload).
  857. *
  858. * @param {Array} messages
  859. * @api private
  860. */
  861. parser.encodePayload = function (packets) {
  862. var decoded = '';
  863. if (packets.length == 1)
  864. return packets[0];
  865. for (var i = 0, l = packets.length; i < l; i++) {
  866. var packet = packets[i];
  867. decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
  868. }
  869. return decoded;
  870. };
  871. /**
  872. * Decodes a packet
  873. *
  874. * @api private
  875. */
  876. var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
  877. parser.decodePacket = function (data) {
  878. var pieces = data.match(regexp);
  879. if (!pieces) return {};
  880. var id = pieces[2] || ''
  881. , data = pieces[5] || ''
  882. , packet = {
  883. type: packets[pieces[1]]
  884. , endpoint: pieces[4] || ''
  885. };
  886. // whether we need to acknowledge the packet
  887. if (id) {
  888. packet.id = id;
  889. if (pieces[3])
  890. packet.ack = 'data';
  891. else
  892. packet.ack = true;
  893. }
  894. // handle different packet types
  895. switch (packet.type) {
  896. case 'error':
  897. var pieces = data.split('+');
  898. packet.reason = reasons[pieces[0]] || '';
  899. packet.advice = advice[pieces[1]] || '';
  900. break;
  901. case 'message':
  902. packet.data = data || '';
  903. break;
  904. case 'event':
  905. try {
  906. var opts = JSON.parse(data);
  907. packet.name = opts.name;
  908. packet.args = opts.args;
  909. } catch (e) { }
  910. packet.args = packet.args || [];
  911. break;
  912. case 'json':
  913. try {
  914. packet.data = JSON.parse(data);
  915. } catch (e) { }
  916. break;
  917. case 'connect':
  918. packet.qs = data || '';
  919. break;
  920. case 'ack':
  921. var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
  922. if (pieces) {
  923. packet.ackId = pieces[1];
  924. packet.args = [];
  925. if (pieces[3]) {
  926. try {
  927. packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
  928. } catch (e) { }
  929. }
  930. }
  931. break;
  932. case 'disconnect':
  933. case 'heartbeat':
  934. break;
  935. };
  936. return packet;
  937. };
  938. /**
  939. * Decodes data payload. Detects multiple messages
  940. *
  941. * @return {Array} messages
  942. * @api public
  943. */
  944. parser.decodePayload = function (data) {
  945. // IE doesn't like data[i] for unicode chars, charAt works fine
  946. if (data.charAt(0) == '\ufffd') {
  947. var ret = [];
  948. for (var i = 1, length = ''; i < data.length; i++) {
  949. if (data.charAt(i) == '\ufffd') {
  950. ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
  951. i += Number(length) + 1;
  952. length = '';
  953. } else {
  954. length += data.charAt(i);
  955. }
  956. }
  957. return ret;
  958. } else {
  959. return [parser.decodePacket(data)];
  960. }
  961. };
  962. })(
  963. 'undefined' != typeof io ? io : module.exports
  964. , 'undefined' != typeof io ? io : module.parent.exports
  965. );
  966. /**
  967. * socket.io
  968. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  969. * MIT Licensed
  970. */
  971. (function (exports, io) {
  972. /**
  973. * Expose constructor.
  974. */
  975. exports.Transport = Transport;
  976. /**
  977. * This is the transport template for all supported transport methods.
  978. *
  979. * @constructor
  980. * @api public
  981. */
  982. function Transport (socket, sessid) {
  983. this.socket = socket;
  984. this.sessid = sessid;
  985. };
  986. /**
  987. * Apply EventEmitter mixin.
  988. */
  989. io.util.mixin(Transport, io.EventEmitter);
  990. /**
  991. * Handles the response from the server. When a new response is received
  992. * it will automatically update the timeout, decode the message and
  993. * forwards the response to the onMessage function for further processing.
  994. *
  995. * @param {String} data Response from the server.
  996. * @api private
  997. */
  998. Transport.prototype.onData = function (data) {
  999. this.clearCloseTimeout();
  1000. this.setCloseTimeout();
  1001. if (data !== '') {
  1002. // todo: we should only do decodePayload for xhr transports
  1003. var msgs = io.parser.decodePayload(data);
  1004. if (msgs && msgs.length) {
  1005. for (var i = 0, l = msgs.length; i < l; i++) {
  1006. this.onPacket(msgs[i]);
  1007. }
  1008. }
  1009. }
  1010. return this;
  1011. };
  1012. /**
  1013. * Handles packets.
  1014. *
  1015. * @api private
  1016. */
  1017. Transport.prototype.onPacket = function (packet) {
  1018. if (packet.type == 'heartbeat') {
  1019. return this.onHeartbeat();
  1020. }
  1021. if (packet.type == 'connect' && packet.endpoint == '') {
  1022. this.onConnect();
  1023. }
  1024. this.socket.onPacket(packet);
  1025. return this;
  1026. };
  1027. /**
  1028. * Sets close timeout
  1029. *
  1030. * @api private
  1031. */
  1032. Transport.prototype.setCloseTimeout = function () {
  1033. if (!this.closeTimeout) {
  1034. var self = this;
  1035. this.closeTimeout = setTimeout(function () {
  1036. self.onDisconnect();
  1037. }, this.socket.closeTimeout);
  1038. }
  1039. };
  1040. /**
  1041. * Called when transport disconnects.
  1042. *
  1043. * @api private
  1044. */
  1045. Transport.prototype.onDisconnect = function () {
  1046. if (this.close) this.close();
  1047. this.clearTimeouts();
  1048. this.socket.onDisconnect();
  1049. return this;
  1050. };
  1051. /**
  1052. * Called when transport connects
  1053. *
  1054. * @api private
  1055. */
  1056. Transport.prototype.onConnect = function () {
  1057. this.socket.onConnect();
  1058. return this;
  1059. }
  1060. /**
  1061. * Clears close timeout
  1062. *
  1063. * @api private
  1064. */
  1065. Transport.prototype.clearCloseTimeout = function () {
  1066. if (this.closeTimeout) {
  1067. clearTimeout(this.closeTimeout);
  1068. this.closeTimeout = null;
  1069. }
  1070. };
  1071. /**
  1072. * Clear timeouts
  1073. *
  1074. * @api private
  1075. */
  1076. Transport.prototype.clearTimeouts = function () {
  1077. this.clearCloseTimeout();
  1078. if (this.reopenTimeout) {
  1079. clearTimeout(this.reopenTimeout);
  1080. }
  1081. };
  1082. /**
  1083. * Sends a packet
  1084. *
  1085. * @param {Object} packet object.
  1086. * @api private
  1087. */
  1088. Transport.prototype.packet = function (packet) {
  1089. this.send(io.parser.encodePacket(packet));
  1090. };
  1091. /**
  1092. * Send the received heartbeat message back to server. So the server
  1093. * knows we are still connected.
  1094. *
  1095. * @param {String} heartbeat Heartbeat response from the server.
  1096. * @api private
  1097. */
  1098. Transport.prototype.onHeartbeat = function (heartbeat) {
  1099. this.packet({ type: 'heartbeat' });
  1100. };
  1101. /**
  1102. * Called when the transport opens.
  1103. *
  1104. * @api private
  1105. */
  1106. Transport.prototype.onOpen = function () {
  1107. this.open = true;
  1108. this.clearCloseTimeout();
  1109. this.socket.onOpen();
  1110. };
  1111. /**
  1112. * Notifies the base when the connection with the Socket.IO server
  1113. * has been disconnected.
  1114. *
  1115. * @api private
  1116. */
  1117. Transport.prototype.onClose = function () {
  1118. var self = this;
  1119. /* FIXME: reopen delay causing a infinit loop
  1120. this.reopenTimeout = setTimeout(function () {
  1121. self.open();
  1122. }, this.socket.options['reopen delay']);*/
  1123. this.open = false;
  1124. this.setCloseTimeout();
  1125. this.socket.onClose();
  1126. };
  1127. /**
  1128. * Generates a connection url based on the Socket.IO URL Protocol.
  1129. * See <https://github.com/learnboost/socket.io-node/> for more details.
  1130. *
  1131. * @returns {String} Connection url
  1132. * @api private
  1133. */
  1134. Transport.prototype.prepareUrl = function () {
  1135. var options = this.socket.options;
  1136. return this.scheme() + '://'
  1137. + options.host + ':' + options.port + '/'
  1138. + options.resource + '/' + io.protocol
  1139. + '/' + this.name + '/' + this.sessid;
  1140. };
  1141. /**
  1142. * Checks if the transport is ready to start a connection.
  1143. *
  1144. * @param {Socket} socket The socket instance that needs a transport
  1145. * @param {Function} fn The callback
  1146. * @api private
  1147. */
  1148. Transport.prototype.ready = function (socket, fn) {
  1149. fn.call(this);
  1150. };
  1151. })(
  1152. 'undefined' != typeof io ? io : module.exports
  1153. , 'undefined' != typeof io ? io : module.parent.exports
  1154. );
  1155. /**
  1156. * socket.io
  1157. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1158. * MIT Licensed
  1159. */
  1160. (function (exports, io, global) {
  1161. /**
  1162. * Expose constructor.
  1163. */
  1164. exports.Socket = Socket;
  1165. /**
  1166. * Create a new `Socket.IO client` which can establish a persistent
  1167. * connection with a Socket.IO enabled server.
  1168. *
  1169. * @api public
  1170. */
  1171. function Socket (options) {
  1172. this.options = {
  1173. port: 80
  1174. , secure: false
  1175. , document: 'document' in global ? document : false
  1176. , resource: 'socket.io'
  1177. , transports: io.transports
  1178. , 'connect timeout': 10000
  1179. , 'try multiple transports': true
  1180. , 'reconnect': true
  1181. , 'reconnection delay': 500
  1182. , 'reconnection limit': Infinity
  1183. , 'reopen delay': 3000
  1184. , 'max reconnection attempts': 10
  1185. , 'sync disconnect on unload': true
  1186. , 'auto connect': true
  1187. };
  1188. io.util.merge(this.options, options);
  1189. this.connected = false;
  1190. this.open = false;
  1191. this.connecting = false;
  1192. this.reconnecting = false;
  1193. this.namespaces = {};
  1194. this.buffer = [];
  1195. this.doBuffer = false;
  1196. if (this.options['sync disconnect on unload'] &&
  1197. (!this.isXDomain() || io.util.ua.hasCORS)) {
  1198. var self = this;
  1199. io.util.on(global, 'beforeunload', function () {
  1200. self.disconnectSync();
  1201. }, false);
  1202. }
  1203. if (this.options['auto connect']) {
  1204. this.connect();
  1205. }
  1206. };
  1207. /**
  1208. * Apply EventEmitter mixin.
  1209. */
  1210. io.util.mixin(Socket, io.EventEmitter);
  1211. /**
  1212. * Returns a namespace listener/emitter for this socket
  1213. *
  1214. * @api public
  1215. */
  1216. Socket.prototype.of = function (name) {
  1217. if (!this.namespaces[name]) {
  1218. this.namespaces[name] = new io.SocketNamespace(this, name);
  1219. if (name !== '') {
  1220. this.namespaces[name].packet({ type: 'connect' });
  1221. }
  1222. }
  1223. return this.namespaces[name];
  1224. };
  1225. /**
  1226. * Emits the given event to the Socket and all namespaces
  1227. *
  1228. * @api private
  1229. */
  1230. Socket.prototype.publish = function () {
  1231. this.emit.apply(this, arguments);
  1232. var nsp;
  1233. for (var i in this.namespaces) {
  1234. if (this.namespaces.hasOwnProperty(i)) {
  1235. nsp = this.of(i);
  1236. nsp.$emit.apply(nsp, arguments);
  1237. }
  1238. }
  1239. };
  1240. /**
  1241. * Performs the handshake
  1242. *
  1243. * @api private
  1244. */
  1245. function empty () { };
  1246. Socket.prototype.handshake = function (fn) {
  1247. var self = this
  1248. , options = this.options;
  1249. function complete (data) {
  1250. if (data instanceof Error) {
  1251. self.onError(data.message);
  1252. } else {
  1253. fn.apply(null, data.split(':'));
  1254. }
  1255. };
  1256. var url = [
  1257. 'http' + (options.secure ? 's' : '') + ':/'
  1258. , options.host + ':' + options.port
  1259. , this.options.resource
  1260. , io.protocol
  1261. , io.util.query(this.options.query, 't=' + +new Date)
  1262. ].join('/');
  1263. if (this.isXDomain()) {
  1264. var insertAt = document.getElementsByTagName('script')[0]
  1265. , script = document.createElement('SCRIPT');
  1266. script.src = url + '&jsonp=' + io.j.length;
  1267. insertAt.parentNode.insertBefore(script, insertAt);
  1268. io.j.push(function (data) {
  1269. complete(data);
  1270. script.parentNode.removeChild(script);
  1271. });
  1272. } else {
  1273. var xhr = io.util.request();
  1274. xhr.open('GET', url, true);
  1275. xhr.onreadystatechange = function () {
  1276. if (xhr.readyState == 4) {
  1277. xhr.onreadystatechange = empty;
  1278. if (xhr.status == 200) {
  1279. complete(xhr.responseText);
  1280. } else {
  1281. !self.reconnecting && self.onError(xhr.responseText);
  1282. }
  1283. }
  1284. };
  1285. xhr.send(null);
  1286. }
  1287. };
  1288. /**
  1289. * Find an available transport based on the options supplied in the constructor.
  1290. *
  1291. * @api private
  1292. */
  1293. Socket.prototype.getTransport = function (override) {
  1294. var transports = override || this.transports, match;
  1295. for (var i = 0, transport; transport = transports[i]; i++) {
  1296. if (io.Transport[transport]
  1297. && io.Transport[transport].check(this)
  1298. && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
  1299. return new io.Transport[transport](this, this.sessionid);
  1300. }
  1301. }
  1302. return null;
  1303. };
  1304. /**
  1305. * Connects to the server.
  1306. *
  1307. * @param {Function} [fn] Callback.
  1308. * @returns {io.Socket}
  1309. * @api public
  1310. */
  1311. Socket.prototype.connect = function (fn) {
  1312. if (this.connecting) {
  1313. return this;
  1314. }
  1315. var self = this;
  1316. this.handshake(function (sid, heartbeat, close, transports) {
  1317. self.sessionid = sid;
  1318. self.closeTimeout = close * 1000;
  1319. self.heartbeatTimeout = heartbeat * 1000;
  1320. self.transports = io.util.intersect(
  1321. transports.split(',')
  1322. , self.options.transports
  1323. );
  1324. function connect (transports){
  1325. if (self.transport) self.transport.clearTimeouts();
  1326. self.transport = self.getTransport(transports);
  1327. if (!self.transport) return self.publish('connect_failed');
  1328. // once the transport is ready
  1329. self.transport.ready(self, function () {
  1330. self.connecting = true;
  1331. self.publish('connecting', self.transport.name);
  1332. self.transport.open();
  1333. if (self.options['connect timeout']) {
  1334. self.connectTimeoutTimer = setTimeout(function () {
  1335. if (!self.connected) {
  1336. self.connecting = false;
  1337. if (self.options['try multiple transports']) {
  1338. if (!self.remainingTransports) {
  1339. self.remainingTransports = self.transports.slice(0);
  1340. }
  1341. var remaining = self.remainingTransports;
  1342. while (remaining.length > 0 && remaining.splice(0,1)[0] !=
  1343. self.transport.name) {}
  1344. if (remaining.length){
  1345. connect(remaining);
  1346. } else {
  1347. self.publish('connect_failed');
  1348. }
  1349. }
  1350. }
  1351. }, self.options['connect timeout']);
  1352. }
  1353. });
  1354. }
  1355. connect();
  1356. self.once('connect', function (){
  1357. clearTimeout(self.connectTimeoutTimer);
  1358. fn && typeof fn == 'function' && fn();
  1359. });
  1360. });
  1361. return this;
  1362. };
  1363. /**
  1364. * Sends a message.
  1365. *
  1366. * @param {Object} data packet.
  1367. * @returns {io.Socket}
  1368. * @api public
  1369. */
  1370. Socket.prototype.packet = function (data) {
  1371. if (this.connected && !this.doBuffer) {
  1372. this.transport.packet(data);
  1373. } else {
  1374. this.buffer.push(data);
  1375. }
  1376. return this;
  1377. };
  1378. /**
  1379. * Sets buffer state
  1380. *
  1381. * @api private
  1382. */
  1383. Socket.prototype.setBuffer = function (v) {
  1384. this.doBuffer = v;
  1385. if (!v && this.connected && this.buffer.length) {
  1386. this.transport.payload(this.buffer);
  1387. this.buffer = [];
  1388. }
  1389. };
  1390. /**
  1391. * Disconnect the established connect.
  1392. *
  1393. * @returns {io.Socket}
  1394. * @api public
  1395. */
  1396. Socket.prototype.disconnect = function () {
  1397. if (this.connected) {
  1398. if (this.open) {
  1399. this.of('').packet({ type: 'disconnect' });
  1400. }
  1401. // handle disconnection immediately
  1402. this.onDisconnect('booted');
  1403. }
  1404. return this;
  1405. };
  1406. /**
  1407. * Disconnects the socket with a sync XHR.
  1408. *
  1409. * @api private
  1410. */
  1411. Socket.prototype.disconnectSync = function () {
  1412. // ensure disconnection
  1413. var xhr = io.util.request()
  1414. , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
  1415. xhr.open('GET', uri, true);
  1416. // handle disconnection immediately
  1417. this.onDisconnect('booted');
  1418. };
  1419. /**
  1420. * Check if we need to use cross domain enabled transports. Cross domain would
  1421. * be a different port or different domain name.
  1422. *
  1423. * @returns {Boolean}
  1424. * @api private
  1425. */
  1426. Socket.prototype.isXDomain = function () {
  1427. var locPort = window.location.port || 80;
  1428. return this.options.host !== document.domain || this.options.port != locPort;
  1429. };
  1430. /**
  1431. * Called upon handshake.
  1432. *
  1433. * @api private
  1434. */
  1435. Socket.prototype.onConnect = function () {
  1436. if (!this.connected) {
  1437. this.connected = true;
  1438. this.connecting = false;
  1439. if (!this.doBuffer) {
  1440. // make sure to flush the buffer
  1441. this.setBuffer(false);
  1442. }
  1443. this.emit('connect');
  1444. }
  1445. };
  1446. /**
  1447. * Called when the transport opens
  1448. *
  1449. * @api private
  1450. */
  1451. Socket.prototype.onOpen = function () {
  1452. this.open = true;
  1453. };
  1454. /**
  1455. * Called when the transport closes.
  1456. *
  1457. * @api private
  1458. */
  1459. Socket.prototype.onClose = function () {
  1460. this.open = false;
  1461. };
  1462. /**
  1463. * Called when the transport first opens a connection
  1464. *
  1465. * @param text
  1466. */
  1467. Socket.prototype.onPacket = function (packet) {
  1468. this.of(packet.endpoint).onPacket(packet);
  1469. };
  1470. /**
  1471. * Handles an error.
  1472. *
  1473. * @api private
  1474. */
  1475. Socket.prototype.onError = function (err) {
  1476. if (err && err.advice) {
  1477. if (err.advice === 'reconnect' && this.connected) {
  1478. this.disconnect();
  1479. this.reconnect();
  1480. }
  1481. }
  1482. this.publish('error', err && err.reason ? err.reason : err);
  1483. };
  1484. /**
  1485. * Called when the transport disconnects.
  1486. *
  1487. * @api private
  1488. */
  1489. Socket.prototype.onDisconnect = function (reason) {
  1490. var wasConnected = this.connected;
  1491. this.connected = false;
  1492. this.connecting = false;
  1493. this.open = false;
  1494. if (wasConnected) {
  1495. this.transport.close();
  1496. this.transport.clearTimeouts();
  1497. this.publish('disconnect', reason);
  1498. if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
  1499. this.reconnect();
  1500. }
  1501. }
  1502. };
  1503. /**
  1504. * Called upon reconnection.
  1505. *
  1506. * @api private
  1507. */
  1508. Socket.prototype.reconnect = function () {
  1509. this.reconnecting = true;
  1510. this.reconnectionAttempts = 0;
  1511. this.reconnectionDelay = this.options['reconnection delay'];
  1512. var self = this
  1513. , maxAttempts = this.options['max reconnection attempts']
  1514. , tryMultiple = this.options['try multiple transports']
  1515. , limit = this.options['reconnection limit'];
  1516. function reset () {
  1517. if (self.connected) {
  1518. for (var i in self.namespaces) {
  1519. if (self.namespaces.hasOwnProperty(i) && '' !== i) {
  1520. self.namespaces[i].packet({ type: 'connect' });
  1521. }
  1522. }
  1523. self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
  1524. }
  1525. self.removeListener('connect_failed', maybeReconnect);
  1526. self.removeListener('connect', maybeReconnect);
  1527. self.reconnecting = false;
  1528. delete self.reconnectionAttempts;
  1529. delete self.reconnectionDelay;
  1530. delete self.reconnectionTimer;
  1531. delete self.redoTransports;
  1532. self.options['try multiple transports'] = tryMultiple;
  1533. };
  1534. function maybeReconnect () {
  1535. if (!self.reconnecting) {
  1536. return;
  1537. }
  1538. if (self.connected) {
  1539. return reset();
  1540. };
  1541. if (self.connecting && self.reconnecting) {
  1542. return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
  1543. }
  1544. if (self.reconnectionAttempts++ >= maxAttempts) {
  1545. if (!self.redoTransports) {
  1546. self.on('connect_failed', maybeReconnect);
  1547. self.options['try multiple transports'] = true;
  1548. self.transport = self.getTransport();
  1549. self.redoTransports = true;
  1550. self.connect();
  1551. } else {
  1552. self.publish('reconnect_failed');
  1553. reset();
  1554. }
  1555. } else {
  1556. if (self.reconnectionDelay < limit) {
  1557. self.reconnectionDelay *= 2; // exponential back off
  1558. }
  1559. self.connect();
  1560. self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
  1561. self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
  1562. }
  1563. };
  1564. this.options['try multiple transports'] = false;
  1565. this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
  1566. this.on('connect', maybeReconnect);
  1567. };
  1568. })(
  1569. 'undefined' != typeof io ? io : module.exports
  1570. , 'undefined' != typeof io ? io : module.parent.exports
  1571. , this
  1572. );
  1573. /**
  1574. * socket.io
  1575. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1576. * MIT Licensed
  1577. */
  1578. (function (exports, io) {
  1579. /**
  1580. * Expose constructor.
  1581. */
  1582. exports.SocketNamespace = SocketNamespace;
  1583. /**
  1584. * Socket namespace constructor.
  1585. *
  1586. * @constructor
  1587. * @api public
  1588. */
  1589. function SocketNamespace (socket, name) {
  1590. this.socket = socket;
  1591. this.name = name || '';
  1592. this.flags = {};
  1593. this.json = new Flag(this, 'json');
  1594. this.ackPackets = 0;
  1595. this.acks = {};
  1596. };
  1597. /**
  1598. * Apply EventEmitter mixin.
  1599. */
  1600. io.util.mixin(SocketNamespace, io.EventEmitter);
  1601. /**
  1602. * Copies emit since we override it
  1603. *
  1604. * @api private
  1605. */
  1606. SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
  1607. /**
  1608. * Creates a new namespace, by proxying the request to the socket. This
  1609. * allows us to use the synax as we do on the server.
  1610. *
  1611. * @api public
  1612. */
  1613. SocketNamespace.prototype.of = function () {
  1614. return this.socket.of.apply(this.socket, arguments);
  1615. };
  1616. /**
  1617. * Sends a packet.
  1618. *
  1619. * @api private
  1620. */
  1621. SocketNamespace.prototype.packet = function (packet) {
  1622. packet.endpoint = this.name;
  1623. this.socket.packet(packet);
  1624. this.flags = {};
  1625. return this;
  1626. };
  1627. /**
  1628. * Sends a message
  1629. *
  1630. * @api public
  1631. */
  1632. SocketNamespace.prototype.send = function (data, fn) {
  1633. var packet = {
  1634. type: this.flags.json ? 'json' : 'message'
  1635. , data: data
  1636. };
  1637. if ('function' == typeof fn) {
  1638. packet.id = ++this.ackPackets;
  1639. packet.ack = true;
  1640. this.acks[packet.id] = fn;
  1641. }
  1642. return this.packet(packet);
  1643. };
  1644. /**
  1645. * Emits an event
  1646. *
  1647. * @api public
  1648. */
  1649. SocketNamespace.prototype.emit = function (name) {
  1650. var args = Array.prototype.slice.call(arguments, 1)
  1651. , lastArg = args[args.length - 1]
  1652. , packet = {
  1653. type: 'event'
  1654. , name: name
  1655. };
  1656. if ('function' == typeof lastArg) {
  1657. packet.id = ++this.ackPackets;
  1658. packet.ack = 'data';
  1659. this.acks[packet.id] = lastArg;
  1660. args = args.slice(0, args.length - 1);
  1661. }
  1662. packet.args = args;
  1663. return this.packet(packet);
  1664. };
  1665. /**
  1666. * Disconnects the namespace
  1667. *
  1668. * @api private
  1669. */
  1670. SocketNamespace.prototype.disconnect = function () {
  1671. if (this.name === '') {
  1672. this.socket.disconnect();
  1673. } else {
  1674. this.packet({ type: 'disconnect' });
  1675. this.$emit('disconnect');
  1676. }
  1677. return this;
  1678. };
  1679. /**
  1680. * Handles a packet
  1681. *
  1682. * @api private
  1683. */
  1684. SocketNamespace.prototype.onPacket = function (packet) {
  1685. var self = this;
  1686. function ack () {
  1687. self.packet({
  1688. type: 'ack'
  1689. , args: io.util.toArray(arguments)
  1690. , ackId: packet.id
  1691. });
  1692. };
  1693. switch (packet.type) {
  1694. case 'connect':
  1695. this.$emit('connect');
  1696. break;
  1697. case 'disconnect':
  1698. if (this.name === '') {
  1699. this.socket.onDisconnect(packet.reason || 'booted');
  1700. } else {
  1701. this.$emit('disconnect', packet.reason);
  1702. }
  1703. break;
  1704. case 'message':
  1705. case 'json':
  1706. var params = ['message', packet.data];
  1707. if (packet.ack == 'data') {
  1708. params.push(ack);
  1709. } else if (packet.ack) {
  1710. this.packet({ type: 'ack', ackId: packet.id });
  1711. }
  1712. this.$emit.apply(this, params);
  1713. break;
  1714. case 'event':
  1715. var params = [packet.name].concat(packet.args);
  1716. if (packet.ack == 'data')
  1717. params.push(ack);
  1718. this.$emit.apply(this, params);
  1719. break;
  1720. case 'ack':
  1721. if (this.acks[packet.ackId]) {
  1722. this.acks[packet.ackId].apply(this, packet.args);
  1723. delete this.acks[packet.ackId];
  1724. }
  1725. break;
  1726. case 'error':
  1727. if (packet.advice){
  1728. this.socket.onError(packet);
  1729. } else {
  1730. if (packet.reason == 'unauthorized') {
  1731. this.$emit('connect_failed', packet.reason);
  1732. } else {
  1733. this.$emit('error', packet.reason);
  1734. }
  1735. }
  1736. break;
  1737. }
  1738. };
  1739. /**
  1740. * Flag interface.
  1741. *
  1742. * @api private
  1743. */
  1744. function Flag (nsp, name) {
  1745. this.namespace = nsp;
  1746. this.name = name;
  1747. };
  1748. /**
  1749. * Send a message
  1750. *
  1751. * @api public
  1752. */
  1753. Flag.prototype.send = function () {
  1754. this.namespace.flags[this.name] = true;
  1755. this.namespace.send.apply(this.namespace, arguments);
  1756. };
  1757. /**
  1758. * Emit an event
  1759. *
  1760. * @api public
  1761. */
  1762. Flag.prototype.emit = function () {
  1763. this.namespace.flags[this.name] = true;
  1764. this.namespace.emit.apply(this.namespace, arguments);
  1765. };
  1766. })(
  1767. 'undefined' != typeof io ? io : module.exports
  1768. , 'undefined' != typeof io ? io : module.parent.exports
  1769. );
  1770. /**
  1771. * socket.io
  1772. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1773. * MIT Licensed
  1774. */
  1775. (function (exports, io) {
  1776. /**
  1777. * Expose c…

Large files files are truncated, but you can click here to view the full file