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.

146 lines
2.5 KiB

4 years ago
  1. /**
  2. * Module dependencies.
  3. */
  4. var client = require('redis').createClient;
  5. var parser = require('socket.io-parser');
  6. var msgpack = require('notepack.io');
  7. var debug = require('debug')('socket.io-emitter');
  8. /**
  9. * Module exports.
  10. */
  11. module.exports = init;
  12. /**
  13. * Flags.
  14. *
  15. * @api public
  16. */
  17. var flags = [
  18. 'json',
  19. 'volatile',
  20. 'broadcast'
  21. ];
  22. /**
  23. * uid for emitter
  24. *
  25. * @api private
  26. */
  27. var uid = 'emitter';
  28. /**
  29. * Socket.IO redis based emitter.
  30. *
  31. * @param {Object} redis client (optional)
  32. * @param {Object} options
  33. * @api public
  34. */
  35. function init(redis, opts){
  36. opts = opts || {};
  37. if ('string' == typeof redis) {
  38. redis = client(redis);
  39. }
  40. if (redis && !redis.hset) {
  41. opts = redis;
  42. redis = null;
  43. }
  44. if (!redis) {
  45. if (!opts.socket && !opts.host) throw new Error('Missing redis `host`');
  46. if (!opts.socket && !opts.port) throw new Error('Missing redis `port`');
  47. redis = opts.socket
  48. ? client(opts.socket)
  49. : client(opts.port, opts.host);
  50. }
  51. var prefix = opts.key || 'socket.io';
  52. return new Emitter(redis, prefix, '/');
  53. }
  54. function Emitter(redis, prefix, nsp){
  55. this.redis = redis;
  56. this.prefix = prefix;
  57. this.nsp = nsp;
  58. this.channel = this.prefix + '#' + nsp + '#';
  59. this._rooms = [];
  60. this._flags = {};
  61. }
  62. /**
  63. * Apply flags from `Socket`.
  64. */
  65. flags.forEach(function(flag){
  66. Emitter.prototype.__defineGetter__(flag, function(){
  67. debug('flag %s on', flag);
  68. this._flags[flag] = true;
  69. return this;
  70. });
  71. });
  72. /**
  73. * Limit emission to a certain `room`.
  74. *
  75. * @param {String} room
  76. */
  77. Emitter.prototype.in =
  78. Emitter.prototype.to = function(room){
  79. if (!~this._rooms.indexOf(room)) {
  80. debug('room %s', room);
  81. this._rooms.push(room);
  82. }
  83. return this;
  84. };
  85. /**
  86. * Return a new emitter for the given namespace.
  87. *
  88. * @param {String} namespace
  89. */
  90. Emitter.prototype.of = function(nsp){
  91. return new Emitter(this.redis, this.prefix, nsp);
  92. };
  93. /**
  94. * Send the packet.
  95. *
  96. * @api public
  97. */
  98. Emitter.prototype.emit = function(){
  99. // packet
  100. var args = Array.prototype.slice.call(arguments);
  101. var packet = { type: parser.EVENT, data: args, nsp: this.nsp };
  102. var opts = {
  103. rooms: this._rooms,
  104. flags: this._flags
  105. };
  106. var msg = msgpack.encode([uid, packet, opts]);
  107. var channel = this.channel;
  108. if (opts.rooms && opts.rooms.length === 1) {
  109. channel += opts.rooms[0] + '#';
  110. }
  111. debug('publishing message to channel %s', channel);
  112. this.redis.publish(channel, msg);
  113. // reset state
  114. this._rooms = [];
  115. this._flags = {};
  116. return this;
  117. };