Skip to content

Instantly share code, notes, and snippets.

@jhollinger
Last active April 6, 2017 17:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhollinger/f5904f3ef144a75f688f to your computer and use it in GitHub Desktop.
Save jhollinger/f5904f3ef144a75f688f to your computer and use it in GitHub Desktop.
ManagedWebSocket - WebSocket wrapper to handle auto reconnecting and event re-binding
/*
* ManagedWebSocket is a thin wrapper around WebSocket that handles automatic reconnecting and re-binding.
* If the server/network drops the connection, it will keep trying to reconnect. However, you may call
* "kill" to permanently disconnect on the client side. The native WebSocket object is available as "ws".
*
* Use "on" to bind to normal WebSocket events (open, message, error, close), and to the following custom events:
* - connecting: Fired when it is attempting to connect or reconnect.
* - drop: Fired when the connection has been dropped by the server or network. (fired before "close")
* - kill: Fired when you call "kill" on the MWS. (fired before "close")
*
* Options:
* wait: milliseconds to wait between re-connect attempts. (default 3000)
*
* Example:
* var mws = new ManagedWebSocket("ws://example.com/chat", {wait: 3000});
* mws.on('connecting', function() { console.log('Connecting...') }.
* on('open', function() { console.log('Connected') }.
* on('message', function(data) { console.log('Received ' + data) }.
* on('drop', function(data) { console.log('Connection lost') };
* mws.send(data); // Forwarded to mws.ws.send, which is the wrapped WebSocket object
*/
function ManagedWebSocket(url, options) {
if ( !options ) options = {};
this.url = url;
this.wait = options['wait'] || 3000;
this.state = ManagedWebSocket.PENDING;
this.events = {};
this._connect();
window.addEventListener('beforeunload', this.kill.bind(this));
}
// Add an event handler
ManagedWebSocket.prototype.on = function(event, callback) {
if ( !this.events[event] ) this.events[event] = new Array();
this.events[event].push(callback);
return this;
};
// Send a message through the socket
ManagedWebSocket.prototype.send = function(data) {
return this.ws.send(data);
};
// Close the socket without attempting to reconnect
ManagedWebSocket.prototype.kill = function() {
this.state = ManagedWebSocket.KILLED;
this.ws.close();
};
// Open a WebSocket connection
ManagedWebSocket.prototype._connect = function() {
if ( this.state == ManagedWebSocket.CONNECTED ) return;
if ( (this.state == ManagedWebSocket.PENDING || this.state == ManagedWebSocket.DISCONNECTED) ) this._fire('connecting');
this.state = ManagedWebSocket.CONNECTING;
this.ws = new WebSocket(this.url);
var _this = this;
this.ws.addEventListener('open', function(e) {
_this.state = ManagedWebSocket.CONNECTED;
_this._fire('open', e);
});
this.ws.addEventListener('message', function(data) {
_this._fire('message', data);
});
this.ws.addEventListener('error', function(e) {
_this._fire('error', e);
});
this.ws.addEventListener('close', function(e) {
var timeout;
if ( _this.state == ManagedWebSocket.KILLED ) {
_this._fire('kill');
}
else if ( _this.state == ManagedWebSocket.CONNECTED ) {
_this._fire('drop');
_this.state = ManagedWebSocket.DISCONNECTED;
timeout = 1000;
}
else {
timeout = _this.wait;
}
if ( timeout ) setTimeout(_this._connect.bind(_this), timeout);
_this._fire('close', e);
});
}
// Fire event handlers of a particular type, and pass an optional argument
ManagedWebSocket.prototype._fire = function(name, arg) {
if ( this.events[name] ) {
for ( var i=0; i < this.events[name].length; i++ ) {
this.events[name][i](arg);
}
}
};
ManagedWebSocket.PENDING = 0;
ManagedWebSocket.CONNECTING = 1;
ManagedWebSocket.CONNECTED = 2;
ManagedWebSocket.DISCONNECTED = 3;
ManagedWebSocket.KILLED = 4;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment