diff --git a/reconnecting-websocket.js b/reconnecting-websocket.js index a2c8974..8257421 100644 --- a/reconnecting-websocket.js +++ b/reconnecting-websocket.js @@ -1,179 +1,179 @@ -// MIT License: -// -// Copyright (c) 2010-2012, Joe Walnes -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -/** - * This behaves like a WebSocket in every way, except if it fails to connect, - * or it gets disconnected, it will repeatedly poll until it succesfully connects - * again. - * - * It is API compatible, so when you have: - * ws = new WebSocket('ws://....'); - * you can replace with: - * ws = new ReconnectingWebSocket('ws://....'); - * - * The event stream will typically look like: - * onconnecting - * onopen - * onmessage - * onmessage - * onclose // lost connection - * onconnecting - * onopen // sometime later... - * onmessage - * onmessage - * etc... - * - * It is API compatible with the standard WebSocket API. - * - * Latest version: https://github.com/joewalnes/reconnecting-websocket/ - * - Joe Walnes - */ -function ReconnectingWebSocket(url, protocols) { - protocols = protocols || []; - - // These can be altered by calling code. - this.debug = false; - this.reconnectInterval = 1000; - this.timeoutInterval = 2000; - - var self = this; - var ws; - var forcedClose = false; - var timedOut = false; - - this.url = url; - this.protocols = protocols; - this.readyState = WebSocket.CONNECTING; - this.URL = url; // Public API - - this.onopen = function(event) { - }; - - this.onclose = function(event) { - }; - - this.onconnecting = function(event) { - }; - - this.onmessage = function(event) { - }; - - this.onerror = function(event) { - }; - - function connect(reconnectAttempt) { - ws = new WebSocket(url, protocols); - - self.onconnecting(); - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'attempt-connect', url); - } - - var localWs = ws; - var timeout = setTimeout(function() { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'connection-timeout', url); - } - timedOut = true; - localWs.close(); - timedOut = false; - }, self.timeoutInterval); - - ws.onopen = function(event) { - clearTimeout(timeout); - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onopen', url); - } - self.readyState = WebSocket.OPEN; - reconnectAttempt = false; - self.onopen(event); - }; - - ws.onclose = function(event) { - clearTimeout(timeout); - ws = null; - if (forcedClose) { - self.readyState = WebSocket.CLOSED; - self.onclose(event); - } else { - self.readyState = WebSocket.CONNECTING; - self.onconnecting(); - if (!reconnectAttempt && !timedOut) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onclose', url); - } - self.onclose(event); - } - setTimeout(function() { - connect(true); - }, self.reconnectInterval); - } - }; - ws.onmessage = function(event) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onmessage', url, event.data); - } - self.onmessage(event); - }; - ws.onerror = function(event) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onerror', url, event); - } - self.onerror(event); - }; - } - connect(url); - - this.send = function(data) { - if (ws) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'send', url, data); - } - return ws.send(data); - } else { - throw 'INVALID_STATE_ERR : Pausing to reconnect websocket'; - } - }; - - this.close = function() { - if (ws) { - forcedClose = true; - ws.close(); - } - }; - - /** - * Additional public API method to refresh the connection if still open (close, re-open). - * For example, if the app suspects bad data / missed heart beats, it can try to refresh. - */ - this.refresh = function() { - if (ws) { - ws.close(); - } - }; -} - -/** - * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true. - */ -ReconnectingWebSocket.debugAll = false; - +// MIT License: +// +// Copyright (c) 2010-2012, Joe Walnes +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** + * This behaves like a WebSocket in every way, except if it fails to connect, + * or it gets disconnected, it will repeatedly poll until it succesfully connects + * again. + * + * It is API compatible, so when you have: + * ws = new WebSocket('ws://....'); + * you can replace with: + * ws = new ReconnectingWebSocket('ws://....'); + * + * The event stream will typically look like: + * onconnecting + * onopen + * onmessage + * onmessage + * onclose // lost connection + * onconnecting + * onopen // sometime later... + * onmessage + * onmessage + * etc... + * + * It is API compatible with the standard WebSocket API. + * + * Latest version: https://github.com/joewalnes/reconnecting-websocket/ + * - Joe Walnes + */ +function ReconnectingWebSocket(url, protocols) { + protocols = protocols || []; + + // These can be altered by calling code. + this.debug = false; + this.reconnectInterval = 1000; + this.timeoutInterval = 2000; + + var self = this; + var ws; + var forcedClose = false; + var timedOut = false; + + this.url = url; + this.protocols = protocols; + this.readyState = WebSocket.CONNECTING; + this.URL = url; // Public API + + this.onopen = function(event) { + }; + + this.onclose = function(event) { + }; + + this.onconnecting = function(event) { + }; + + this.onmessage = function(event) { + }; + + this.onerror = function(event) { + }; + + function connect(reconnectAttempt) { + ws = new WebSocket(url, protocols); + + self.onconnecting(); + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'attempt-connect', url); + } + + var localWs = ws; + var timeout = setTimeout(function() { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'connection-timeout', url); + } + timedOut = true; + localWs.close(); + timedOut = false; + }, self.timeoutInterval); + + ws.onopen = function(event) { + clearTimeout(timeout); + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onopen', url); + } + self.readyState = WebSocket.OPEN; + reconnectAttempt = false; + self.onopen(event); + }; + + ws.onclose = function(event) { + clearTimeout(timeout); + ws = null; + if (forcedClose) { + self.readyState = WebSocket.CLOSED; + self.onclose(event); + } else { + self.readyState = WebSocket.CONNECTING; + self.onconnecting(); + if (!reconnectAttempt && !timedOut) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onclose', url); + } + self.onclose(event); + } + setTimeout(function() { + connect(true); + }, self.reconnectInterval); + } + }; + ws.onmessage = function(event) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onmessage', url, event.data); + } + self.onmessage(event); + }; + ws.onerror = function(event) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onerror', url, event); + } + self.onerror(event); + }; + } + connect(false); + + this.send = function(data) { + if (ws) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'send', url, data); + } + return ws.send(data); + } else { + throw 'INVALID_STATE_ERR : Pausing to reconnect websocket'; + } + }; + + this.close = function() { + if (ws) { + forcedClose = true; + ws.close(); + } + }; + + /** + * Additional public API method to refresh the connection if still open (close, re-open). + * For example, if the app suspects bad data / missed heart beats, it can try to refresh. + */ + this.refresh = function() { + if (ws) { + ws.close(); + } + }; +} + +/** + * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true. + */ +ReconnectingWebSocket.debugAll = false; +