Action Cable Channel Base¶ ↑
Channel 提供了在 WebSocket 连接上通信时将行为分组到逻辑单元的基本结构。您可以将 Channel 视为一种控制器,但它除了响应订阅者的直接请求外,还能将内容推送到订阅者。
Channel 实例是长生命周期的。当 Cable 消费者成为订阅者时,Channel 对象将被实例化,然后一直存在直到消费者断开连接。这可能持续几秒、几分钟、几小时甚至几天。这意味着您必须特别小心,不要在 Channel 中执行任何可能导致其内存占用膨胀的愚蠢操作。引用是永久的,因此它们不会像通常情况下被丢弃的控制器实例那样被释放。
长生命周期的 Channel(和连接)也意味着您有责任确保数据的时效性。如果您持有一个用户记录的引用,但在持有该引用的同时更改了该用户的姓名,那么如果您不采取预防措施,可能会发送过时的数据。
长生命周期 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
当消费者订阅 Channel 时,`speak` 操作会简单地使用创建的 `Chat::Room` 对象,以便在订阅者想要在房间里发言时使用。
Action 处理¶ ↑
与 ActionController::Base 的子类不同,Channel 不遵循 RESTful 约束形式的 Action。相反,Action Cable 通过远程过程调用(RPC)模型进行操作。您可以在 Channel 上声明任何公共方法(可选参数为 `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` 也不是可调用的,因为它是一个私有方法。您会看到 `appear` 接受一个 `data` 参数,然后将其用作模型调用的部分。而 `away` 不接受,因为它只是一个触发操作。
另请注意,在此示例中,`current_user` 可用,因为它已在连接上标记为识别属性。所有此类标识符都会自动在 Channel 实例上创建一个同名的委托方法。
拒绝订阅请求¶ ↑
Channel 可以在 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` 回调。
- A
- C
- D
- E
- M
- N
- P
- R
- S
- T
- U
- ActionCable::Channel::Callbacks
- ActionCable::Channel::PeriodicTimers
- ActionCable::Channel::Streams
- ActionCable::Channel::Naming
- ActionCable::Channel::Broadcasting
- ActiveSupport::Rescuable
Attributes
| [R] | connection | |
| [R] | 标识符 | |
| [R] | params |
类公共方法
action_methods() 链接
一个应被视为 Action 的方法名列表。这包括 Channel 上的所有公共实例方法,减去任何内部方法(在 Base 上定义),并重新加上即使是内部方法但仍然存在于类本身的方法。
返回值¶ ↑
-
Set- 一个所有应被视为 Action 的方法的集合。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 128 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 methods.reject! { |m| m.start_with?("_") } methods.map!(&:name) methods.to_set end end
new(connection, identifier, params = {}) 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 158 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 @unsubscribed = false delegate_connection_identifiers end
类私有方法
clear_action_methods!() 链接
action_methods 是缓存的,有时需要刷新它们。::clear_action_methods! 允许您这样做,这样下次运行 action_methods 时,它们将被重新计算。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 147 def clear_action_methods! # :doc: @action_methods = nil end
method_added(name) 链接
当添加新的 action_method 时,刷新缓存的 action_methods。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 152 def method_added(name) # :doc: super clear_action_methods! end
实例公共方法
perform_action(data) 链接
从传入的数据中提取 Action 名称,并通过 Channel 进行处理。该过程将确保请求的 Action 是用户在 Channel 上声明的公共方法(因此不是像 subscribed 这样的回调)。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 179 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_channel() 链接
此方法在订阅已添加到连接后被调用,并确认或拒绝订阅。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 194 def subscribe_to_channel run_callbacks :subscribe do subscribed end reject_subscription if subscription_rejected? ensure_confirmation_sent end
实例私有方法
defer_subscription_confirmation!() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 253 def defer_subscription_confirmation! # :doc: @defer_subscription_confirmation_counter.increment end
defer_subscription_confirmation?() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 257 def defer_subscription_confirmation? # :doc: @defer_subscription_confirmation_counter.value > 0 end
ensure_confirmation_sent() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 247 def ensure_confirmation_sent # :doc: return if subscription_rejected? @defer_subscription_confirmation_counter.decrement transmit_subscription_confirmation unless defer_subscription_confirmation? end
reject() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 265 def reject # :doc: @reject_subscription = true end
subscribed() 链接
当消费者成为 Channel 的订阅者后调用。通常是设置 Channel 要发送给订阅者的任何流(streams)的地方。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 221 def subscribed # :doc: # Override in subclasses end
subscription_confirmation_sent?() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 261 def subscription_confirmation_sent? # :doc: @subscription_confirmation_sent end
subscription_rejected?() 链接
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 269 def subscription_rejected? # :doc: @reject_subscription end
transmit(data, via: nil) 链接
向订阅者传输一个数据哈希。该哈希将自动包装在一个 JSON 信封中,并将正确的 Channel 标识符标记为收件人。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 234 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
unsubscribed() 链接
当消费者断开其 Cable 连接时调用。可用于清理连接或将用户标记为离线等。
来源: 显示 | 在 GitHub 上
# File actioncable/lib/action_cable/channel/base.rb, line 227 def unsubscribed # :doc: # Override in subclasses end