From c7cb4d5471b3a53eae9ede6d9197f6e9e2b821b0 Mon Sep 17 00:00:00 2001 From: Darren Date: Fri, 19 Sep 2014 13:43:46 +0100 Subject: [PATCH] Kiwi client/server RPC namespaces --- client/assets/libs/engine.io.tools.js | 91 ++++++++++++++++++++++++++- client/src/app.js | 10 ++- server/websocketrpc.js | 90 +++++++++++++++++++++++++- 3 files changed, 184 insertions(+), 7 deletions(-) diff --git a/client/assets/libs/engine.io.tools.js b/client/assets/libs/engine.io.tools.js index 8758d79..4846df0 100644 --- a/client/assets/libs/engine.io.tools.js +++ b/client/assets/libs/engine.io.tools.js @@ -124,6 +124,9 @@ var EngineioTools = { ret._mixinEmitter(); ret._bindSocketListeners(); + // Keep a reference to the main Rpc object so namespaces can find calling functions + ret._rpc = ret; + return ret; } @@ -132,6 +135,10 @@ var EngineioTools = { this._next_id = 0; this._rpc_callbacks = {}; this._socket = eio_socket; + + this._rpc = this; + this._namespace = ''; + this._namespaces = []; } @@ -153,21 +160,63 @@ var EngineioTools = { delete this._onMessageProxy; } + // Clean up any namespaces + for (var idx in this._namespaces) { + this._namespaces[idx].dispose(); + } + this.removeAllListeners(); }; + WebsocketRpcCaller.prototype.namespace = function(namespace_name) { + var complete_namespace, namespace; + + if (this._namespace) { + complete_namespace = this._namespace + '.' + namespace_name; + } else { + complete_namespace = namespace_name; + } + + namespace = new this._rpc.Namespace(this._rpc, complete_namespace); + this._rpc._namespaces.push(namespace); + + return namespace; + }; + + + + // Find all namespaces that either matches or starts with namespace_name + WebsocketRpcCaller.prototype._findRelevantNamespaces = function(namespace_name) { + var found_namespaces = []; + + for(var idx in this._namespaces) { + if (this._namespaces[idx]._namespace === namespace_name) { + found_namespaces.push(this._namespaces[idx]); + } + + if (this._namespaces[idx]._namespace.indexOf(namespace_name + '.') === 0) { + found_namespaces.push(this._namespaces[idx]); + } + } + + return found_namespaces; + }; + + /** * The engine.io socket already has an emitter mixin so steal it from there */ - WebsocketRpcCaller.prototype._mixinEmitter = function() { + WebsocketRpcCaller.prototype._mixinEmitter = function(target_obj) { var funcs = ['on', 'once', 'off', 'removeListener', 'removeAllListeners', 'emit', 'listeners', 'hasListeners']; + target_obj = target_obj || this; + for (var i=0; i 0) { + namespace = packet.method.substring(0, packet.method.lastIndexOf('.')); + namespaces = this._findRelevantNamespaces(namespace); + for(idx in namespaces){ + packet.method = packet.method.replace(namespaces[idx]._namespace + '.', ''); + namespaces[idx].emit.apply(namespaces[idx], [packet.method, returnFn].concat(packet.params)); + } + } } }; @@ -299,6 +359,31 @@ var EngineioTools = { WebsocketRpcCaller.prototype._noop = function() {}; + + WebsocketRpcCaller.prototype.Namespace = function(rpc, namespace) { + var ret = function WebsocketRpcNamespaceInstance() { + if (typeof arguments[0] === 'undefined') { + return; + } + + arguments[0] = ret._namespace + '.' + arguments[0]; + return ret._rpc.apply(ret._rpc, arguments); + }; + + ret._rpc = rpc; + ret._namespace = namespace; + + ret.dispose = function() { + ret.removeAllListeners(); + ret._rpc = null; + }; + + rpc._mixinEmitter(ret); + + return ret; + }; + + return WebsocketRpc; }()) diff --git a/client/src/app.js b/client/src/app.js index f83ee83..6f95977 100644 --- a/client/src/app.js +++ b/client/src/app.js @@ -37,7 +37,15 @@ _kiwi.global = { throw 'RPC unavailable. Is Kiwi connected to the server yet?'; } - _kiwi.gateway.rpc.apply(_kiwi.gateway.rpc, arguments); + return _kiwi.gateway.rpc.apply(_kiwi.gateway.rpc, arguments); + }, + + rpcNamespace: function(namespace) { + if (!_kiwi.gateway.rpc) { + throw 'RPC unavailable. Is Kiwi connected to the server yet?'; + } + + return _kiwi.gateway.rpc.namespace(namespace); }, addMediaMessageType: function(match, buildHtml) { diff --git a/server/websocketrpc.js b/server/websocketrpc.js index 1bc8cf5..a8d287b 100644 --- a/server/websocketrpc.js +++ b/server/websocketrpc.js @@ -21,6 +21,9 @@ function WebsocketRpc(eio_socket) { ret._mixinEmitter(); ret._bindSocketListeners(); + // Keep a reference to the main Rpc object so namespaces can find calling functions + ret._rpc = ret; + return ret; } @@ -29,6 +32,10 @@ function WebsocketRpcCaller(eio_socket) { this._next_id = 0; this._rpc_callbacks = {}; this._socket = eio_socket; + + this._rpc = this; + this._namespace = ''; + this._namespaces = []; } @@ -50,21 +57,63 @@ WebsocketRpcCaller.prototype.dispose = function() { delete this._onMessageProxy; } + // Clean up any namespaces + for (var idx in this._namespaces) { + this._namespaces[idx].dispose(); + } + this.removeAllListeners(); }; +WebsocketRpcCaller.prototype.namespace = function(namespace_name) { + var complete_namespace, namespace; + + if (this._namespace) { + complete_namespace = this._namespace + '.' + namespace_name; + } else { + complete_namespace = namespace_name; + } + + namespace = new this._rpc.Namespace(this._rpc, complete_namespace); + this._rpc._namespaces.push(namespace); + + return namespace; +}; + + + +// Find all namespaces that either matches or starts with namespace_name +WebsocketRpcCaller.prototype._findRelevantNamespaces = function(namespace_name) { + var found_namespaces = []; + + for(var idx in this._namespaces) { + if (this._namespaces[idx]._namespace === namespace_name) { + found_namespaces.push(this._namespaces[idx]); + } + + if (this._namespaces[idx]._namespace.indexOf(namespace_name + '.') === 0) { + found_namespaces.push(this._namespaces[idx]); + } + } + + return found_namespaces; +}; + + /** * The engine.io socket already has an emitter mixin so steal it from there */ -WebsocketRpcCaller.prototype._mixinEmitter = function() { +WebsocketRpcCaller.prototype._mixinEmitter = function(target_obj) { var funcs = ['on', 'once', 'off', 'removeListener', 'removeAllListeners', 'emit', 'listeners', 'hasListeners']; + target_obj = target_obj || this; + for (var i=0; i 0) { + namespace = packet.method.substring(0, packet.method.lastIndexOf('.')); + namespaces = this._findRelevantNamespaces(namespace); + for(idx in namespaces){ + packet.method = packet.method.replace(namespaces[idx]._namespace + '.', ''); + namespaces[idx].emit.apply(namespaces[idx], [packet.method, returnFn].concat(packet.params)); + } + } } }; @@ -198,6 +257,31 @@ WebsocketRpcCaller.prototype._noop = function() {}; +WebsocketRpcCaller.prototype.Namespace = function(rpc, namespace) { + var ret = function WebsocketRpcNamespaceInstance() { + if (typeof arguments[0] === 'undefined') { + return; + } + + arguments[0] = ret._namespace + '.' + arguments[0]; + return ret._rpc.apply(ret._rpc, arguments); + }; + + ret._rpc = rpc; + ret._namespace = namespace; + + ret.dispose = function() { + ret.removeAllListeners(); + ret._rpc = null; + }; + + rpc._mixinEmitter(ret); + + return ret; +}; + + + // If running a node module, set the exports if (typeof module === 'object' && typeof module.exports !== 'undefined') { -- 2.25.1