Socket.io: Как подсчитать клиентов в комнате с адаптером Socket.io-redis

Я начинаю создавать чат-сервер, используя Socket.io с несколькими узлами. Он использует Socket.io-redis для соединения всех серверов и rooms для обмена сообщениями.

Когда клиент подключается к серверу, я присоединяюсь к клиенту в какой-то комнате.

io.on('connection', function(socket){
  socket.join("CLIENT_1");
});

Итак, я хочу, чтобы количество клиентов было подключено к комнате "CLIENT_1",

io.sockets.adapter.rooms["CLIENT_1"];

но я получаю только соединение из текущего процесса. Как я могу получить соединение со всеми серверными процессами, подключенными через адаптер redis?

Я рассмотрел этот вопрос:

Как проверить, что сокет жив (подключен) в socket.io с несколькими узлами и socket.io-redis

но это мне не помогло.

Спасибо за продвижение.

Ответ 1

На момент написания этой статьи:

Адаптер redis расширяет базовый адаптер, но он только переопределяет/добавляет следующие свойства:

  • onmessage
  • broadcast
  • add
  • del
  • delAll

С помощью этого кода:

io.sockets.adapter.rooms["CLIENT_1"];

вы запрашиваете свойство rooms. Это не было отменено адаптером redis, поэтому вы действительно запрашиваете базовый адаптер, который знает только о комнатах/клиентах в текущем процессе.

Почему адаптер redis не переопределил свойство rooms? Поскольку для соответствия точной сигнатуре вызова выше, он должен будет запросить экземпляр redis для построения объекта, содержащего все комнаты и соединения, каждый раз, когда к нему обращаются свойства. Нехорошо. (То есть, если вы не можете выяснить, как вычислить значения объектов во время запроса их значений.)

Если вы хотите получить количество подключений к "CLIENT_1" для всех процессов в кластере, вам придется добавить эту функциональность в самого адаптера с помощью такого метода:

/**
   * Count the number of connections in a room.
   *
   * @param {String} room id
   * @param {Function} callback (optional)
   * @api public
   */

  Redis.prototype.numClients = function(room, fn){ ... }

в котором вы будете запрашивать экземпляр redis db.

IMO, это должно быть частью интерфейса базового адаптера для всех других адаптеров для реализации. Это общая проблема.

Ответ 2

Этот метод отлично работает:

io.sockets.adapter.clients(["room1"], function(err, clients){
  console.log("total clients in room1: %d", clients.length);
})

Ответ 3

другой подход заключается в использовании методов customRequest/customHook в socket.io-redis 3.1.0. Я пробовал и работает. Подробности здесь. https://github.com/socketio/socket.io-redis/issues/137