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