diff options
| author | Arjun Roychowdhury <pliablepixels@gmail.com> | 2015-10-06 16:57:33 -0400 |
|---|---|---|
| committer | Arjun Roychowdhury <pliablepixels@gmail.com> | 2015-10-06 16:57:33 -0400 |
| commit | dd8d072fdae253c611e8ca3ff9ed8d92f0d4483a (patch) | |
| tree | 696d990d460f00dd8969a226138e8f505207602c | |
| parent | b4e1f72cfc6f38046bb3afce3eb12664251c1c94 (diff) | |
ng-websockets with patch for reconnect exponential issue
| -rw-r--r-- | www/external/ng-websocket.js | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/www/external/ng-websocket.js b/www/external/ng-websocket.js new file mode 100644 index 00000000..8354eb2f --- /dev/null +++ b/www/external/ng-websocket.js @@ -0,0 +1,371 @@ +'use strict'; + +(function () { + /** + * @ngdoc provider + * @name $websocketProvider + * @module ngWebsocket + * @description + * HTML5 WebSocket provider for AngularJS + */ + function $websocketProvider () { + var wsp = this; + + wsp.$$config = { + lazy: false, + reconnect: true, + reconnectInterval: 2000, + mock: false, + enqueue: false, + protocols: null + }; + + wsp.$setup = function (cfg) { + cfg = cfg || {}; + wsp.$$config = angular.extend({}, wsp.$$config, cfg); + + return wsp; + }; + + wsp.$get = ['$http', function ($http) { + return new $websocketService(wsp.$$config, $http); + }]; + } + + /** + * @ngdoc service + * @name $websocketService + * @module ngWebsocketService + * @description + * HTML5 Websocket service for AngularJS + */ + function $websocketService (cfg, $http) { + var wss = this; + + wss.$$websocketList = {}; + wss.$$config = cfg || {}; + + wss.$get = function (url) { + return wss.$$websocketList[url]; + }; + + wss.$new = function (cfg) { + cfg = cfg || {}; + + // Url or url + protocols initialization + if (typeof cfg === 'string') { + cfg = {url: cfg}; + + // url + protocols + if (arguments.length > 1) { + if (typeof arguments[1] === 'string' && arguments[1].length > 0) cfg.protocols = [arguments[1]]; + else if (typeof arguments[1] === 'object' && arguments[1].length > 0) cfg.protocols = arguments[1]; + } + } + + // If the websocket already exists, return that instance + var ws = wss.$get(cfg.url); + if (typeof ws === 'undefined') { + var wsCfg = angular.extend({}, wss.$$config, cfg); + + ws = new $websocket(wsCfg, $http); + wss.$$websocketList[wsCfg.url] = ws; + } + + return ws; + }; + } + + /** + * @ngdoc class + * @name $websocket + * @module ngWebsocket + * @description + * HTML5 Websocket wrapper class for AngularJS + */ + function $websocket (cfg, $http) { + var me = this; + + if (typeof cfg === 'undefined' || (typeof cfg === 'object' && typeof cfg.url === 'undefined')) throw new Error('An url must be specified for WebSocket'); + + me.$$eventMap = {}; + me.$$ws = undefined; + me.$$reconnectTask = undefined; + me.$$reconnectCopy = true; + me.$$queue = []; + me.$$config = { + url: undefined, + lazy: false, + reconnect: true, + reconnectInterval: 2000, + enqueue: false, + mock: false, + protocols: null + }; + + me.$$fireEvent = function () { + var args = []; + + Array.prototype.push.apply(args, arguments); + + var event = args.shift(), + handlers = me.$$eventMap[event]; + + if (typeof handlers !== 'undefined') { + for (var i = 0; i < handlers.length; i++) { + if (typeof handlers[i] === 'function') handlers[i].apply(me, args); + } + } + }; + + me.$$init = function (cfg) { + me.$$ws = cfg.mock ? new $$mockWebsocket(cfg.mock, $http) : new WebSocket(cfg.url, cfg.protocols); + + me.$$ws.onmessage = function (message) { + try { + var decoded = JSON.parse(message.data); + me.$$fireEvent(decoded.event, decoded.data); + me.$$fireEvent('$message', decoded); + } + catch (err) { + me.$$fireEvent('$message', message.data); + } + }; + + me.$$ws.onerror = function (error) { + me.$$fireEvent('$error', error); + }; + + me.$$ws.onopen = function () { + // Clear the reconnect task if exists + if (me.$$reconnectTask) { + clearInterval(me.$$reconnectTask); + delete me.$$reconnectTask; + } + + // Flush the message queue + if (me.$$config.enqueue && me.$$queue.length > 0) { + while (me.$$queue.length > 0) { + if (me.$ready()) me.$$send(me.$$queue.shift()); + else break; + } + } + + me.$$fireEvent('$open'); + }; + + me.$$ws.onclose = function () { + // Activate the reconnect task + // PP https://github.com/cdupetit/ng-websocket/commit/bec0d2c56316871758fcd0e33cb55904efb877f1 + if (me.$$config.reconnect && !me.$$reconnectTask) { + me.$$reconnectTask = setInterval(function () { + if (me.$status() === me.$CLOSED) me.$open(); + }, me.$$config.reconnectInterval); + } + + me.$$fireEvent('$close'); + }; + + return me; + }; + + me.$CONNECTING = 0; + me.$OPEN = 1; + me.$CLOSING = 2; + me.$CLOSED = 3; + + // TODO: it doesn't refresh the view (maybe $apply on something?) + /*me.$bind = function (event, scope, model) { + me.$on(event, function (message) { + model = message; + scope.$apply(); + }); + };*/ + + me.$on = function () { + var handlers = []; + + Array.prototype.push.apply(handlers, arguments); + + var event = handlers.shift(); + if (typeof event !== 'string' || handlers.length === 0) throw new Error('$on accept two parameters at least: a String and a Function or an array of Functions'); + + me.$$eventMap[event] = me.$$eventMap[event] || []; + for (var i = 0; i < handlers.length; i++) { + me.$$eventMap[event].push(handlers[i]); + } + + return me; + }; + + me.$un = function (event) { + if (typeof event !== 'string') throw new Error('$un needs a String representing an event.'); + + if (typeof me.$$eventMap[event] !== 'undefined') delete me.$$eventMap[event]; + + return me; + }; + + me.$$send = function (message) { + if (me.$ready()) me.$$ws.send(JSON.stringify(message)); + else if (me.$$config.enqueue) me.$$queue.push(message); + }; + + me.$emit = function (event, data) { + if (typeof event !== 'string') throw new Error('$emit needs two parameter: a String and a Object or a String'); + + var message = { + event: event, + data: data + }; + + me.$$send(message); + + return me; + }; + + me.$open = function () { + me.$$config.reconnect = me.$$reconnectCopy; + + if (me.$status() !== me.$OPEN) me.$$init(me.$$config); + return me; + }; + + me.$close = function () { + if (me.$status() !== me.$CLOSED) me.$$ws.close(); + + if (me.$$reconnectTask) { + clearInterval(me.$$reconnectTask); + delete me.$$reconnectTask; + } + + me.$$config.reconnect = false; + + return me; + }; + + me.$status = function () { + if (typeof me.$$ws === 'undefined') return me.$CLOSED; + else return me.$$ws.readyState; + }; + + me.$ready = function () { + return me.$status() === me.$OPEN; + }; + + me.$mockup = function () { + return me.$$config.mock; + }; + + // setup + me.$$config = angular.extend({}, me.$$config, cfg); + me.$$reconnectCopy = me.$$config.reconnect; + + if (!me.$$config.lazy) me.$$init(me.$$config); + + return me; + } + + function $$mockWebsocket (cfg, $http) { + cfg = cfg || {}; + + var me = this, + openTimeout = cfg.openTimeout || 500, + closeTimeout = cfg.closeTimeout || 1000, + messageInterval = cfg.messageInterval || 2000, + fixtures = cfg.fixtures || {}, + messageQueue = []; + + me.CONNECTING = 0; + me.OPEN = 1; + me.CLOSING = 2; + me.CLOSED = 3; + + me.readyState = me.CONNECTING; + + me.send = function (message) { + if (me.readyState === me.OPEN) { + messageQueue.push(message); + return me; + } + else throw new Error('WebSocket is already in CLOSING or CLOSED state.'); + }; + + me.close = function () { + if (me.readyState === me.OPEN) { + me.readyState = me.CLOSING; + + setTimeout(function () { + me.readyState = me.CLOSED; + + me.onclose(); + }, closeTimeout); + } + + return me; + }; + + me.onmessage = function () {}; + me.onerror = function () {}; + me.onopen = function () {}; + me.onclose = function () {}; + + setInterval(function () { + if (messageQueue.length > 0) { + var message = messageQueue.shift(), + msgObj = JSON.parse(message); + + switch (msgObj.event) { + case '$close': + me.close(); + break; + default: + // Check for a custom response + if (typeof fixtures[msgObj.event] !== 'undefined') { + msgObj.data = fixtures[msgObj.event].data || msgObj.data; + msgObj.event = fixtures[msgObj.event].event || msgObj.event; + } + + message = JSON.stringify(msgObj); + + me.onmessage({ + data: message + }); + } + } + }, messageInterval); + + var start = function (fixs) { + fixs = fixs || {}; + fixs = fixs instanceof Error ? {} : fixs; + + fixtures = fixs; + + setTimeout(function () { + me.readyState = me.OPEN; + me.onopen(); + }, openTimeout); + }; + + // Get fixtures from a server or a file if it's a string + if (typeof fixtures === 'string') { + $http.get(fixtures) + .success(start) + .error(start); + } + else start(fixtures); + + return me; + } + + /** + * @ngdoc module + * @name $websocket + * @module ngWebsocket + * @description + * HTML5 WebSocket module for AngularJS + */ + angular + .module('ngWebsocket', []) + .provider('$websocket', $websocketProvider); +})(); |
