Spec-Zone.ru › Ruby on Rails 7.2

класс ActionCable::Channel::Base

Родитель:
Объект
Включенные модули:
ActionCable::Channel::Callbacks, ActionCable::Channel::PeriodicTimers, ActionCable::Channel::Streams, ActionCable::Channel::Naming, ActionCable::Channel::Broadcasting, ActiveSupport::Rescuable

Канал Action Cable Base

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

Channel экземпляры долгоживущие. Объект канала будет создан, когда потребитель кабеля станет подписчиком, и будет существовать до момента отключения потребителя. Это может быть секунды, минуты, часы или даже дни. Это означает, что вам необходимо обращать особое внимание, чтобы не делать ничего глупого в канале, что могло бы увеличить объем занимаемой памяти и т.д. Ссылки вечные, поэтому они не будут освобождаться, как обычно происходит с экземпляром контроллера, который удаляется после каждого запроса.

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

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

class ChatChannel < ApplicationCable::Channel
  def subscribed
    @room = Chat::Room[params[:room_number]]
  end

  def speak(data)
    @room.speak data, user: current_user
  end
end

Действие speak просто использует объект Chat::Room, который был создан, когда канал был впервые подписан потребителем, когда этот подписчик хочет что-то сказать в комнате.

Обработка действий

В отличие от подклассов ActionController::Base, каналы не следуют форме RESTful-ограничений для своих действий. Вместо этого Action Cable работает по модели вызова удаленных процедур. Вы можете объявить любой публичный метод в канале (при необходимости приняв data аргумент), и этот метод автоматически будет доступен для вызова клиентом.

Пример:

class AppearanceChannel < ApplicationCable::Channel
  def subscribed
    @connection_token = generate_connection_token
  end

  def unsubscribed
    current_user.disappear @connection_token
  end

  def appear(data)
    current_user.appear @connection_token, on: data['appearing_on']
  end

  def away
    current_user.away @connection_token
  end

  private
    def generate_connection_token
      SecureRandom.hex(36)
    end
end

В этом примере методы subscribed и unsubscribed не являются вызываемыми методами, так как они уже были объявлены в ActionCable::Channel::Base, но #appear и #away являются. #generate_connection_token также не является вызываемым методом, так как это закрытый метод. Вы увидите, что он принимает параметр данных, который затем используется как часть вызова модели. #away не делает этого, так как это просто триггерное действие.

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

Отклонение запросов на подписку

Канал может отклонить запрос на подписку в обратном вызове subscribed, вызвав метод reject:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    @room = Chat::Room[params[:room_number]]
    reject unless current_user.can_access?(@room)
  end
end

В этом примере подписка будет отклонена, если у current_user нет доступа к чат-комнате. На стороне клиента вызов Channel#rejected будет вызван, когда сервер отклонит запрос на подписку.

Атрибуты

connection[R]
identifier[R]
params[R]

Публичные методы класса

action_methods() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 129
def action_methods
  @action_methods ||= begin
    # All public instance methods of this class, including ancestors
    methods = (public_instance_methods(true) -
      # Except for public instance methods of Base and its ancestors
      ActionCable::Channel::Base.public_instance_methods(true) +
      # Be sure to include shadowed public instance methods of this class
      public_instance_methods(false)).uniq.map(&:to_s)
    methods.to_set
  end
end

Список имен методов, которые следует рассматривать как действия. Это включает все публичные методы экземпляра канала, за исключением любых внутренних методов (определенных в Base), добавляя обратно любые методы, которые являются внутренними, но все еще существуют в самом классе.

Возвращает

  • Set - Множество всех методов, которые следует рассматривать как действия.

new(connection, identifier, params = {}) Show source
# File actioncable/lib/action_cable/channel/base.rb, line 156
def initialize(connection, identifier, params = {})
  @connection = connection
  @identifier = identifier
  @params     = params

  # When a channel is streaming via pubsub, we want to delay the confirmation
  # transmission until pubsub subscription is confirmed.
  #
  # The counter starts at 1 because it's awaiting a call to #subscribe_to_channel
  @defer_subscription_confirmation_counter = Concurrent::AtomicFixnum.new(1)

  @reject_subscription = nil
  @subscription_confirmation_sent = nil

  delegate_connection_identifiers
end

Приватные методы класса

clear_action_methods!() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 145
def clear_action_methods! # :doc:
  @action_methods = nil
end

action_methods кэшируются, и иногда возникает необходимость обновить их. ::clear_action_methods! позволяет это сделать, поэтому в следующий раз, когда вы запустите action_methods, они будут пересчитаны.

method_added(name) Show source
# File actioncable/lib/action_cable/channel/base.rb, line 150
def method_added(name) # :doc:
  super
  clear_action_methods!
end

Обновить кэшированные action_methods, когда добавляется новый action_method.

Вызывает метод суперкласса

Публичные методы экземпляра

perform_action(data) Show source
# File actioncable/lib/action_cable/channel/base.rb, line 176
def perform_action(data)
  action = extract_action(data)

  if processable_action?(action)
    payload = { channel_class: self.class.name, action: action, data: data }
    ActiveSupport::Notifications.instrument("perform_action.action_cable", payload) do
      dispatch_action(action, data)
    end
  else
    logger.error "Unable to process #{action_signature(action, data)}"
  end
end

Извлечь имя действия из переданных данных и обработать его через канал. Процесс гарантирует, что запрашиваемое действие является публичным методом на канале, объявленном пользователем (а не одним из обратных вызовов, таких как subscribed).

subscribe_to_channel() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 191
def subscribe_to_channel
  run_callbacks :subscribe do
    subscribed
  end

  reject_subscription if subscription_rejected?
  ensure_confirmation_sent
end

Этот метод вызывается после добавления подписки к соединению и подтверждает или отклоняет подписку.

Приватные методы экземпляра

defer_subscription_confirmation!() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 245
def defer_subscription_confirmation! # :doc:
  @defer_subscription_confirmation_counter.increment
end
defer_subscription_confirmation?() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 249
def defer_subscription_confirmation? # :doc:
  @defer_subscription_confirmation_counter.value > 0
end
ensure_confirmation_sent() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 239
def ensure_confirmation_sent # :doc:
  return if subscription_rejected?
  @defer_subscription_confirmation_counter.decrement
  transmit_subscription_confirmation unless defer_subscription_confirmation?
end
reject() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 257
def reject # :doc:
  @reject_subscription = true
end
subscribed() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 213
def subscribed # :doc:
  # Override in subclasses
end

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

subscription_confirmation_sent?() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 253
def subscription_confirmation_sent? # :doc:
  @subscription_confirmation_sent
end
subscription_rejected?() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 261
def subscription_rejected? # :doc:
  @reject_subscription
end
transmit(data, via: nil) Show source
# File actioncable/lib/action_cable/channel/base.rb, line 226
def transmit(data, via: nil) # :doc:
  logger.debug do
    status = "#{self.class.name} transmitting #{data.inspect.truncate(300)}"
    status += " (via #{via})" if via
    status
  end

  payload = { channel_class: self.class.name, data: data, via: via }
  ActiveSupport::Notifications.instrument("transmit.action_cable", payload) do
    connection.transmit identifier: @identifier, message: data
  end
end

Передать хэш данных подписчику. Хэш будет автоматически заключен в оболочку JSON с правильным идентификатором канала, помеченным как получатель.

unsubscribed() Show source
# File actioncable/lib/action_cable/channel/base.rb, line 219
def unsubscribed # :doc:
  # Override in subclasses
end

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

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API