Rails 5 ActionCable Настройка и рабочий процесс

Я новичок в ActionCable и сокетах и ​​пытаюсь реализовать некоторые функции в реальном времени.

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

Мой код уведомлений в реальном времени:

Процесс аутентификации:

# Connection.rb (using Devise)
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = env['warden'].user
      reject_unauthorized_connection unless self.current_user

      logger.add_tags 'ActionCable', current_user.email
    end

  end
end

Канал уведомления:

class NotificationsChannel < ApplicationCable::Channel
  def subscribed
    stream_from "notification_channel_#{current_user.id}"
  end

  def unsubscribed
  end
end

Уведомления. Кофе

App.notifications = App.cable.subscriptions.create "NotificationsChannel",
  connected: ->

  disconnected: ->

  received: (data) ->
    this.update_counter(data.counter)

    # if use_sound is "true" play a mp3 sound
    # use_sound is sent ("true" or "false") because when a notification is destroyed we don't want to use sound only update counter  

    if data.use_sound == "true"
      $("#sound-play").get(0).play()

  # Update Notifications Counter and change color

  update_counter: (counter) ->
    $("#notifications-counter").html("#{counter}")

    if counter > 0
      $("#notifications-counter").css('color','#FFA5A5')
    else
      $("#notifications-counter").css('color','white')

И есть файл Job, который мы транслируем на канал со счетчиком уведомлений.

Примечание. Я отправляю только количество уведомлений, потому что на панели навигации, когда пользователь нажимает кнопку (например, 2 Уведомления), раскрывающийся список переключается и заполняется с помощью вызова AJax.

Мои вопросы:

  1. Нормально ли постоянно иметь запросы «GET / cable» с ответом «Попытка несанкционированного подключения отклонена», когда пользователь не вошел в систему (я понимаю, что current_user в файле Connect.rb устанавливается из файла cookie, но когда пользователь находится на бывшей домашней странице, странице входа в систему и т. д. в основном не аутентифицирован.

    В журналах сервера каждые 1,2 секунды я вижу GET / cable  введите описание изображения здесь

    Это нормально? Я думаю, что мне нужно как-то это остановить, если пользователь выйдет из системы или что-то в этом роде.

  2. Когда я запускаю сервер, я получаю следующую ошибку примерно за 10 секунд, пока сервер не запустится в консоли браузера. Поскольку уведомления работают, я не знаю, проблема ли это, но это ошибка.

    Соединение WebSocket с 'ws: // localhost: 3000 / cable' не удалось: ошибка при установлении соединения: net :: ERR_CONNECTION_REFUSED

    Я даже попытался установить config.action_cable.mount_path = "/ cable" или "ws: // localhost: 3000 / cable", но не исправил.

  3. Затем я хочу реализовать чат, где 2 пользователя могут вести частный разговор, это «current_user», определенный в Connection.rb «secure», как я могу добавить авторизацию в ActionCable или что-то в этом роде. В остальной части своего приложения я использую CanCan Gem и отлично работает.

Большое спасибо за время, потраченное на чтение вопроса. Если у вас есть ответы на мои вопросы, я буду очень признателен. И если у вас есть какие-то направления или советы по созданию сложного и безопасного чата с ActionCable, я хотел бы их услышать. Спасибо!


person Rares R    schedule 22.04.2017    source источник


Ответы (1)


Я думаю, что вы хотите посмотреть файл cable.js, в котором вызывается функция createConsumer.

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

Вы используете аутентификацию пользователя, чтобы отклонить несанкционированное использование.

Это очень хорошо, но не так хорошо, когда потребитель JS создается для любого посетителя (т.е. cable.js загружается в application.js для всех страниц).

Что вы можете сделать, так это использовать content_for в отдельном макете для аутентифицированных пользователей, который вызывает cable.js для создания потребителя и гарантирует, что cable.js не попадет на неавторизованные страницы.

person fbelanger    schedule 22.04.2017
comment
Эта великолепная идея! В моем приложении несколько макетов, мы точно знаем, в каком макете он зарегистрирован. Прежде чем прочитать ваш ответ, я подумал о следующем решении, обратите внимание, что я действительно не знаю, является ли это решением. Что, если мы установим timeOut и вызовем выполнить 'unfollow' где-нибудь в js, если, например, $ ('notification-counter-id') нет, а на стороне сервера метода unfollow мы делаем stop_all_streams. Я не уверен, сможем ли мы вызвать выполнение 'unfollow', если мы отклоним current_user, потому что он не аутентифицирован. И не уверен, когда вызывать «отменить подписку», а когда делать stop_all_streams в коде. - person Rares R; 22.04.2017
comment
Отказ от подписки похож на занесение в черный список. В процессе все сначала включаются, а затем отказываются от участия. Я думаю, что другой подход менее сложен и надежен, потому что только зарегистрированные пользователи получат потребителя и, если это будет сделано вручную, все равно отклонят их. Если бы вы использовали подход отмены подписки, то часть отказа была бы направлена ​​на трансляцию отмены подписки, создание действия канала и кода для потребителя. - person fbelanger; 22.04.2017
comment
Вы определенно правы. Еще одна вещь, чтобы я мог лучше понять ActionCable. Сценарий для моего приложения, когда пользователь не вошел в систему, следующий: Пользователь находится на локальном хосте, потому что мы включаем кабель в application.rb, он пытается подписаться через createCustomer, и вот чего я не понимаю, createCustomer вызывает функцию 'follow' в NotificationsChannel, чтобы подписаться на него, верно? Я проверил пример DHH ActionCable, и мы вызвали @performe для каждой «комнаты чата», это логично, потому что мы хотим остановить все потоки, если мы изменим комнату, а затем перейдем в новую комнату. Извините, если я плохо выразился. :) - person Rares R; 22.04.2017
comment
Я считаю, что createConsumer вызывает ApplicationCable::Connection для настройки и сохранения веб-сокета. Как только веб-сокет установлен, JS для NotficationsChannel будет подчиняться определенному потоку. Канал будет знать о сокетах, на которые подписаны, и будет нажимать на эти веб-сокеты. - person fbelanger; 22.04.2017
comment
Я прочитал еще немного и действительно понял. Потребителям («пользователям») требуется экземпляр соединения на стороне клиента. Это установлено createConsumer. Затем нам нужно будет сказать клиенту подписаться на любые трансляции контента, и мы установим это, подписавшись App.notifications = App.cable.subscriptions.create "NotificationsChannel" - person Rares R; 22.04.2017