PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/battlementjs/app/socket.js

https://bitbucket.org/FlaiseSaffron/flaisesaffron.bitbucket.org
JavaScript | 382 lines | 166 code | 74 blank | 142 comment | 20 complexity | cb9f2d5020de04a2181a24d958b7b11a MD5 | raw file
Possible License(s): GPL-3.0
  1. /*****************************************************
  2. * Installation of Battlement:
  3. * This file needs to be copied to overwrite the file
  4. * of the same name in the /lib/ folder of socket.io
  5. * because a harder-to-fix bug in the client-side
  6. * socket.io.js file prevents a feature from working
  7. * that Battlement requires that I really shouldn't
  8. * have to waste my life re-inventing.
  9. *****************************************************/
  10. /*!
  11. * socket.io-node
  12. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  13. * MIT Licensed
  14. */
  15. /**
  16. * Module dependencies.
  17. */
  18. var parser = require('./parser')
  19. , util = require('./util')
  20. , EventEmitter = process.EventEmitter
  21. /**
  22. * Export the constructor.
  23. */
  24. exports = module.exports = Socket;
  25. /**
  26. * Default error event listener to prevent uncaught exceptions.
  27. */
  28. var defaultError = function () {};
  29. /**
  30. * Socket constructor.
  31. *
  32. * @param {Manager} manager instance
  33. * @param {String} session id
  34. * @param {Namespace} namespace the socket belongs to
  35. * @param {Boolean} whether the
  36. * @api public
  37. */
  38. function Socket (manager, id, nsp, readable) {
  39. this.id = id;
  40. this.namespace = nsp;
  41. this.manager = manager;
  42. this.disconnected = false;
  43. this.ackPackets = 0;
  44. this.acks = {};
  45. this.setFlags();
  46. this.readable = readable;
  47. this.store = this.manager.store.client(this.id);
  48. this.on('error', defaultError);
  49. };
  50. /**
  51. * Inherits from EventEmitter.
  52. */
  53. Socket.prototype.__proto__ = EventEmitter.prototype;
  54. /**
  55. * Accessor shortcut for the handshake data
  56. *
  57. * @api private
  58. */
  59. Socket.prototype.__defineGetter__('handshake', function () {
  60. return this.manager.handshaken[this.id];
  61. });
  62. /**
  63. * Accessor shortcut for the transport type
  64. *
  65. * @api private
  66. */
  67. Socket.prototype.__defineGetter__('transport', function () {
  68. return this.manager.transports[this.id].name;
  69. });
  70. /**
  71. * Accessor shortcut for the logger.
  72. *
  73. * @api private
  74. */
  75. Socket.prototype.__defineGetter__('log', function () {
  76. return this.manager.log;
  77. });
  78. /**
  79. * JSON message flag.
  80. *
  81. * @api public
  82. */
  83. Socket.prototype.__defineGetter__('json', function () {
  84. this.flags.json = true;
  85. return this;
  86. });
  87. /**
  88. * Volatile message flag.
  89. *
  90. * @api public
  91. */
  92. Socket.prototype.__defineGetter__('volatile', function () {
  93. this.flags.volatile = true;
  94. return this;
  95. });
  96. /**
  97. * Broadcast message flag.
  98. *
  99. * @api public
  100. */
  101. Socket.prototype.__defineGetter__('broadcast', function () {
  102. this.flags.broadcast = true;
  103. return this;
  104. });
  105. /**
  106. * Overrides the room to broadcast messages to (flag)
  107. *
  108. * @api public
  109. */
  110. Socket.prototype.to = Socket.prototype.in = function (room) {
  111. this.flags.room = room;
  112. return this;
  113. };
  114. /**
  115. * Resets flags
  116. *
  117. * @api private
  118. */
  119. Socket.prototype.setFlags = function () {
  120. this.flags = {
  121. endpoint: this.namespace.name
  122. , room: ''
  123. };
  124. return this;
  125. };
  126. /**
  127. * Triggered on disconnect
  128. *
  129. * @api private
  130. */
  131. Socket.prototype.onDisconnect = function (reason) {
  132. if (!this.disconnected) {
  133. this.$emit('disconnect', reason);
  134. this.disconnected = true;
  135. }
  136. };
  137. /**
  138. * Joins a user to a room.
  139. *
  140. * @api public
  141. */
  142. Socket.prototype.join = function (name, fn) {
  143. var nsp = this.namespace.name
  144. , name = (nsp + '/') + name;
  145. this.manager.onJoin(this.id, name);
  146. this.manager.store.publish('join', this.id, name);
  147. if (fn) {
  148. this.log.warn('Client#join callback is deprecated');
  149. fn();
  150. }
  151. return this;
  152. };
  153. /**
  154. * Un-joins a user from a room.
  155. *
  156. * @api public
  157. */
  158. Socket.prototype.leave = function (name, fn) {
  159. var nsp = this.namespace.name
  160. , name = (nsp + '/') + name;
  161. this.manager.onLeave(this.id, name);
  162. this.manager.store.publish('leave', this.id, name);
  163. if (fn) {
  164. this.log.warn('Client#leave callback is deprecated');
  165. fn();
  166. }
  167. return this;
  168. };
  169. /**
  170. * Transmits a packet.
  171. *
  172. * @api private
  173. */
  174. Socket.prototype.packet = function (packet) {
  175. if (this.flags.broadcast) {
  176. this.log.debug('broadcasting packet');
  177. this.namespace.in(this.flags.room).except(this.id).packet(packet);
  178. } else {
  179. packet.endpoint = this.flags.endpoint;
  180. packet = parser.encodePacket(packet);
  181. this.dispatch(packet, this.flags.volatile);
  182. }
  183. this.setFlags();
  184. return this;
  185. };
  186. /**
  187. * Dispatches a packet
  188. *
  189. * @api private
  190. */
  191. Socket.prototype.dispatch = function (packet, volatile) {
  192. if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
  193. this.manager.transports[this.id].onDispatch(packet, volatile);
  194. } else {
  195. if (!volatile) {
  196. this.manager.onClientDispatch(this.id, packet, volatile);
  197. }
  198. this.manager.store.publish('dispatch:' + this.id, packet, volatile);
  199. }
  200. };
  201. /**
  202. * Stores data for the client.
  203. *
  204. * @api public
  205. */
  206. Socket.prototype.set = function (key, value, fn) {
  207. this.store.set(key, value, fn);
  208. return this;
  209. };
  210. /**
  211. * Retrieves data for the client
  212. *
  213. * @api public
  214. */
  215. Socket.prototype.get = function (key, fn) {
  216. this.store.get(key, fn);
  217. return this;
  218. };
  219. /**
  220. * Checks data for the client
  221. *
  222. * @api public
  223. */
  224. Socket.prototype.has = function (key, fn) {
  225. this.store.has(key, fn);
  226. return this;
  227. };
  228. /**
  229. * Deletes data for the client
  230. *
  231. * @api public
  232. */
  233. Socket.prototype.del = function (key, fn) {
  234. this.store.del(key, fn);
  235. return this;
  236. };
  237. /**
  238. * Kicks client
  239. *
  240. * @api public
  241. */
  242. Socket.prototype.disconnect = function () {
  243. if (!this.disconnected) {
  244. this.log.info('booting client');
  245. if ('' === this.namespace.name) {
  246. if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
  247. this.manager.transports[this.id].onForcedDisconnect();
  248. } else {
  249. this.manager.onClientDisconnect(this.id);
  250. this.manager.store.publish('disconnect:' + this.id);
  251. }
  252. } else {
  253. this.packet({type: 'disconnect'});
  254. this.manager.onLeave(this.id, this.namespace.name);
  255. this.$emit('disconnect', 'booted');
  256. }
  257. }
  258. return this;
  259. };
  260. /**
  261. * Send a message.
  262. *
  263. * @api public
  264. */
  265. Socket.prototype.send = function (data, fn) {
  266. var packet = {
  267. type: this.flags.json ? 'json' : 'message'
  268. , data: data
  269. };
  270. if (fn) {
  271. packet.id = ++this.ackPackets;
  272. packet.ack = true;
  273. this.acks[packet.id] = fn;
  274. }
  275. return this.packet(packet);
  276. };
  277. /**
  278. * Original emit function.
  279. *
  280. * @api private
  281. */
  282. Socket.prototype.$emit = EventEmitter.prototype.emit;
  283. /**
  284. * Emit override for custom events.
  285. *
  286. * @api public
  287. */
  288. Socket.prototype.emit = function (ev) {
  289. if (ev == 'newListener') {
  290. return this.$emit.apply(this, arguments);
  291. }
  292. var args = util.toArray(arguments).slice(1)
  293. , lastArg = args[args.length - 1]
  294. , packet = {
  295. type: 'event'
  296. , name: ev
  297. };
  298. if ('function' == typeof lastArg) {
  299. packet.id = ++this.ackPackets;
  300. // modification by Flaise
  301. // packet.ack = lastArg.length ? 'data' : true; // original
  302. packet.ack = 'data' // a hack to circumvent a broken conditional in the client-side code, easier than examining and fixing the entire client-side program
  303. this.acks[packet.id] = lastArg;
  304. args = args.slice(0, args.length - 1);
  305. }
  306. packet.args = args;
  307. return this.packet(packet);
  308. };