Engine.io.tools file + ignoring built bundle
authorDarren <darren@darrenwhitlen.com>
Fri, 30 Aug 2013 11:08:06 +0000 (12:08 +0100)
committerDarren <darren@darrenwhitlen.com>
Sun, 1 Sep 2013 13:18:20 +0000 (14:18 +0100)
.gitignore
client/assets/libs/engine.io.tools.js [new file with mode: 0644]

index a32777db11eebcd2075ec7c646b9616981a919e2..16f2aeeec4bdf199a1a5801b3a5497adf6d7c5ff 100644 (file)
@@ -2,6 +2,7 @@
 node/node_modules/
 node_modules/
 doc/
+client/assets/libs/engine.io.bundle.*
 client/assets/kiwi.js
 client/assets/kiwi.min.js
 client/assets/locales/*.json
diff --git a/client/assets/libs/engine.io.tools.js b/client/assets/libs/engine.io.tools.js
new file mode 100644 (file)
index 0000000..47e1a15
--- /dev/null
@@ -0,0 +1,266 @@
+var EngineioTools = {
+       ReconnectingSocket: function ReconnectingSocket(server_uri, socket_options) {
+        var connected = false;
+        var is_reconnecting = false;
+
+        var reconnect_delay = 2000;
+        var reconnect_last_delay = 0;
+        var reconnect_delay_exponential = true;
+        var reconnect_max_attempts = 5;
+        var reconnect_step = 0;
+        var reconnect_tmr = null;
+
+        var original_disconnect;
+        var planned_disconnect = false;
+
+        var socket = eio.apply(eio, arguments);
+        socket.on('open', onOpen);
+        socket.on('close', onClose);
+        socket.on('error', onError);
+
+        original_disconnect = socket.close;
+        socket.close = close;
+
+        // Apply any custom reconnection config
+        if (socket_options) {
+            if (typeof socket_options.reconnect_delay === 'number')
+                reconnect_delay = socket_options.reconnect_delay;
+
+            if (typeof socket_options.reconnect_max_attempts === 'number')
+                reconnect_max_attempts = socket_options.reconnect_max_attempts;
+
+            if (typeof socket_options.reconnect_delay_exponential !== 'undefined')
+                reconnect_delay_exponential = !!socket_options.reconnect_delay_exponential;
+        }
+
+
+        function onOpen() {
+            connected = true;
+            is_reconnecting = false;
+            planned_disconnect = false;
+
+            reconnect_step = 0;
+            reconnect_last_delay = 0;
+
+            clearTimeout(reconnect_tmr);
+        }
+
+
+        function onClose() {
+            connected = false;
+
+            if (!planned_disconnect)
+                reconnect();
+        }
+
+
+        function onError() {
+            // This will be called when a reconnect fails
+            if (is_reconnecting)
+                reconnect();
+        }
+
+
+        function close() {
+            planned_disconnect = true;
+            original_disconnect.call(socket);
+        }
+
+
+        function reconnect() {
+            if (reconnect_step >= reconnect_max_attempts) {
+                socket.emit('reconnecting_failed');
+                return;
+            }
+
+            var delay = reconnect_delay_exponential ?
+                (reconnect_last_delay || reconnect_delay / 2) * 2 :
+                reconnect_delay * reconnect_step;
+
+            is_reconnecting = true;
+
+            reconnect_tmr = setTimeout(function() {
+                socket.open();
+            }, delay);
+
+            reconnect_last_delay = delay;
+
+            socket.emit('reconnecting', {
+                attempt: reconnect_step + 1,
+                max_attempts: reconnect_max_attempts,
+                delay: delay
+            });
+
+            reconnect_step++;
+        }
+
+        return socket;
+    },
+
+
+
+
+    Rpc: (function(){
+               /*
+                   Create a document explaining the protocol
+               */
+
+               function WebsocketRpc(eio_socket) {
+                   var self = this;
+
+                   this._next_id = 0;
+                   this._callbacks = {};
+                   this._socket = eio_socket;
+
+                   this._mixinEmitter();
+                   this._bindSocketListeners();
+               }
+
+
+               WebsocketRpc.prototype._bindSocketListeners = function() {
+                   var self = this;
+
+                   // Proxy the onMessage listener
+                   this._onMessageProxy = function rpcOnMessageBoundFunction(){
+                       self._onMessage.apply(self, arguments);
+                   };
+                   this._socket.on('message', this._onMessageProxy);
+               };
+
+
+
+               WebsocketRpc.prototype.dispose = function() {
+                   if (this._onMessageProxy) {
+                       this._socket.removeListener('message', this._onMessageProxy);
+                       delete this._onMessageProxy;
+                   }
+
+                   this.removeAllListeners();
+               };
+
+
+
+
+               /**
+                * The engine.io socket already has an emitter mixin so steal it from there
+                */
+               WebsocketRpc.prototype._mixinEmitter = function() {
+                   var funcs = ['on', 'once', 'off', 'removeListener', 'removeAllListeners', 'emit', 'listeners', 'hasListeners'];
+
+                   for (var i=0; i<funcs.length; i++) {
+                       if (typeof this._socket[funcs[i]] === 'function')
+                           this[funcs[i]] = this._socket[funcs[i]];
+                   }
+               };
+
+
+               /**
+                * Check if a packet is a valid RPC call
+                */
+               WebsocketRpc.prototype._isCall = function(packet) {
+                   return (typeof packet.method !== 'undefined' &&
+                           typeof packet.params !== 'undefined');
+               };
+
+
+               /**
+                * Check if a packet is a valid RPC response
+                */
+               WebsocketRpc.prototype._isResponse = function(packet) {
+                   return (typeof packet.id !== 'undefined' &&
+                           typeof packet.response !== 'undefined');
+               };
+
+
+
+               /**
+                * Make an RPC call
+                * First argument must be the method name to call
+                * If the last argument is a function, it is used as a callback
+                * All other arguments are passed to the RPC method
+                * Eg. Rpc.call('namespace.method_name', 1, 2, 3, callbackFn)
+                */
+               WebsocketRpc.prototype.call = function(method) {
+                   var params, callback, packet;
+
+                   // Get a normal array of passed in params
+                   params = Array.prototype.slice.call(arguments, 1, arguments.length);
+
+                   // If the last param is a function, take it as a callback and strip it out
+                   if (typeof params[params.length-1] === 'function') {
+                       callback = params[params.length-1];
+                       params = params.slice(0, params.length-1);
+                   }
+
+                   packet = {
+                       method: method,
+                       params: params
+                   };
+
+                   if (typeof callback === 'function') {
+                       packet.id = this._next_id;
+
+                       this._next_id++;
+                       this._callbacks[packet.id] = callback;
+                   }
+
+                   this.send(packet);
+               };
+
+
+               /**
+                * Encode the packet into JSON and send it over the websocket
+                */
+               WebsocketRpc.prototype.send = function(packet) {
+                   if (this._socket)
+                       this._socket.send(JSON.stringify(packet));
+               };
+
+
+               /**
+                * Handler for the websocket `message` event
+                */
+               WebsocketRpc.prototype._onMessage = function(message_raw) {
+                   var self = this,
+                       packet,
+                       returnFn;
+
+                   try {
+                       packet = JSON.parse(message_raw);
+                       if (!packet) throw 'Corrupt packet';
+                   } catch(err) {
+                       return;
+                   }
+
+                   if (this._isResponse(packet)) {
+                       this._callbacks[packet.id].apply(this, packet.response);
+                       delete this._callbacks[packet.id];
+
+                   } else if (this._isCall(packet)) {
+                       // Calls with an ID may be responded to
+                       if (typeof packet.id !== 'undefined') {
+                           returnFn = function returnCallFn() {
+                               var value = Array.prototype.slice.call(arguments, 0);
+
+                               var ret_packet = {
+                                   id: packet.id,
+                                   response: value
+                               };
+
+                               self.send(ret_packet);
+                           };
+
+                       } else {
+                           returnFn = function noop(){};
+                       }
+
+                       this.emit.apply(this, [packet.method, returnFn].concat(packet.params));
+                   }
+               };
+
+
+
+               return WebsocketRpc;
+
+    }())
+};