Обнаружение закрытия последнего окна/вкладки с помощью ActionCable

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

Поэтому мне нужно каким-то образом проверить каждое отключение, чтобы увидеть, есть ли у них другие активные подключения с тем же идентификатором.

Я попытался настроить проверку RemoteConnections в методе отключения. Но когда это вызывается, кажется, что закрывающееся соединение все еще возвращается в RemoteConnections.

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', current_user.username
      logger.debug self.current_user.username + " now connected."
    end

    def disconnect
      self.close()
      logger.debug ActionCable.server.remote_connections.where(current_user: current_user)
      logger.debug ActionCable.server.remote_connections.where(current_user: current_user).identifiers
      logger.debug ActionCable.server.remote_connections.where(current_user: current_user).identifiers.inspect()
    end
end

Эта настройка возвращает следующее, даже если последнее соединение, использующее этот идентификатор, закрывается:

[ActionCable] [[email protected]] UserChannel stopped streaming from user:Z2lkOi8vYWxseWNoYXQvVXNlci80Nw
[ActionCable] [[email protected]] #<ActionCable::RemoteConnections::RemoteConnection:0x00000007062690>
[ActionCable] [[email protected]] #<Set:0x00000007791b78>
[ActionCable] [[email protected]] #<Set: {:current_user}>

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

Может ли кто-нибудь предложить способ управления этим? Я просматривал документацию API для ActionCable и ничего не нашел.


person Scott W    schedule 01.06.2017    source источник


Ответы (1)


Я нашел решение для этого, которое может не сработать для всех, но, поскольку это несколько вопросов SO, открытых для этого без ответа, я подумал, что опубликую то, с чем я закончил, и, возможно, это поможет кому-то еще.

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

Я также экспериментировал с использованием Active Record для подсчета активных соединений, сохранения GIDS для их идентификации и выполнения очистки при закрытии последнего соединения. Это сработало... но я не фанат, так как он добавил массу дополнительных запросов, новую модель для отслеживания подписок и большую чувствительность к времени работы по очистке. Возможно, но некрасиво.

Вместо этого я принял концепцию «ведущего» и «ведомого», соединений, а также дополнительный пользовательский канал (управляемый моей аутентификацией пользователя). По сути, соединение, которое инициирует первую подписку, становится «основным» соединением (в моем случае — с чатом). Когда мастер присоединяется, я передаю уведомление всем другим активным окнам/вкладкам, аутентифицированным как один и тот же пользователь через UserChannel. Те, кто получает эту трансляцию, следуют основному соединению, устанавливая соединения на отдельном, но парном ведомом канале. «Главное» соединение также устанавливает соответствующее собственное «ведомое» соединение.

Поэтому для каждого чата я поддерживаю 2 канала: room_#slave и room#_master.

Все трансляции активности в чатах происходят на "ведомом" канале (поскольку он доступен для всех сессий пользователя, тогда как на мастер подписано только одно окно/вкладка). Здесь транслируются новые сообщения, выходы пользователей, входы и т. д.

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

Когда основное соединение закрывается, его метод "отписки" передает выход, обрабатывает активную очистку записи и передает сообщение всем подчиненным соединениям, чтобы этот пользователь перешел в состояние приостановки. Затем ведомые устройства могут выбрать (с помощью действия пользователя), чтобы стать новым основным соединением, и в этом случае соединение восстанавливается.

Это был лучший баланс, который я смог найти; только одно окно/вкладка учитывается для соединения с ActiveRecord. Если это окно закрыто, пользователь «ушел». Тем не менее, ведомый канал позволяет мне сохранять общее состояние для всех окон/вкладок браузера пользователя, поскольку они по-прежнему являются свидетелями всех отправленных трансляций. Если пользователь случайно закроет «главное» соединение, у него будет простой путь для повторного подключения.

person Scott W    schedule 26.06.2017