var extend = require('./utils').extend; var util = require('util'); var EventEmitter = require('events').EventEmitter; var WebSocketRouterRequest = require('./WebSocketRouterRequest'); function WebSocketRouter(config){ this.config = { server: null } ; if (config) { extend(this.config, config); } if (this.config.server) { this.attachServer(this.config.server); } this.handlers = [] ; this._requestHandler = this.handleRequest.bind(this); } 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(); 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 = _AN_Read_length("length", this.handlers); i < len; i++ ){ var handler = this.handlers[i]; if (handler.pathString === pathString && _AN_Read_protocol("protocol", handler) === protocol) { return i; } } return -1; } ; WebSocketRouter.prototype.pathToRegExp = function (path){ if (typeof (path) === 'string') { if (path === '*') { path = /^.*$/; } else { path = _AN_Call_replace('replace', path, /[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); path = new RegExp('^' + path + '$'); } } return path; } ; WebSocketRouter.prototype.handleRequest = function (request){ var requestedProtocols = request.requestedProtocols; if (_AN_Read_length('length', requestedProtocols) === 0) { requestedProtocols = ['____no_protocol____'] ; } for (var i = 0; i < _AN_Read_length('length', requestedProtocols); i++ ){ var requestedProtocol = requestedProtocols[i].toLocaleLowerCase(); for (var j = 0, len = _AN_Read_length('length', this.handlers); j < len; j++ ){ var handler = this.handlers[j]; if (handler.path.test(_AN_Read_pathname('pathname', request.resourceURL))) { if (requestedProtocol === _AN_Read_protocol('protocol', handler) || _AN_Read_protocol('protocol', handler) === '*') { var routerRequest = new WebSocketRouterRequest(request, requestedProtocol); handler.callback(routerRequest); return ; } } } } request.reject(404, "No handler is available for the given request."); } ; module.exports = WebSocketRouter;