Websocket
[VSoRC/.git] / node_modules / websocket / lib / WebSocketRouter.js
diff --git a/node_modules/websocket/lib/WebSocketRouter.js b/node_modules/websocket/lib/WebSocketRouter.js
new file mode 100644 (file)
index 0000000..35bced9
--- /dev/null
@@ -0,0 +1,157 @@
+/************************************************************************
+ *  Copyright 2010-2015 Brian McKelvey.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ ***********************************************************************/
+
+var extend = require('./utils').extend;
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var WebSocketRouterRequest = require('./WebSocketRouterRequest');
+
+function WebSocketRouter(config) {
+    // Superclass Constructor
+    EventEmitter.call(this);
+
+    this.config = {
+        // The WebSocketServer instance to attach to.
+        server: null
+    };
+    if (config) {
+        extend(this.config, config);
+    }
+    this.handlers = [];
+
+    this._requestHandler = this.handleRequest.bind(this);
+    if (this.config.server) {
+        this.attachServer(this.config.server);
+    }
+}
+
+util.inherits(WebSocketRouter, EventEmitter);
+
+WebSocketRouter.prototype.attachServer = function(server) {
+    if (server) {
+        this.server = server;
+        this.server.on('request', this._requestHandler);
+    }
+    else {
+        throw new Error('You must specify a WebSocketServer instance to attach to.');
+    }
+};
+
+WebSocketRouter.prototype.detachServer = function() {
+    if (this.server) {
+        this.server.removeListener('request', this._requestHandler);
+        this.server = null;
+    }
+    else {
+        throw new Error('Cannot detach from server: not attached.');
+    }
+};
+
+WebSocketRouter.prototype.mount = function(path, protocol, callback) {
+    if (!path) {
+        throw new Error('You must specify a path for this handler.');
+    }
+    if (!protocol) {
+        protocol = '____no_protocol____';
+    }
+    if (!callback) {
+        throw new Error('You must specify a callback for this handler.');
+    }
+
+    path = this.pathToRegExp(path);
+    if (!(path instanceof RegExp)) {
+        throw new Error('Path must be specified as either a string or a RegExp.');
+    }
+    var pathString = path.toString();
+
+    // normalize protocol to lower-case
+    protocol = protocol.toLocaleLowerCase();
+
+    if (this.findHandlerIndex(pathString, protocol) !== -1) {
+        throw new Error('You may only mount one handler per path/protocol combination.');
+    }
+
+    this.handlers.push({
+        'path': path,
+        'pathString': pathString,
+        'protocol': protocol,
+        'callback': callback
+    });
+};
+WebSocketRouter.prototype.unmount = function(path, protocol) {
+    var index = this.findHandlerIndex(this.pathToRegExp(path).toString(), protocol);
+    if (index !== -1) {
+        this.handlers.splice(index, 1);
+    }
+    else {
+        throw new Error('Unable to find a route matching the specified path and protocol.');
+    }
+};
+
+WebSocketRouter.prototype.findHandlerIndex = function(pathString, protocol) {
+    protocol = protocol.toLocaleLowerCase();
+    for (var i=0, len=this.handlers.length; i < len; i++) {
+        var handler = this.handlers[i];
+        if (handler.pathString === pathString && handler.protocol === protocol) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+WebSocketRouter.prototype.pathToRegExp = function(path) {
+    if (typeof(path) === 'string') {
+        if (path === '*') {
+            path = /^.*$/;
+        }
+        else {
+            path = path.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+            path = new RegExp('^' + path + '$');
+        }
+    }
+    return path;
+};
+
+WebSocketRouter.prototype.handleRequest = function(request) {
+    var requestedProtocols = request.requestedProtocols;
+    if (requestedProtocols.length === 0) {
+        requestedProtocols = ['____no_protocol____'];
+    }
+
+    // Find a handler with the first requested protocol first
+    for (var i=0; i < requestedProtocols.length; i++) {
+        var requestedProtocol = requestedProtocols[i].toLocaleLowerCase();
+
+        // find the first handler that can process this request
+        for (var j=0, len=this.handlers.length; j < len; j++) {
+            var handler = this.handlers[j];
+            if (handler.path.test(request.resourceURL.pathname)) {
+                if (requestedProtocol === handler.protocol ||
+                    handler.protocol === '*')
+                {
+                    var routerRequest = new WebSocketRouterRequest(request, requestedProtocol);
+                    handler.callback(routerRequest);
+                    return;
+                }
+            }
+        }
+    }
+
+    // If we get here we were unable to find a suitable handler.
+    request.reject(404, 'No handler is available for the given request.');
+};
+
+module.exports = WebSocketRouter;