Комнаты и онлайн-статус

Делим пользователей на группы (комнаты) и показываем, кто сейчас онлайн.

Комната (room) — именованная группа клиентов; broadcast в комнату уходит только её участникам, а не всем подряд.

Зачем комнаты

В реальном приложении бесед много: разные чаты, каналы, игровые сессии. Рассылать каждое сообщение всем подключённым нельзя — люди увидят чужое и сервер захлебнётся. Решение — комнаты: при подключении клиент указывает, в какую комнату входит, и сообщения ходят только внутри неё.

Как устроены комнаты

Сервер хранит, кто в какой комнате. Простейшая модель — словарь «комната → набор клиентов». Концептуально:

// серверная логика (для чтения)
const rooms = new Map();  // имя комнаты -> Set сокетов

function join(room, socket) {
  if (!rooms.has(room)) rooms.set(room, new Set());
  rooms.get(room).add(socket);
}

function broadcastToRoom(room, text) {
  const members = rooms.get(room) || new Set();
  for (const client of members) {
    if (client.readyState === 1) client.send(text);
  }
}

Когда приходит сообщение для комнаты general, оно уходит только её участникам.

Онлайн-статус

Кто онлайн — определяется наличием открытого соединения. При connection помечаем пользователя онлайн и рассылаем комнате событие { "type": "join", "user": ... }. При close — помечаем оффлайн и шлём { "type": "leave", "user": ... }. Клиенты обновляют список присутствующих.

{ "type": "presence", "online": ["anna", "ivan", "masha"] }

Как работает под капотом

Онлайн-статус «бесплатен» в реалтайме: само наличие живого сокета — это и есть присутствие, в отличие от HTTP, где пришлось бы постоянно опрашивать. Тонкость — один пользователь может открыть несколько вкладок (несколько сокетов). Тогда считают присутствие по пользователю, а не по сокету: оффлайн объявляют, только когда закрылась последняя вкладка. Для этого ведут счётчик соединений на пользователя.

Частые ошибки

  • Не чистить пустые комнаты. После ухода всех участников структура должна освобождаться, иначе течёт память.
  • Считать пользователя оффлайн при закрытии одной вкладки. Учитывайте все его соединения.
  • Доверять комнате из сообщения без проверки прав. Сервер должен проверять, вправе ли клиент писать в эту комнату.

Итоги

  • Комнаты делят клиентов на группы; broadcast уходит только участникам комнаты.
  • Сервер хранит соответствие «комната → клиенты» и рассылает внутри неё.
  • Онлайн-статус определяется наличием живого соединения и событиями join/leave.
  • Учитывайте несколько вкладок одного пользователя и чистите пустые комнаты.
Проверьте себя
1. Зачем нужны комнаты?
AДля шифрования сообщений
BЧтобы рассылать сообщения только участникам нужной группы, а не всем
CЧтобы ускорить рукопожатие
DЧтобы хранить историю сообщений
2. Как корректно определить, что пользователь ушёл оффлайн, если он открыл две вкладки?
AСразу при закрытии любой вкладки
BКогда закрылось последнее его соединение
CЧерез 5 минут после первого закрытия
DОнлайн-статус определить нельзя