/**
* WebSocket abstraction. This, unlike the browser implementation,
* doesn't (try to) establish the connection immediately. Instead
* the method <code>open()</code> must be called.
*
* @param {!Object} options Setup options.
* @param {!string} options.address Address of the web socket server.
* @param {!string=} options.protocol Web socket protocol.
* @param {!Grape2D.utils.SynchronizedClock=} options.clock A clock, to
* to be synchronized with the clock of the server.
*
* @constructor
*/
Grape2D.WebSocket = function(options) {
options = options || {};
/**
* List of callback for the on message event.
*
* @type {!Array.<!Function>}
* @private
*/
this.onmessageCallback = [];
/**
* List of callback for the on close event.
*
* @type {!Array.<!Function>}
* @private
*/
this.oncloseCallback = [];
/**
* List of callback for the on open event.
*
* @type {!Array.<!Function>}
* @private
*/
this.onopenCallback = [];
/**
* List of callback for messages sent.
*
* @type {!Array.<!Function>}
* @private
*/
this.onsendCallback = [];
/**
* Web socket.
*
* @type {?WebSocket}
* @private
*/
this.ws = null;
/**
* Address to connect.
*
* @type {!string}
* @private
*/
this.address = options.address;
/**
* Connection's protocol.
*
* @type {(string|undefined)}
* @private
*/
this.protocol = options.protocol || undefined;
/**
* Network metrics.
*
* @type {!Grape2D.WebSocketMetrics}
* @private
*/
this.metrics = new Grape2D.WebSocketMetrics(this, options.clock || undefined);
};
Grape2D.WebSocket.prototype = {
constructor: Grape2D.WebSocket,
/**
* Sends a message to the web socket.
*
* @param {!string} msg Message to send.
* @public
*/
send: function(msg) {
if (this.isOpen()) {
this.ws.send(msg)
for (var i = 0; i < this.onsendCallback.length; i++) {
this.onsendCallback[i](msg);
}
}
},
/**
* Adds a callback for the sned event.
*
* @param {Function} callback Callback function.
* @public
*/
addOnSend: function(callback) {
this.onsendCallback.push(callback);
},
/**
* Removes a callback for the send event.
*
* @param {Function} callback Callback function.
* @public
*/
removeOnSend: function(callback) {
var idx = this.onsendCallback.indexOf(callback);
if (idx > -1) {
this.onsendCallback.splice(idx, 1);
}
},
/**
* Adds a callback for the on message event.
*
* @param {Function} callback Callback function.
* @public
*/
addOnMessage: function(callback) {
this.onmessageCallback.push(callback);
},
/**
* Removes a callback for the on message event.
*
* @param {Function} callback Callback function.
* @public
*/
removeOnMessage: function(callback) {
var idx = this.onmessageCallback.indexOf(callback);
if (idx > -1) {
this.onmessageCallback.splice(idx, 1);
}
},
/**
* Adds a callback for the on close event.
*
* @param {Function} callback Callback function.
* @public
*/
addOnClose: function(callback) {
this.oncloseCallback.push(callback);
},
/**
* Removes a callback for the on close event.
*
* @param {Function} callback Callback function.
* @public
*/
removeOnClose: function(callback) {
var idx = this.oncloseCallback.indexOf(callback);
if (idx > -1) {
this.oncloseCallback.splice(idx, 1);
}
},
/**
* Adds a callback for the on open event.
*
* @param {Function} callback Callback function.
* @public
*/
addOnOpen: function(callback) {
this.onopenCallback.push(callback);
},
/**
* Removes a callback for the on open event.
*
* @param {Function} callback Callback function.
* @public
*/
removeOnOpen: function(callback) {
var idx = this.onopenCallback.indexOf(callback);
if (idx > -1) {
this.onopenCallback.splice(idx, 1);
}
},
/**
* Closes the connection.
*
* @public
*/
close: function() {
this.ws.close();
},
/**
* Opens the connection. This method must be called, for
* the connection to be established.
*
* @public
*/
open: function() {
var that = this;
this.ws = new WebSocket(this.address, this.protocol);
this.ws.onopen = function(event) {
for (var i = 0; i < that.onopenCallback.length; i++) {
that.onopenCallback[i](event);
}
};
this.ws.onmessage = function(event) {
for (var i = 0; i < that.onmessageCallback.length; i++) {
that.onmessageCallback[i](event.data, event);
}
};
this.ws.onclose = function(event) {
for (var i = 0; i < that.oncloseCallback.length; i++) {
that.oncloseCallback[i](event);
}
};
},
/**
* Gets the metrics of this web socket.
*
* @return {!Grape2D.WebSocketMetrics} Web socket's metrics.
* @public
*/
getMetrics: function() {
return this.metrics;
},
/**
* Checks if the web socket is open.
*
* @return {!boolean} True if it's open.
* @public
*/
isOpen: function() {
return this.ws.readyState == this.ws.OPEN;
}
};