Socket.io : Как работать с аутентифицированным клиентом, который открывает два окна?

#javascript #html #socket.io

#javascript #HTML #socket.io

Вопрос:

Я кодирую игровой сервер HTML5. Сервер содержит список матчей, и когда пользователь присоединяется к одному из матчей, он может видеть ход игры, а также общаться с другими пользователями и т. Д.

Когда пользователь присоединяется к совпадению, сервер ищет в их объекте сеанса строку ‘userid’. Строка userid ссылается на пользовательский объект. Если он не найден, создается новый объект user и строка ‘userid’ добавляется к объекту сеанса.

Это позволяет пользователю подключаться к нескольким играм, используя несколько вкладок / окон, при этом отображая одно и то же имя пользователя, отображая картинку в каждом окне.

Теперь проблема заключается в том, что один и тот же пользователь подключается к одному и тому же совпадению более одного раза. Если у пользователя есть два окна, подключенных к одной и той же игре, я хочу, чтобы они видели одно и то же в обоих окнах — что-то вроде чата в Facebook.

В настоящее время, когда пользователь подключается к совпадению, создается новый объект «connection», и на этом объекте я обрабатываю события сокета и т.д.

Что я надеялся сделать, так это обработать события нескольких сокетов, используя одну и ту же функцию обработчика событий. Единственное, что меня останавливает, это то, что события сокета не имеют аргумента ‘owner’. Без ссылки на сокет, получающий сообщение, я не могу передать сообщение всем сокетам, кроме того, который получил сообщение.

Комнаты SocketIO также не соответствуют моим требованиям, потому что нет событий для сообщений, полученных по каналу.

Вместо этого я вынужден учитывать наличие как объекта подключения, так и объекта участника, где у каждого участника есть несколько подключений. Мне это кажется очень раздутым.

Другим вариантом было бы попытаться заставить себя писать с использованием спагетти-кода и использовать преимущества замыканий и т.д.

Действительно нужен совет от кого-то, кто был в подобной ситуации.

Комментарии:

1. Что вы подразумеваете под «нет событий для сообщений, полученных по каналу»? Если вы вызовете .send(‘foo’) на канале, это приведет к отправке события ‘message’ (это происходит одинаково как в пространстве имен канала, так и в пространстве имен по умолчанию). Если вам нужны пользовательские события на этом канале, я не понимаю, почему вы считаете, что прикрепить их невозможно? Ваши точные требования кажутся несколько двусмысленными, но рассматривали ли вы метод «широковещательной передачи» для разрешения «широковещательной передачи сообщения всем сокетам, за исключением того, который получил сообщение»?

Ответ №1:

Продуктовое решение: заставить пользователя использовать одно окно.

Если пользователь уже подключен и поскольку сервер знает об этом, пусть во втором окне отобразится диалоговое окно типа,

У вас уже открыто другое окно с AwesomeGame. Пожалуйста, используйте это окно или нажмите кнопку ниже.

Use this window

Если пользователь нажимает на кнопку, отправьте сообщение через SocketIO, утверждая, что это соединение является тем, которое представляет пользователя. Затем сервер уведомит все предыдущие подключения о том, что они были заменены.

Инженерное решение: предоставьте каждому клиенту токен, который они могут использовать для аутентификации на сервере с помощью SocketIO.

Когда HTML-код сгенерирован и отправлен, укажите идентификатор пользователя на странице и подпишите его секретным ключом, известным серверу. Например, наш токен выглядит следующим образом:

 <user id>|<salt>|<SHA1 hash of uid   salt   secret key>
 

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

На сервере используйте систему pubsub для подписки на открытые соединения SocketIO с идентификаторами пользователей. Если сообщение привязано к определенному пользователю, опубликуйте его с идентификатором пользователя.