PageRenderTime 139ms CodeModel.GetById 81ms app.highlight 18ms RepoModel.GetById 22ms app.codeStats 0ms

/js/lib/Socket.IO-node/lib/socket.io/listener.js

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
JavaScript | 224 lines | 159 code | 35 blank | 30 comment | 32 complexity | 3a9fcc06ff57591c9046453296b0ed2f MD5 | raw file
  1
  2/*!
  3 * Socket.IO - Listener
  4 * Copyright (c) 2010-2011 Guillermo Rauch <guillermo@learnboost.com>
  5 * MIT Licensed
  6 */
  7
  8var EventEmitter = require('events').EventEmitter
  9  , util = require(process.binding('natives').util ? 'util' : 'sys')
 10  , clientVersion = require('./../../support/socket.io-client/lib/io').io.version
 11  , Client = require('./client')
 12  , merge = require('./utils').merge
 13  , url = require('url')
 14  , fs = require('fs')
 15  , transports = {};
 16
 17/**
 18 * Supported transports.
 19 */
 20
 21var transports = [
 22    'websocket'
 23  , 'flashsocket'
 24  , 'htmlfile'
 25  , 'xhr-multipart'
 26  , 'xhr-polling'
 27  , 'jsonp-polling'
 28];
 29
 30/**
 31 * Expose `Listener`.
 32 */
 33
 34module.exports = Listener;
 35
 36/**
 37 * Initialize a `Listener` with the given `server` and `options`.
 38 *
 39 * @param {http.Server} server
 40 * @param {Object} options
 41 * @api private
 42 */
 43
 44function Listener(server, options){
 45  var self = this;
 46  this.server = server;
 47  this.clients = this.clientsIndex = {};
 48  this._clientCount = 0;
 49  this._clientFiles = {};
 50
 51  var defaults = {
 52      origins: '*:*'
 53    , resource: 'socket.io'
 54    , flashPolicyServer: true
 55    , transports: transports
 56    , transportOptions: {}
 57    , log: util.log
 58  };
 59
 60  merge(this, merge(defaults, options || {}));
 61  this.log = this.log || function(){};
 62
 63  
 64  var listeners = this.server.listeners('request');
 65  this.server.removeAllListeners('request');
 66  
 67  this.server.on('request', function(req, res){
 68    if (self.check(req, res)) return;
 69    for (var i = 0, len = listeners.length; i < len; i++){
 70      listeners[i].call(this, req, res);
 71    }
 72  });
 73  
 74  this.server.on('upgrade', function(req, socket, head){
 75    if (!self.check(req, socket, true, head)){
 76      socket.end();
 77      socket.destroy();
 78    }
 79  });
 80  
 81  this.transports.forEach(function(name) {
 82    if (!(name in transports))
 83      transports[name] = require('./transports/' + name);
 84    if ('init' in transports[name]) transports[name].init(self);
 85  });
 86
 87  this.log('socket.io ready - accepting connections');
 88};
 89
 90/**
 91 * Inherit from `EventEmitter.prototype`.
 92 */
 93
 94Listener.prototype.__proto__ = EventEmitter.prototype;
 95
 96/**
 97 * Broadcast `message` to all clients, omitting those specified
 98 * by the `except` argument.
 99 *
100 * @param {String} message
101 * @param {String|Number|Array} except
102 * @return {Listener}
103 * @api private
104 */
105
106Listener.prototype.broadcast = function(message, except){
107  var keys = Object.keys(this.clients)
108    , len = keys.length
109    , key;
110
111  for (var i = 0; i < len; ++i){
112    key = keys[i];
113    if (except) {
114      if (Array.isArray(except) && ~except.indexOf(key)) continue;
115      else if (key == except) continue;
116    }
117    this.clients[key].send(message);
118  }
119
120  return this;
121};
122
123Listener.prototype.check = function(req, res, httpUpgrade, head){
124  var path = url.parse(req.url).pathname
125    , parts
126    , cn;
127
128  if (path && 0 === path.indexOf('/' + this.resource)){
129    parts = path.substr(2 + this.resource.length).split('/');
130    if (this._serveClient(parts.join('/'), req, res)) return true;
131    if (!(parts[0] in transports)) return false;
132    if (parts[1]){
133      cn = this.clients[parts[1]];
134      if (cn){
135        cn._onConnect(req, res);
136      } else {
137        req.connection.end();
138        req.connection.destroy();
139        this.log('Couldnt find client with session id "' + parts[1] + '"');
140      }
141    } else {
142      this._onConnection(parts[0], req, res, httpUpgrade, head);
143    }
144    return true;
145  }
146  return false;
147};
148
149Listener.prototype._serveClient = function(file, req, res){
150  var self = this
151    , clientPaths = {
152        'socket.io.js': 'socket.io.js',
153        'lib/vendor/web-socket-js/WebSocketMain.swf': 'lib/vendor/web-socket-js/WebSocketMain.swf', // for compat with old clients
154        'WebSocketMain.swf': 'lib/vendor/web-socket-js/WebSocketMain.swf'
155      }
156    , types = {
157        swf: 'application/x-shockwave-flash',
158        js: 'text/javascript'
159      };
160  
161  function write(path){
162    if (req.headers['if-none-match'] == clientVersion){
163      res.writeHead(304);
164      res.end();
165    } else {
166      res.writeHead(200, self._clientFiles[path].headers);
167      res.end(self._clientFiles[path].content, self._clientFiles[path].encoding);
168    }
169  };
170  
171  var path = clientPaths[file];
172  
173  if (req.method == 'GET' && path !== undefined){
174    if (path in this._clientFiles){
175      write(path);
176      return true;
177    }
178    
179    fs.readFile(__dirname + '/../../support/socket.io-client/' + path, function(err, data){
180      if (err){
181        res.writeHead(404);
182        res.end('404');
183      } else {
184        var ext = path.split('.').pop();
185        self._clientFiles[path] = {
186          headers: {
187            'Content-Length': data.length,
188            'Content-Type': types[ext],
189            'ETag': clientVersion
190          },
191          content: data,
192          encoding: ext == 'swf' ? 'binary' : 'utf8'
193        };
194        write(path);
195      }
196    });
197    
198    return true;
199  }
200  
201  return false;
202};
203
204Listener.prototype._onClientConnect = function(client){
205  this.clients[client.sessionId] = client;
206  this.log('Client '+ client.sessionId +' connected');
207  this.emit('clientConnect', client);
208  this.emit('connection', client);
209};
210
211Listener.prototype._onClientMessage = function(data, client){
212  this.emit('clientMessage', data, client);
213};
214
215Listener.prototype._onClientDisconnect = function(client){
216  delete this.clients[client.sessionId];
217  this.log('Client '+ client.sessionId +' disconnected');
218  this.emit('clientDisconnect', client);
219};
220
221Listener.prototype._onConnection = function(transport, req, res, httpUpgrade, head){
222  this.log('Initializing client with transport "'+ transport +'"');
223  new transports[transport](this, req, res, this.transportOptions[transport], head);
224};