├── LICENSE.txt ├── README.md ├── bower.json ├── package.json ├── reconnecting-websocket.js └── reconnecting-websocket.min.js /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License: 2 | 3 | Copyright (c) 2010-2012, Joe Walnes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ReconnectingWebSocket 2 | ===================== 3 | 4 | A small JavaScript library that decorates the WebSocket API to provide a WebSocket connection that will automatically reconnect if the connection is dropped. 5 | 6 | It is API compatible, so when you have: 7 | 8 | ```javascript 9 | var ws = new WebSocket('ws://....'); 10 | ``` 11 | 12 | you can replace with: 13 | 14 | ```javascript 15 | var ws = new ReconnectingWebSocket('ws://....'); 16 | ``` 17 | 18 | Minified library with gzip compression is less than 600 bytes. 19 | 20 | How reconnections occur 21 | ----------------------- 22 | 23 | With the standard `WebSocket` API, the events you receive from the WebSocket instance are typically: 24 | 25 | onopen 26 | onmessage 27 | onmessage 28 | onmessage 29 | onclose // At this point the WebSocket instance is dead. 30 | 31 | With a `ReconnectingWebSocket`, after an `onclose` event is called it will automatically attempt to reconnect. In addition, a connection is attempted repeatedly (with a small pause) until it succeeds. So the events you receive may look something more like: 32 | 33 | onopen 34 | onmessage 35 | onmessage 36 | onmessage 37 | onclose 38 | // ReconnectingWebSocket attempts to reconnect 39 | onopen 40 | onmessage 41 | onmessage 42 | onmessage 43 | onclose 44 | // ReconnectingWebSocket attempts to reconnect 45 | onopen 46 | onmessage 47 | onmessage 48 | onmessage 49 | onclose 50 | 51 | This is all handled automatically for you by the library. 52 | 53 | ## Parameters 54 | 55 | ```javascript 56 | var socket = new ReconnectingWebSocket(url, protocols, options); 57 | ``` 58 | 59 | #### `url` 60 | - The URL you are connecting to. 61 | - https://html.spec.whatwg.org/multipage/comms.html#network 62 | 63 | #### `protocols` 64 | - Optional string or array of protocols per the WebSocket spec. 65 | - https://tools.ietf.org/html/rfc6455 66 | 67 | #### `options` 68 | - Options (see below) 69 | 70 | ## Options 71 | 72 | Options can either be passed as the 3rd parameter upon instantiation or set directly on the object after instantiation: 73 | 74 | ```javascript 75 | var socket = new ReconnectingWebSocket(url, null, {debug: true, reconnectInterval: 3000}); 76 | ``` 77 | 78 | or 79 | 80 | ```javascript 81 | var socket = new ReconnectingWebSocket(url); 82 | socket.debug = true; 83 | socket.timeoutInterval = 5400; 84 | ``` 85 | 86 | #### `debug` 87 | - Whether this instance should log debug messages or not. Debug messages are printed to `console.debug()`. 88 | - Accepts `true` or `false` 89 | - Default value: `false` 90 | 91 | #### `automaticOpen` 92 | - Whether or not the websocket should attempt to connect immediately upon instantiation. The socket can be manually opened or closed at any time using ws.open() and ws.close(). 93 | - Accepts `true` or `false` 94 | - Default value: `true` 95 | 96 | #### `reconnectInterval` 97 | - The number of milliseconds to delay before attempting to reconnect. 98 | - Accepts `integer` 99 | - Default: `1000` 100 | 101 | #### `maxReconnectInterval` 102 | - The maximum number of milliseconds to delay a reconnection attempt. 103 | - Accepts `integer` 104 | - Default: `30000` 105 | 106 | ####`reconnectDecay` 107 | - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. 108 | - Accepts `integer` or `float` 109 | - Default: `1.5` 110 | 111 | #### `timeoutInterval` 112 | - The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. 113 | - Accepts `integer` 114 | - Default: `2000` 115 | 116 | #### `maxReconnectAttempts` 117 | - The maximum number of reconnection attempts that will be made before giving up. If null, reconnection attempts will be continue to be made forever. 118 | - Accepts `integer` or `null`. 119 | - Default: `null` 120 | 121 | #### `binaryType` 122 | - The binary type is required by some applications. 123 | - Accepts strings `'blob'` or `'arraybuffer'`. 124 | - Default: `'blob'` 125 | 126 | --- 127 | 128 | ## Methods 129 | 130 | #### `ws.open()` 131 | - Open the Reconnecting Websocket 132 | 133 | #### `ws.close(code, reason)` 134 | - Closes the WebSocket connection or connection attempt, if any. If the connection is already CLOSED, this method does nothing. 135 | - `code` is optional the closing code (default value 1000). [https://tools.ietf.org/html/rfc6455#section-7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1) 136 | - `reason` is the optional reason that the socket is being closed. [https://tools.ietf.org/html/rfc6455#section-7.1.6](https://tools.ietf.org/html/rfc6455#section-7.1.6) 137 | 138 | #### `ws.refresh()` 139 | - Refresh the connection if still open (close and then re-open it). 140 | 141 | #### `ws.send(data)` 142 | - Transmits data to the server over the WebSocket connection. 143 | - Accepts @param data a text string, ArrayBuffer or Blob 144 | 145 | Like this? Check out [websocketd](https://github.com/joewalnes/websocketd) for the simplest way to create WebSocket backends from any programming language. 146 | 147 | [Follow @joewalnes](https://twitter.com/joewalnes) 148 | 149 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/joewalnes/reconnecting-websocket/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 150 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reconnectingWebsocket", 3 | "main": "reconnecting-websocket.js", 4 | "version": "1.0.1", 5 | "homepage": "https://github.com/joewalnes/reconnecting-websocket", 6 | "authors": [ 7 | "Joe Walnes", 8 | "headlessme " 9 | ], 10 | "description": "A small decorator for the JavaScript WebSocket API that automatically reconnects", 11 | "moduleType": [ 12 | "amd", 13 | "globals", 14 | "node" 15 | ], 16 | "license": "MIT", 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "test", 22 | "tests" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReconnectingWebSocket", 3 | "version": "1.0.1", 4 | "description": "A small JavaScript library that decorates the WebSocket API to provide a WebSocket connection that will automatically reconnect if the connection is dropped.", 5 | "main": "reconnecting-websocket.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/joewalnes/reconnecting-websocket.git" 12 | }, 13 | "author": "Joe Walnes", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/joewalnes/reconnecting-websocket/issues" 17 | }, 18 | "homepage": "https://github.com/joewalnes/reconnecting-websocket" 19 | } 20 | -------------------------------------------------------------------------------- /reconnecting-websocket.js: -------------------------------------------------------------------------------- 1 | // MIT License: 2 | // 3 | // Copyright (c) 2010-2012, Joe Walnes 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | /** 24 | * This behaves like a WebSocket in every way, except if it fails to connect, 25 | * or it gets disconnected, it will repeatedly poll until it successfully connects 26 | * again. 27 | * 28 | * It is API compatible, so when you have: 29 | * ws = new WebSocket('ws://....'); 30 | * you can replace with: 31 | * ws = new ReconnectingWebSocket('ws://....'); 32 | * 33 | * The event stream will typically look like: 34 | * onconnecting 35 | * onopen 36 | * onmessage 37 | * onmessage 38 | * onclose // lost connection 39 | * onconnecting 40 | * onopen // sometime later... 41 | * onmessage 42 | * onmessage 43 | * etc... 44 | * 45 | * It is API compatible with the standard WebSocket API, apart from the following members: 46 | * 47 | * - `bufferedAmount` 48 | * - `extensions` 49 | * - `binaryType` 50 | * 51 | * Latest version: https://github.com/joewalnes/reconnecting-websocket/ 52 | * - Joe Walnes 53 | * 54 | * Syntax 55 | * ====== 56 | * var socket = new ReconnectingWebSocket(url, protocols, options); 57 | * 58 | * Parameters 59 | * ========== 60 | * url - The url you are connecting to. 61 | * protocols - Optional string or array of protocols. 62 | * options - See below 63 | * 64 | * Options 65 | * ======= 66 | * Options can either be passed upon instantiation or set after instantiation: 67 | * 68 | * var socket = new ReconnectingWebSocket(url, null, { debug: true, reconnectInterval: 4000 }); 69 | * 70 | * or 71 | * 72 | * var socket = new ReconnectingWebSocket(url); 73 | * socket.debug = true; 74 | * socket.reconnectInterval = 4000; 75 | * 76 | * debug 77 | * - Whether this instance should log debug messages. Accepts true or false. Default: false. 78 | * 79 | * automaticOpen 80 | * - Whether or not the websocket should attempt to connect immediately upon instantiation. The socket can be manually opened or closed at any time using ws.open() and ws.close(). 81 | * 82 | * reconnectInterval 83 | * - The number of milliseconds to delay before attempting to reconnect. Accepts integer. Default: 1000. 84 | * 85 | * maxReconnectInterval 86 | * - The maximum number of milliseconds to delay a reconnection attempt. Accepts integer. Default: 30000. 87 | * 88 | * reconnectDecay 89 | * - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. Accepts integer or float. Default: 1.5. 90 | * 91 | * timeoutInterval 92 | * - The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. Accepts integer. Default: 2000. 93 | * 94 | */ 95 | (function (global, factory) { 96 | if (typeof define === 'function' && define.amd) { 97 | define([], factory); 98 | } else if (typeof module !== 'undefined' && module.exports){ 99 | module.exports = factory(); 100 | } else { 101 | global.ReconnectingWebSocket = factory(); 102 | } 103 | })(this, function () { 104 | 105 | if (!('WebSocket' in window)) { 106 | return; 107 | } 108 | 109 | function ReconnectingWebSocket(url, protocols, options) { 110 | 111 | // Default settings 112 | var settings = { 113 | 114 | /** Whether this instance should log debug messages. */ 115 | debug: false, 116 | 117 | /** Whether or not the websocket should attempt to connect immediately upon instantiation. */ 118 | automaticOpen: true, 119 | 120 | /** The number of milliseconds to delay before attempting to reconnect. */ 121 | reconnectInterval: 1000, 122 | /** The maximum number of milliseconds to delay a reconnection attempt. */ 123 | maxReconnectInterval: 30000, 124 | /** The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. */ 125 | reconnectDecay: 1.5, 126 | 127 | /** The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. */ 128 | timeoutInterval: 2000, 129 | 130 | /** The maximum number of reconnection attempts to make. Unlimited if null. */ 131 | maxReconnectAttempts: null, 132 | 133 | /** The binary type, possible values 'blob' or 'arraybuffer', default 'blob'. */ 134 | binaryType: 'blob' 135 | } 136 | if (!options) { options = {}; } 137 | 138 | // Overwrite and define settings with options if they exist. 139 | for (var key in settings) { 140 | if (typeof options[key] !== 'undefined') { 141 | this[key] = options[key]; 142 | } else { 143 | this[key] = settings[key]; 144 | } 145 | } 146 | 147 | // These should be treated as read-only properties 148 | 149 | /** The URL as resolved by the constructor. This is always an absolute URL. Read only. */ 150 | this.url = url; 151 | 152 | /** The number of attempted reconnects since starting, or the last successful connection. Read only. */ 153 | this.reconnectAttempts = 0; 154 | 155 | /** 156 | * The current state of the connection. 157 | * Can be one of: WebSocket.CONNECTING, WebSocket.OPEN, WebSocket.CLOSING, WebSocket.CLOSED 158 | * Read only. 159 | */ 160 | this.readyState = WebSocket.CONNECTING; 161 | 162 | /** 163 | * A string indicating the name of the sub-protocol the server selected; this will be one of 164 | * the strings specified in the protocols parameter when creating the WebSocket object. 165 | * Read only. 166 | */ 167 | this.protocol = null; 168 | 169 | // Private state variables 170 | 171 | var self = this; 172 | var ws; 173 | var forcedClose = false; 174 | var timedOut = false; 175 | var eventTarget = document.createElement('div'); 176 | 177 | // Wire up "on*" properties as event handlers 178 | 179 | eventTarget.addEventListener('open', function(event) { self.onopen(event); }); 180 | eventTarget.addEventListener('close', function(event) { self.onclose(event); }); 181 | eventTarget.addEventListener('connecting', function(event) { self.onconnecting(event); }); 182 | eventTarget.addEventListener('message', function(event) { self.onmessage(event); }); 183 | eventTarget.addEventListener('error', function(event) { self.onerror(event); }); 184 | 185 | // Expose the API required by EventTarget 186 | 187 | this.addEventListener = eventTarget.addEventListener.bind(eventTarget); 188 | this.removeEventListener = eventTarget.removeEventListener.bind(eventTarget); 189 | this.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget); 190 | 191 | /** 192 | * This function generates an event that is compatible with standard 193 | * compliant browsers and IE9 - IE11 194 | * 195 | * This will prevent the error: 196 | * Object doesn't support this action 197 | * 198 | * http://stackoverflow.com/questions/19345392/why-arent-my-parameters-getting-passed-through-to-a-dispatched-event/19345563#19345563 199 | * @param s String The name that the event should use 200 | * @param args Object an optional object that the event will use 201 | */ 202 | function generateEvent(s, args) { 203 | var evt = document.createEvent("CustomEvent"); 204 | evt.initCustomEvent(s, false, false, args); 205 | return evt; 206 | }; 207 | 208 | this.open = function (reconnectAttempt) { 209 | ws = new WebSocket(self.url, protocols || []); 210 | ws.binaryType = this.binaryType; 211 | 212 | if (reconnectAttempt) { 213 | if (this.maxReconnectAttempts && this.reconnectAttempts > this.maxReconnectAttempts) { 214 | return; 215 | } 216 | } else { 217 | eventTarget.dispatchEvent(generateEvent('connecting')); 218 | this.reconnectAttempts = 0; 219 | } 220 | 221 | if (self.debug || ReconnectingWebSocket.debugAll) { 222 | console.debug('ReconnectingWebSocket', 'attempt-connect', self.url); 223 | } 224 | 225 | var localWs = ws; 226 | var timeout = setTimeout(function() { 227 | if (self.debug || ReconnectingWebSocket.debugAll) { 228 | console.debug('ReconnectingWebSocket', 'connection-timeout', self.url); 229 | } 230 | timedOut = true; 231 | localWs.close(); 232 | timedOut = false; 233 | }, self.timeoutInterval); 234 | 235 | ws.onopen = function(event) { 236 | clearTimeout(timeout); 237 | if (self.debug || ReconnectingWebSocket.debugAll) { 238 | console.debug('ReconnectingWebSocket', 'onopen', self.url); 239 | } 240 | self.protocol = ws.protocol; 241 | self.readyState = WebSocket.OPEN; 242 | self.reconnectAttempts = 0; 243 | var e = generateEvent('open'); 244 | e.isReconnect = reconnectAttempt; 245 | reconnectAttempt = false; 246 | eventTarget.dispatchEvent(e); 247 | }; 248 | 249 | ws.onclose = function(event) { 250 | clearTimeout(timeout); 251 | ws = null; 252 | if (forcedClose) { 253 | self.readyState = WebSocket.CLOSED; 254 | eventTarget.dispatchEvent(generateEvent('close')); 255 | } else { 256 | self.readyState = WebSocket.CONNECTING; 257 | var e = generateEvent('connecting'); 258 | e.code = event.code; 259 | e.reason = event.reason; 260 | e.wasClean = event.wasClean; 261 | eventTarget.dispatchEvent(e); 262 | if (!reconnectAttempt && !timedOut) { 263 | if (self.debug || ReconnectingWebSocket.debugAll) { 264 | console.debug('ReconnectingWebSocket', 'onclose', self.url); 265 | } 266 | eventTarget.dispatchEvent(generateEvent('close')); 267 | } 268 | 269 | var timeout = self.reconnectInterval * Math.pow(self.reconnectDecay, self.reconnectAttempts); 270 | setTimeout(function() { 271 | self.reconnectAttempts++; 272 | self.open(true); 273 | }, timeout > self.maxReconnectInterval ? self.maxReconnectInterval : timeout); 274 | } 275 | }; 276 | ws.onmessage = function(event) { 277 | if (self.debug || ReconnectingWebSocket.debugAll) { 278 | console.debug('ReconnectingWebSocket', 'onmessage', self.url, event.data); 279 | } 280 | var e = generateEvent('message'); 281 | e.data = event.data; 282 | eventTarget.dispatchEvent(e); 283 | }; 284 | ws.onerror = function(event) { 285 | if (self.debug || ReconnectingWebSocket.debugAll) { 286 | console.debug('ReconnectingWebSocket', 'onerror', self.url, event); 287 | } 288 | eventTarget.dispatchEvent(generateEvent('error')); 289 | }; 290 | } 291 | 292 | // Whether or not to create a websocket upon instantiation 293 | if (this.automaticOpen == true) { 294 | this.open(false); 295 | } 296 | 297 | /** 298 | * Transmits data to the server over the WebSocket connection. 299 | * 300 | * @param data a text string, ArrayBuffer or Blob to send to the server. 301 | */ 302 | this.send = function(data) { 303 | if (ws) { 304 | if (self.debug || ReconnectingWebSocket.debugAll) { 305 | console.debug('ReconnectingWebSocket', 'send', self.url, data); 306 | } 307 | return ws.send(data); 308 | } else { 309 | throw 'INVALID_STATE_ERR : Pausing to reconnect websocket'; 310 | } 311 | }; 312 | 313 | /** 314 | * Closes the WebSocket connection or connection attempt, if any. 315 | * If the connection is already CLOSED, this method does nothing. 316 | */ 317 | this.close = function(code, reason) { 318 | // Default CLOSE_NORMAL code 319 | if (typeof code == 'undefined') { 320 | code = 1000; 321 | } 322 | forcedClose = true; 323 | if (ws) { 324 | ws.close(code, reason); 325 | } 326 | }; 327 | 328 | /** 329 | * Additional public API method to refresh the connection if still open (close, re-open). 330 | * For example, if the app suspects bad data / missed heart beats, it can try to refresh. 331 | */ 332 | this.refresh = function() { 333 | if (ws) { 334 | ws.close(); 335 | } 336 | }; 337 | } 338 | 339 | /** 340 | * An event listener to be called when the WebSocket connection's readyState changes to OPEN; 341 | * this indicates that the connection is ready to send and receive data. 342 | */ 343 | ReconnectingWebSocket.prototype.onopen = function(event) {}; 344 | /** An event listener to be called when the WebSocket connection's readyState changes to CLOSED. */ 345 | ReconnectingWebSocket.prototype.onclose = function(event) {}; 346 | /** An event listener to be called when a connection begins being attempted. */ 347 | ReconnectingWebSocket.prototype.onconnecting = function(event) {}; 348 | /** An event listener to be called when a message is received from the server. */ 349 | ReconnectingWebSocket.prototype.onmessage = function(event) {}; 350 | /** An event listener to be called when an error occurs. */ 351 | ReconnectingWebSocket.prototype.onerror = function(event) {}; 352 | 353 | /** 354 | * Whether all instances of ReconnectingWebSocket should log debug messages. 355 | * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true. 356 | */ 357 | ReconnectingWebSocket.debugAll = false; 358 | 359 | ReconnectingWebSocket.CONNECTING = WebSocket.CONNECTING; 360 | ReconnectingWebSocket.OPEN = WebSocket.OPEN; 361 | ReconnectingWebSocket.CLOSING = WebSocket.CLOSING; 362 | ReconnectingWebSocket.CLOSED = WebSocket.CLOSED; 363 | 364 | return ReconnectingWebSocket; 365 | }); 366 | -------------------------------------------------------------------------------- /reconnecting-websocket.min.js: -------------------------------------------------------------------------------- 1 | !function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a}); 2 | --------------------------------------------------------------------------------