namespace.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /**
  2. * socket.io
  3. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  4. * MIT Licensed
  5. */
  6. (function (exports, io) {
  7. /**
  8. * Expose constructor.
  9. */
  10. exports.SocketNamespace = SocketNamespace;
  11. /**
  12. * Socket namespace constructor.
  13. *
  14. * @constructor
  15. * @api public
  16. */
  17. function SocketNamespace (socket, name) {
  18. this.socket = socket;
  19. this.name = name || '';
  20. this.flags = {};
  21. this.json = new Flag(this, 'json');
  22. this.ackPackets = 0;
  23. this.acks = {};
  24. };
  25. /**
  26. * Apply EventEmitter mixin.
  27. */
  28. io.util.mixin(SocketNamespace, io.EventEmitter);
  29. /**
  30. * Copies emit since we override it
  31. *
  32. * @api private
  33. */
  34. SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
  35. /**
  36. * Creates a new namespace, by proxying the request to the socket. This
  37. * allows us to use the synax as we do on the server.
  38. *
  39. * @api public
  40. */
  41. SocketNamespace.prototype.of = function () {
  42. return this.socket.of.apply(this.socket, arguments);
  43. };
  44. /**
  45. * Sends a packet.
  46. *
  47. * @api private
  48. */
  49. SocketNamespace.prototype.packet = function (packet) {
  50. packet.endpoint = this.name;
  51. this.socket.packet(packet);
  52. this.flags = {};
  53. return this;
  54. };
  55. /**
  56. * Sends a message
  57. *
  58. * @api public
  59. */
  60. SocketNamespace.prototype.send = function (data, fn) {
  61. var packet = {
  62. type: this.flags.json ? 'json' : 'message'
  63. , data: data
  64. };
  65. if ('function' == typeof fn) {
  66. packet.id = ++this.ackPackets;
  67. packet.ack = true;
  68. this.acks[packet.id] = fn;
  69. }
  70. return this.packet(packet);
  71. };
  72. /**
  73. * Emits an event
  74. *
  75. * @api public
  76. */
  77. SocketNamespace.prototype.emit = function (name) {
  78. var args = Array.prototype.slice.call(arguments, 1)
  79. , lastArg = args[args.length - 1]
  80. , packet = {
  81. type: 'event'
  82. , name: name
  83. };
  84. if ('function' == typeof lastArg) {
  85. packet.id = ++this.ackPackets;
  86. packet.ack = 'data';
  87. this.acks[packet.id] = lastArg;
  88. args = args.slice(0, args.length - 1);
  89. }
  90. packet.args = args;
  91. return this.packet(packet);
  92. };
  93. /**
  94. * Disconnects the namespace
  95. *
  96. * @api private
  97. */
  98. SocketNamespace.prototype.disconnect = function () {
  99. if (this.name === '') {
  100. this.socket.disconnect();
  101. } else {
  102. this.packet({ type: 'disconnect' });
  103. this.$emit('disconnect');
  104. }
  105. return this;
  106. };
  107. /**
  108. * Handles a packet
  109. *
  110. * @api private
  111. */
  112. SocketNamespace.prototype.onPacket = function (packet) {
  113. var self = this;
  114. function ack () {
  115. self.packet({
  116. type: 'ack'
  117. , args: io.util.toArray(arguments)
  118. , ackId: packet.id
  119. });
  120. };
  121. switch (packet.type) {
  122. case 'connect':
  123. this.$emit('connect');
  124. break;
  125. case 'disconnect':
  126. if (this.name === '') {
  127. this.socket.onDisconnect(packet.reason || 'booted');
  128. } else {
  129. this.$emit('disconnect', packet.reason);
  130. }
  131. break;
  132. case 'message':
  133. case 'json':
  134. var params = ['message', packet.data];
  135. if (packet.ack == 'data') {
  136. params.push(ack);
  137. } else if (packet.ack) {
  138. this.packet({ type: 'ack', ackId: packet.id });
  139. }
  140. this.$emit.apply(this, params);
  141. break;
  142. case 'event':
  143. var params = [packet.name].concat(packet.args);
  144. if (packet.ack == 'data')
  145. params.push(ack);
  146. this.$emit.apply(this, params);
  147. break;
  148. case 'ack':
  149. if (this.acks[packet.ackId]) {
  150. this.acks[packet.ackId].apply(this, packet.args);
  151. delete this.acks[packet.ackId];
  152. }
  153. break;
  154. case 'error':
  155. if (packet.advice){
  156. this.socket.onError(packet);
  157. } else {
  158. if (packet.reason == 'unauthorized') {
  159. this.$emit('connect_failed', packet.reason);
  160. } else {
  161. this.$emit('error', packet.reason);
  162. }
  163. }
  164. break;
  165. }
  166. };
  167. /**
  168. * Flag interface.
  169. *
  170. * @api private
  171. */
  172. function Flag (nsp, name) {
  173. this.namespace = nsp;
  174. this.name = name;
  175. };
  176. /**
  177. * Send a message
  178. *
  179. * @api public
  180. */
  181. Flag.prototype.send = function () {
  182. this.namespace.flags[this.name] = true;
  183. this.namespace.send.apply(this.namespace, arguments);
  184. };
  185. /**
  186. * Emit an event
  187. *
  188. * @api public
  189. */
  190. Flag.prototype.emit = function () {
  191. this.namespace.flags[this.name] = true;
  192. this.namespace.emit.apply(this.namespace, arguments);
  193. };
  194. })(
  195. 'undefined' != typeof io ? io : module.exports
  196. , 'undefined' != typeof io ? io : module.parent.exports
  197. );