PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/chat/node_modules/socket.io/lib/socket.js

https://github.com/raghunat/suny-live
JavaScript | 428 lines | 219 code | 64 blank | 145 comment | 35 complexity | 758e03a6da1e3da66ca0dbf275fc96d5 MD5 | raw file
Possible License(s): MIT, 0BSD, Apache-2.0, GPL-2.0
  1. /**
  2. * Module dependencies.
  3. */
  4. var Emitter = require('events').EventEmitter;
  5. var parser = require('socket.io-parser');
  6. var url = require('url');
  7. var debug = require('debug')('socket.io:socket');
  8. var hasBin = require('has-binary-data');
  9. /**
  10. * Module exports.
  11. */
  12. module.exports = exports = Socket;
  13. /**
  14. * Blacklisted events.
  15. *
  16. * @api public
  17. */
  18. exports.events = [
  19. 'error',
  20. 'connect',
  21. 'disconnect',
  22. 'newListener'
  23. ];
  24. /**
  25. * Flags.
  26. *
  27. * @api private
  28. */
  29. var flags = [
  30. 'json',
  31. 'volatile',
  32. 'broadcast'
  33. ];
  34. /**
  35. * `EventEmitter#emit` reference.
  36. */
  37. var emit = Emitter.prototype.emit;
  38. /**
  39. * Interface to a `Client` for a given `Namespace`.
  40. *
  41. * @param {Namespace} nsp
  42. * @param {Client} client
  43. * @api public
  44. */
  45. function Socket(nsp, client){
  46. this.nsp = nsp;
  47. this.server = nsp.server;
  48. this.adapter = this.nsp.adapter;
  49. this.id = client.id;
  50. this.request = client.request;
  51. this.client = client;
  52. this.conn = client.conn;
  53. this.rooms = [];
  54. this.acks = {};
  55. this.connected = true;
  56. this.disconnected = false;
  57. this.handshake = this.buildHandshake();
  58. }
  59. /**
  60. * Inherits from `EventEmitter`.
  61. */
  62. Socket.prototype.__proto__ = Emitter.prototype;
  63. /**
  64. * Apply flags from `Socket`.
  65. */
  66. flags.forEach(function(flag){
  67. Socket.prototype.__defineGetter__(flag, function(){
  68. this.flags = this.flags || {};
  69. this.flags[flag] = true;
  70. return this;
  71. });
  72. });
  73. /**
  74. * `request` engine.io shorcut.
  75. *
  76. * @api public
  77. */
  78. Socket.prototype.__defineGetter__('request', function(){
  79. return this.conn.request;
  80. });
  81. /**
  82. * Builds the `handshake` BC object
  83. *
  84. * @api private
  85. */
  86. Socket.prototype.buildHandshake = function(){
  87. return {
  88. headers: this.request.headers,
  89. time: (new Date) + '',
  90. address: this.request.connection.address(),
  91. xdomain: !!this.request.headers.origin,
  92. secure: !!this.request.connection.encrypted,
  93. issued: +(new Date),
  94. url: this.request.url,
  95. query: url.parse(this.request.url, true).query || {}
  96. };
  97. };
  98. /**
  99. * Emits to this client.
  100. *
  101. * @return {Socket} self
  102. * @api public
  103. */
  104. Socket.prototype.emit = function(ev){
  105. if (~exports.events.indexOf(ev)) {
  106. emit.apply(this, arguments);
  107. } else {
  108. var args = Array.prototype.slice.call(arguments);
  109. var packet = {};
  110. packet.type = hasBin(args) ? parser.BINARY_EVENT : parser.EVENT;
  111. packet.data = args;
  112. // access last argument to see if it's an ACK callback
  113. if ('function' == typeof args[args.length - 1]) {
  114. if (this._rooms || (this.flags && this.flags.broadcast)) {
  115. throw new Error('Callbacks are not supported when broadcasting');
  116. }
  117. debug('emitting packet with ack id %d', this.nsp.ids);
  118. this.acks[this.nsp.ids] = args.pop();
  119. packet.id = this.nsp.ids++;
  120. }
  121. if (this._rooms || (this.flags && this.flags.broadcast)) {
  122. this.adapter.broadcast(packet, {
  123. except: [this.id],
  124. rooms: this._rooms,
  125. flags: this.flags
  126. });
  127. } else {
  128. // dispatch packet
  129. this.packet(packet);
  130. }
  131. // reset flags
  132. delete this._rooms;
  133. delete this.flags;
  134. }
  135. return this;
  136. };
  137. /**
  138. * Targets a room when broadcasting.
  139. *
  140. * @param {String} name
  141. * @return {Socket} self
  142. * @api public
  143. */
  144. Socket.prototype.to =
  145. Socket.prototype.in = function(name){
  146. this._rooms = this._rooms || [];
  147. if (!~this._rooms.indexOf(name)) this._rooms.push(name);
  148. return this;
  149. };
  150. /**
  151. * Sends a `message` event.
  152. *
  153. * @return {Socket} self
  154. * @api public
  155. */
  156. Socket.prototype.send =
  157. Socket.prototype.write = function(){
  158. var args = Array.prototype.slice.call(arguments);
  159. args.unshift('message');
  160. this.emit.apply(this, args);
  161. return this;
  162. };
  163. /**
  164. * Writes a packet.
  165. *
  166. * @param {Object} packet object
  167. * @api private
  168. */
  169. Socket.prototype.packet = function(packet, preEncoded){
  170. packet.nsp = this.nsp.name;
  171. var volatile = this.flags && this.flags.volatile;
  172. this.client.packet(packet, preEncoded, volatile);
  173. };
  174. /**
  175. * Joins a room.
  176. *
  177. * @param {String} room
  178. * @param {Function} optional, callback
  179. * @return {Socket} self
  180. * @api private
  181. */
  182. Socket.prototype.join = function(room, fn){
  183. debug('joining room %s', room);
  184. var self = this;
  185. if (~this.rooms.indexOf(room)) return this;
  186. this.adapter.add(this.id, room, function(err){
  187. if (err) return fn && fn(err);
  188. debug('joined room %s', room);
  189. self.rooms.push(room);
  190. fn && fn(null);
  191. });
  192. return this;
  193. };
  194. /**
  195. * Leaves a room.
  196. *
  197. * @param {String} room
  198. * @param {Function} optional, callback
  199. * @return {Socket} self
  200. * @api private
  201. */
  202. Socket.prototype.leave = function(room, fn){
  203. debug('leave room %s', room);
  204. var self = this;
  205. this.adapter.del(this.id, room, function(err){
  206. if (err) return fn && fn(err);
  207. debug('left room %s', room);
  208. self.rooms.splice(self.rooms.indexOf(room, 1));
  209. fn && fn(null);
  210. });
  211. return this;
  212. };
  213. /**
  214. * Leave all rooms.
  215. *
  216. * @api private
  217. */
  218. Socket.prototype.leaveAll = function(){
  219. this.adapter.delAll(this.id);
  220. };
  221. /**
  222. * Called by `Namespace` upon succesful
  223. * middleware execution (ie: authorization).
  224. *
  225. * @api private
  226. */
  227. Socket.prototype.onconnect = function(){
  228. debug('socket connected - writing packet');
  229. this.join(this.id);
  230. this.packet({ type: parser.CONNECT });
  231. this.nsp.connected[this.id] = this;
  232. };
  233. /**
  234. * Called with each packet. Called by `Client`.
  235. *
  236. * @param {Object} packet
  237. * @api private
  238. */
  239. Socket.prototype.onpacket = function(packet){
  240. debug('got packet %j', packet);
  241. switch (packet.type) {
  242. case parser.EVENT:
  243. this.onevent(packet);
  244. break;
  245. case parser.BINARY_EVENT:
  246. this.onevent(packet);
  247. break;
  248. case parser.ACK:
  249. this.onack(packet);
  250. break;
  251. case parser.BINARY_ACK:
  252. this.onack(packet);
  253. break;
  254. case parser.DISCONNECT:
  255. this.ondisconnect();
  256. break;
  257. case parser.ERROR:
  258. this.emit('error', packet.data);
  259. }
  260. };
  261. /**
  262. * Called upon event packet.
  263. *
  264. * @param {Object} packet object
  265. * @api private
  266. */
  267. Socket.prototype.onevent = function(packet){
  268. var args = packet.data || [];
  269. debug('emitting event %j', args);
  270. if (null != packet.id) {
  271. debug('attaching ack callback to event');
  272. args.push(this.ack(packet.id));
  273. }
  274. emit.apply(this, args);
  275. };
  276. /**
  277. * Produces an ack callback to emit with an event.
  278. *
  279. * @param {Number} packet id
  280. * @api private
  281. */
  282. Socket.prototype.ack = function(id){
  283. var self = this;
  284. var sent = false;
  285. return function(){
  286. // prevent double callbacks
  287. if (sent) return;
  288. var args = Array.prototype.slice.call(arguments);
  289. debug('sending ack %j', args);
  290. var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK;
  291. self.packet({
  292. id: id,
  293. type: type,
  294. data: args
  295. });
  296. };
  297. };
  298. /**
  299. * Called upon ack packet.
  300. *
  301. * @api private
  302. */
  303. Socket.prototype.onack = function(packet){
  304. var ack = this.acks[packet.id];
  305. if ('function' == typeof ack) {
  306. debug('calling ack %s with %j', packet.id, packet.data);
  307. ack.apply(this, packet.data);
  308. delete this.acks[packet.id];
  309. } else {
  310. debug('bad ack %s', packet.id);
  311. }
  312. };
  313. /**
  314. * Called upon client disconnect packet.
  315. *
  316. * @api private
  317. */
  318. Socket.prototype.ondisconnect = function(){
  319. debug('got disconnect packet');
  320. this.onclose('client namespace disconnect');
  321. };
  322. /**
  323. * Called upon closing. Called by `Client`.
  324. *
  325. * @param {String} reason
  326. * @api private
  327. */
  328. Socket.prototype.onclose = function(reason){
  329. if (!this.connected) return this;
  330. debug('closing socket - reason %s', reason);
  331. this.leaveAll();
  332. this.nsp.remove(this);
  333. this.client.remove(this);
  334. this.connected = false;
  335. this.disconnected = true;
  336. delete this.nsp.connected[this.id];
  337. this.emit('disconnect', reason);
  338. };
  339. /**
  340. * Produces an `error` packet.
  341. *
  342. * @param {Object} error object
  343. * @api private
  344. */
  345. Socket.prototype.error = function(err){
  346. this.packet({ type: parser.ERROR, data: err });
  347. };
  348. /**
  349. * Disconnects this client.
  350. *
  351. * @param {Boolean} if `true`, closes the underlying connection
  352. * @return {Socket} self
  353. * @api public
  354. */
  355. Socket.prototype.disconnect = function(close){
  356. if (!this.connected) return this;
  357. if (close) {
  358. this.client.disconnect();
  359. } else {
  360. this.packet({ type: parser.DISCONNECT });
  361. this.onclose('server namespace disconnect');
  362. }
  363. return this;
  364. };