Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/externals/javelin/lib/WebSocket.js
- This file was added.
| /** | |||||
| * @requires javelin-install | |||||
| * @provides javelin-websocket | |||||
| * @javelin | |||||
| */ | |||||
| /** | |||||
| * Wraps a WebSocket. | |||||
| */ | |||||
| JX.install('WebSocket', { | |||||
| construct: function(uri) { | |||||
| this.setURI(uri); | |||||
| }, | |||||
| properties: { | |||||
| URI: null, | |||||
| /** | |||||
| * Called when a connection is established or re-established after an | |||||
| * interruption. | |||||
| */ | |||||
| openHandler: null, | |||||
| /** | |||||
| * Called when a message is received. | |||||
| */ | |||||
| messageHandler: null, | |||||
| /** | |||||
| * Called when the connection is closed. | |||||
| * | |||||
| * You can return `true` to prevent the socket from reconnecting. | |||||
| */ | |||||
| closeHandler: null | |||||
| }, | |||||
| members: { | |||||
| /** | |||||
| * The underlying WebSocket. | |||||
| */ | |||||
| _socket: null, | |||||
| /** | |||||
| * Is the socket connected? | |||||
| */ | |||||
| _isOpen: false, | |||||
| /** | |||||
| * Has the caller asked us to close? | |||||
| * | |||||
| * By default, we reconnect when the connection is interrupted. | |||||
| * This stops us from reconnecting if @{method:close} was called. | |||||
| */ | |||||
| _shouldClose: false, | |||||
| /** | |||||
| * Number of milliseconds to wait after a connection failure before | |||||
| * attempting to reconnect. | |||||
| */ | |||||
| _delayUntilReconnect: null, | |||||
| /** | |||||
| * Open the connection. | |||||
| */ | |||||
| open: function() { | |||||
| if (!window.WebSocket) { | |||||
| return; | |||||
| } | |||||
| this._shouldClose = false; | |||||
| this._resetDelay(); | |||||
| this._socket = new WebSocket(this.getURI()); | |||||
| this._socket.onopen = JX.bind(this, this._onopen); | |||||
| this._socket.onmessage = JX.bind(this, this._onmessage); | |||||
| this._socket.onclose = JX.bind(this, this._onclose); | |||||
| }, | |||||
| /** | |||||
| * Send a message. | |||||
| * | |||||
| * If the connection is not currently open, this method has no effect and | |||||
| * the messages vanishes into the ether. | |||||
| */ | |||||
| send: function(message) { | |||||
| if (this._isOpen) { | |||||
| this._socket.send(message); | |||||
| } | |||||
| }, | |||||
| /** | |||||
| * Close the connection. | |||||
| */ | |||||
| close: function() { | |||||
| if (!$this._isOpen) { | |||||
| return; | |||||
| } | |||||
| this._shouldClose = true; | |||||
| this._socket.close(); | |||||
| }, | |||||
| /** | |||||
| * Callback for connection open. | |||||
| */ | |||||
| _onopen: function(e) { | |||||
| this._isOpen = true; | |||||
| // Reset the reconnect delay, since we connected successfully. | |||||
| this._resetDelay(); | |||||
| var handler = this.getOpenHandler(); | |||||
| if (handler) { | |||||
| handler(); | |||||
| } | |||||
| }, | |||||
| /** | |||||
| * Reset the reconnect delay to its base value. | |||||
| */ | |||||
| _resetDelay: function() { | |||||
| this._delayUntilReconnect = 2000; | |||||
| }, | |||||
| /** | |||||
| * Callback for message received. | |||||
| */ | |||||
| _onmessage: function(e) { | |||||
| var data = e.data; | |||||
| var handler = this.getMessageHandler(); | |||||
| if (handler) { | |||||
| handler(data); | |||||
| } | |||||
| }, | |||||
| /** | |||||
| * Callback for connection close. | |||||
| */ | |||||
| _onclose: function(e) { | |||||
| this._isOpen = false; | |||||
| var done = false; | |||||
| var handler = this.getCloseHandler(); | |||||
| if (handler) { | |||||
| done = handler(); | |||||
| } | |||||
| // If we didn't explicitly see a close() call and the close handler | |||||
| // did not return `true` to stop the reconnect, wait a little while | |||||
| // and try to reconnect. | |||||
| if (!done && !this._shouldClose) { | |||||
| setTimeout(JX.bind(this, this._reconnect), this._delayUntilReconnect); | |||||
| } | |||||
| }, | |||||
| /** | |||||
| * Reconnect an interrupted socket. | |||||
| */ | |||||
| _reconnect: function() { | |||||
| // Increase the reconnect delay by a factor of 2. If we fail to open the | |||||
| // connection, the close handler will send us back here. We'll reconnect | |||||
| // more and more slowly until we eventually get a valid connection. | |||||
| this._delayUntilReconnect = this._delayUntilReconnect * 2; | |||||
| this.open(); | |||||
| } | |||||
| } | |||||
| }); | |||||