You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
5.1 KiB

7 years ago
  1. /**
  2. * Module dependencies.
  3. */
  4. var Emitter = require('events').EventEmitter;
  5. var parser = require('socket.io-parser');
  6. /**
  7. * Module exports.
  8. */
  9. module.exports = Adapter;
  10. /**
  11. * Memory adapter constructor.
  12. *
  13. * @param {Namespace} nsp
  14. * @api public
  15. */
  16. function Adapter(nsp){
  17. this.nsp = nsp;
  18. this.rooms = {};
  19. this.sids = {};
  20. this.encoder = new parser.Encoder();
  21. }
  22. /**
  23. * Inherits from `EventEmitter`.
  24. */
  25. Adapter.prototype.__proto__ = Emitter.prototype;
  26. /**
  27. * Adds a socket to a room.
  28. *
  29. * @param {String} socket id
  30. * @param {String} room name
  31. * @param {Function} callback
  32. * @api public
  33. */
  34. Adapter.prototype.add = function(id, room, fn){
  35. this.sids[id] = this.sids[id] || {};
  36. this.sids[id][room] = true;
  37. this.rooms[room] = this.rooms[room] || Room();
  38. this.rooms[room].add(id);
  39. if (fn) process.nextTick(fn.bind(null, null));
  40. };
  41. /**
  42. * Removes a socket from a room.
  43. *
  44. * @param {String} socket id
  45. * @param {String} room name
  46. * @param {Function} callback
  47. * @api public
  48. */
  49. Adapter.prototype.del = function(id, room, fn){
  50. this.sids[id] = this.sids[id] || {};
  51. delete this.sids[id][room];
  52. if (this.rooms.hasOwnProperty(room)) {
  53. this.rooms[room].del(id);
  54. if (this.rooms[room].length === 0) delete this.rooms[room];
  55. }
  56. if (fn) process.nextTick(fn.bind(null, null));
  57. };
  58. /**
  59. * Removes a socket from all rooms it's joined.
  60. *
  61. * @param {String} socket id
  62. * @param {Function} callback
  63. * @api public
  64. */
  65. Adapter.prototype.delAll = function(id, fn){
  66. var rooms = this.sids[id];
  67. if (rooms) {
  68. for (var room in rooms) {
  69. if (this.rooms.hasOwnProperty(room)) {
  70. this.rooms[room].del(id);
  71. if (this.rooms[room].length === 0) delete this.rooms[room];
  72. }
  73. }
  74. }
  75. delete this.sids[id];
  76. if (fn) process.nextTick(fn.bind(null, null));
  77. };
  78. /**
  79. * Broadcasts a packet.
  80. *
  81. * Options:
  82. * - `flags` {Object} flags for this packet
  83. * - `except` {Array} sids that should be excluded
  84. * - `rooms` {Array} list of rooms to broadcast to
  85. *
  86. * @param {Object} packet object
  87. * @api public
  88. */
  89. Adapter.prototype.broadcast = function(packet, opts){
  90. var rooms = opts.rooms || [];
  91. var except = opts.except || [];
  92. var flags = opts.flags || {};
  93. var packetOpts = {
  94. preEncoded: true,
  95. volatile: flags.volatile,
  96. compress: flags.compress
  97. };
  98. var ids = {};
  99. var self = this;
  100. var socket;
  101. packet.nsp = this.nsp.name;
  102. this.encoder.encode(packet, function(encodedPackets) {
  103. if (rooms.length) {
  104. for (var i = 0; i < rooms.length; i++) {
  105. var room = self.rooms[rooms[i]];
  106. if (!room) continue;
  107. var sockets = room.sockets;
  108. for (var id in sockets) {
  109. if (sockets.hasOwnProperty(id)) {
  110. if (ids[id] || ~except.indexOf(id)) continue;
  111. socket = self.nsp.connected[id];
  112. if (socket) {
  113. socket.packet(encodedPackets, packetOpts);
  114. ids[id] = true;
  115. }
  116. }
  117. }
  118. }
  119. } else {
  120. for (var id in self.sids) {
  121. if (self.sids.hasOwnProperty(id)) {
  122. if (~except.indexOf(id)) continue;
  123. socket = self.nsp.connected[id];
  124. if (socket) socket.packet(encodedPackets, packetOpts);
  125. }
  126. }
  127. }
  128. });
  129. };
  130. /**
  131. * Gets a list of clients by sid.
  132. *
  133. * @param {Array} explicit set of rooms to check.
  134. * @param {Function} callback
  135. * @api public
  136. */
  137. Adapter.prototype.clients = function(rooms, fn){
  138. if ('function' == typeof rooms){
  139. fn = rooms;
  140. rooms = null;
  141. }
  142. rooms = rooms || [];
  143. var ids = {};
  144. var self = this;
  145. var sids = [];
  146. var socket;
  147. if (rooms.length) {
  148. for (var i = 0; i < rooms.length; i++) {
  149. var room = self.rooms[rooms[i]];
  150. if (!room) continue;
  151. var sockets = room.sockets;
  152. for (var id in sockets) {
  153. if (sockets.hasOwnProperty(id)) {
  154. if (ids[id]) continue;
  155. socket = self.nsp.connected[id];
  156. if (socket) {
  157. sids.push(id);
  158. ids[id] = true;
  159. }
  160. }
  161. }
  162. }
  163. } else {
  164. for (var id in self.sids) {
  165. if (self.sids.hasOwnProperty(id)) {
  166. socket = self.nsp.connected[id];
  167. if (socket) sids.push(id);
  168. }
  169. }
  170. }
  171. if (fn) process.nextTick(fn.bind(null, null, sids));
  172. };
  173. /**
  174. * Gets the list of rooms a given client has joined.
  175. *
  176. * @param {String} socket id
  177. * @param {Function} callback
  178. * @api public
  179. */
  180. Adapter.prototype.clientRooms = function(id, fn){
  181. var rooms = this.sids[id];
  182. if (fn) process.nextTick(fn.bind(null, null, rooms ? Object.keys(rooms) : null));
  183. };
  184. /**
  185. * Room constructor.
  186. *
  187. * @api private
  188. */
  189. function Room(){
  190. if (!(this instanceof Room)) return new Room();
  191. this.sockets = {};
  192. this.length = 0;
  193. }
  194. /**
  195. * Adds a socket to a room.
  196. *
  197. * @param {String} socket id
  198. * @api private
  199. */
  200. Room.prototype.add = function(id){
  201. if (!this.sockets.hasOwnProperty(id)) {
  202. this.sockets[id] = true;
  203. this.length++;
  204. }
  205. };
  206. /**
  207. * Removes a socket from a room.
  208. *
  209. * @param {String} socket id
  210. * @api private
  211. */
  212. Room.prototype.del = function(id){
  213. if (this.sockets.hasOwnProperty(id)) {
  214. delete this.sockets[id];
  215. this.length--;
  216. }
  217. };