Class: ActionCable::Channel::Base

Inherits:
Object
  • Object
show all
Includes:
Broadcasting, Callbacks, Naming, PeriodicTimers, Streams
Defined in:
actioncable/lib/action_cable/channel/base.rb

Overview

Канал предоставляет базовую структуру группового поведения в логических единицах при коммуникации через соединение WebSocket. Вы можете думать о канале как о форме контроллера, но он способен отправить контект подписчику (subscriber) в дополнение к простому отклику на прямые запросы подписчиков.

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

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

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

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

В этом примере подписанные и неподписанные методы не являются вызываемыми методами, поскольку они уже были объявлены в ActionCable::Channel::Base, кроме #appear и #away. #generate_connection_token также не вызывается, так как это приватный метод. Вы видели, что #appear принимает параметр data, который затем используется как часть вызова этой модели. А метод #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 будет вызываться, когда сервер отклоняет запрос на подписку.

Constant Summary

Constants included from ActiveSupport::Callbacks

ActiveSupport::Callbacks::CALLBACK_FILTER_TYPES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ActiveSupport::Concern

#append_features, #class_methods, extended, #included

Methods included from Streams

#stop_all_streams, #stream_for, #stream_from

Methods included from ActiveSupport::Callbacks

#run_callbacks

Constructor Details

#initialize(connection, identifier, params = {}) ⇒ Base


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'actioncable/lib/action_cable/channel/base.rb', line 140

def initialize(connection, identifier, params = {})
  @connection = connection
  @identifier = identifier
  @params     = params

  # Когда канал читает поток через pubsub, мы хотим отложить передачу подтверждение
  # до тех пор, пока подписка pubsub не будет подтверждена.
  #
  # Счетчик начинается с 1, потому что он ожидает вызова #subscribe_to_channel
  @defer_subscription_confirmation_counter = Concurrent::AtomicFixnum.new(1)

  @reject_subscription = nil
  @subscription_confirmation_sent = nil

  delegate_connection_identifiers
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection


101
102
103
# File 'actioncable/lib/action_cable/channel/base.rb', line 101

def connection
  @connection
end

#identifierObject (readonly)

Returns the value of attribute identifier


101
102
103
# File 'actioncable/lib/action_cable/channel/base.rb', line 101

def identifier
  @identifier
end

#paramsObject (readonly)

Returns the value of attribute params


101
102
103
# File 'actioncable/lib/action_cable/channel/base.rb', line 101

def params
  @params
end

Class Method Details

.action_methodsObject

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

Возвращает

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


113
114
115
116
117
118
119
120
121
122
123
# File 'actioncable/lib/action_cable/channel/base.rb', line 113

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

Instance Method Details

#perform_action(data) ⇒ Object

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


160
161
162
163
164
165
166
167
168
169
170
171
# File 'actioncable/lib/action_cable/channel/base.rb', line 160

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

#subscribe_to_channelObject

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


175
176
177
178
179
180
181
182
# File 'actioncable/lib/action_cable/channel/base.rb', line 175

def subscribe_to_channel
  run_callbacks :subscribe do
    subscribed
  end

  reject_subscription if subscription_rejected?
  ensure_confirmation_sent
end

#unsubscribe_from_channelObject

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


186
187
188
189
190
# File 'actioncable/lib/action_cable/channel/base.rb', line 186

def unsubscribe_from_channel # :nodoc:
  run_callbacks :unsubscribe do
    unsubscribed
  end
end