Spec-Zone.ru › Ruby on Rails 6.1

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

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

Канал предоставляет базовую структуру для группирования поведения в логические единицы при общении по подключению 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 также не вызываемый, так как это приватный метод. Вы увидите, что accept принимает параметр данных, который он затем использует в качестве части вызова модели. #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() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 117
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 = {}) Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 144
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!() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 133
def clear_action_methods! # :doc:
  @action_methods = nil
end

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

method_added(name) Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 138
def method_added(name) # :doc:
  super
  clear_action_methods!
end

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

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

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

perform_action(data) Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 164
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() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 179
def subscribe_to_channel
  run_callbacks :subscribe do
    subscribed
  end

  reject_subscription if subscription_rejected?
  ensure_confirmation_sent
end

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

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

defer_subscription_confirmation!() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 228
def defer_subscription_confirmation! # :doc:
  @defer_subscription_confirmation_counter.increment
end
defer_subscription_confirmation?() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 232
def defer_subscription_confirmation? # :doc:
  @defer_subscription_confirmation_counter.value > 0
end
ensure_confirmation_sent() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 222
def ensure_confirmation_sent # :doc:
  return if subscription_rejected?
  @defer_subscription_confirmation_counter.decrement
  transmit_subscription_confirmation unless defer_subscription_confirmation?
end
reject() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 240
def reject # :doc:
  @reject_subscription = true
end
subscribed() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 199
def subscribed # :doc:
  # Override in subclasses
end

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

subscription_confirmation_sent?() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 236
def subscription_confirmation_sent? # :doc:
  @subscription_confirmation_sent
end
subscription_rejected?() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 244
def subscription_rejected? # :doc:
  @reject_subscription
end
transmit(data, via: nil) Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 211
def transmit(data, via: nil) # :doc:
  status = "#{self.class.name} transmitting #{data.inspect.truncate(300)}"
  status += " (via #{via})" if via
  logger.debug(status)

  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() Показать исходный код
# File actioncable/lib/action_cable/channel/base.rb, line 205
def unsubscribed # :doc:
  # Override in subclasses
end

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

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

END_OF_DOCUMENT_MARKER

Spec-Zone.ru

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