Created
December 4, 2015 07:46
-
-
Save minicuper/453023331194b79301c0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = Socket; | |
var BCSocket = require('browserchannel/dist/bcsocket-uncompressed').BCSocket; | |
function Socket(options) { | |
this._options = options; | |
this._messageQueue = []; | |
this._connectedOnce = false; | |
this._attemptNum = 0; | |
this._url = getWebSocketURL(options); | |
if (supportWebSockets() && !options.browserChannelOnly) { | |
this._createWebSocket(); | |
} else { | |
this._createBrowserChannel(); | |
} | |
} | |
Socket.prototype._createWebSocket = function() { | |
this._type = 'websocket'; | |
this._socket = new WebSocket(this._url); | |
this.open = this._createWebSocket.bind(this); | |
this._syncState(); | |
this._socket.onmessage = this._ws_onmessage.bind(this); | |
this._socket.onopen = this._ws_onopen.bind(this); | |
this._socket.onclose = this._ws_onclose.bind(this); | |
}; | |
Socket.prototype._createBrowserChannel = function() { | |
this._type = 'browserchannel'; | |
this._socket = BCSocket(this._options.base, this._options); | |
this.open = this._createBrowserChannel.bind(this); | |
this._syncState(); | |
this._socket.onmessage = this._bc_onmessage.bind(this); | |
this._socket.onopen = this._bc_onopen.bind(this); | |
this._socket.onclose = this._bc_onclose.bind(this); | |
}; | |
Socket.prototype._ws_onmessage = function(message) { | |
this._syncState(); | |
console.log('s->c', message.data); | |
message.data = JSON.parse(message.data); | |
this.onmessage && this.onmessage(message); | |
}; | |
Socket.prototype._ws_onopen = function(event) { | |
this._attemptNum = 0; | |
this._connectedOnce = true; | |
this._syncState(); | |
this._flushQueue(); | |
this.onopen && this.onopen(event); | |
}; | |
Socket.prototype._ws_onclose = function(event) { | |
this._syncState(); | |
console.log('WebSocket: connection is broken', event); | |
this.onclose && this.onclose(event); | |
if (!this._connectedOnce) { | |
return this._createBrowserChannel(); | |
} | |
var socket = this; | |
if (this._options.reconnect && !event.wasClean) { | |
setTimeout(function(){ | |
if (socket.readyState === socket.CLOSED) { | |
socket._createWebSocket(); | |
} | |
}, this._getTimeout()); | |
} | |
this._attemptNum++; | |
}; | |
Socket.prototype._getTimeout = function(){ | |
var base = this._options.timeout; | |
var increment = this._options.timeoutIncrement * this._attemptNum; | |
var maxTimeout = base + increment; | |
return getRandom(maxTimeout / 3, maxTimeout); | |
}; | |
Socket.prototype._bc_onmessage = function(data) { | |
this._syncState(); | |
this.onmessage && this.onmessage(data); | |
}; | |
Socket.prototype._bc_onopen = function(event) { | |
this._syncState(); | |
this.onopen && this.onopen(event); | |
}; | |
Socket.prototype._bc_onclose = function(event) { | |
this._syncState(); | |
this.onclose && this.onclose(event); | |
}; | |
Socket.prototype._flushQueue = function(){ | |
while (this._messageQueue.length !== 0) { | |
var data = this._messageQueue.shift(); | |
this._send(data); | |
} | |
}; | |
Socket.prototype._send = function(data){ | |
if (this._type === 'websocket' && (typeof data !== 'string')) data = JSON.stringify(data); | |
console.log('c->s', data); | |
this._socket.send(data); | |
}; | |
Socket.prototype.send = function(data){ | |
if (this._type === 'websocket') { | |
if (this._socket.readyState === WebSocket.OPEN && this._messageQueue.length === 0) { | |
this._send(data); | |
} else { | |
this._messageQueue.push(data); | |
} | |
} else { | |
this._send(data); | |
} | |
}; | |
Socket.prototype.close = function(){ | |
this._socket.close(); | |
}; | |
Socket.prototype._syncState = function(){ | |
this.readyState = this._socket.readyState; | |
}; | |
Socket.prototype.reconnect = function(){ | |
if (this._type === 'websocket' && this.readyState === this.CLOSED){ | |
this._createWebSocket(); | |
} | |
}; | |
// ShareJS constants | |
Socket.prototype.canSendWhileConnecting = true; | |
Socket.prototype.canSendJSON = true; | |
// WebSocket constants | |
Socket.prototype.CONNECTING = 0; | |
Socket.prototype.OPEN = 1; | |
Socket.prototype.CLOSING = 2; | |
Socket.prototype.CLOSED = 3; | |
function getRandom(min, max){ | |
return Math.random() * (max - min) + min; | |
} | |
function supportWebSockets(){ | |
// The condition is from Modernizr | |
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/websockets.js#L28 | |
return 'WebSocket' in window && window.WebSocket.CLOSING === 2; | |
} | |
function getWebSocketURL(options){ | |
var port; | |
if (window.location.port !== '') { | |
port = ":" + window.location.port; | |
} | |
var srvPort = options.srvPort; | |
var srvSecurePort = options.srvSecurePort; | |
var srvHost = options.srvHost || window.location.hostname; | |
var srvProtocol = options.srvProtocol || window.location.protocol; | |
var protocol = (srvProtocol === 'https:' ? 'wss:' : 'ws:'); | |
if (protocol === 'ws:' && srvPort) { | |
port = ":" + srvPort; | |
} else if (protocol === 'wss:' && srvSecurePort) { | |
port = ":" + srvSecurePort; | |
} | |
return protocol + '//' + srvHost + (port || "") + options.base; | |
} | |
// Maybe need to use reconnection timing algorithm from | |
// http://blog.johnryding.com/post/78544969349/how-to-reconnect-web-sockets-in-a-realtime-web-app |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment