【问题标题】:How to terminate subscription to an actioncable channel from server?如何终止从服务器订阅可操作频道?
【发布时间】:2017-02-10 10:20:09
【问题描述】:

有没有办法从服务器端(控制器)终止任何特定消费者对特定频道的订阅,以便可以调用我的咖啡脚本文件中的断开连接的回调?

【问题讨论】:

  • 我也很好奇。我决定向客户端发送一条“断开连接”消息,客户端在收到该消息后终止订阅。

标签: ruby-on-rails ruby-on-rails-5 channel actioncable


【解决方案1】:

你可以这样做。

class YourChannel < ApplicationCable::Channel

  #your code

  def your_custom_action
    if something
      reject_subscription
    end
  end
end

【讨论】:

    【解决方案2】:

    http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests

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

    在致电reject之前,您还可以告知订阅者拒绝的原因:

    class ChatChannel < ApplicationCable::Channel
      def subscribed
    
        if params["answerer"]
    
          answerer = params["answerer"]
    
          answerer_user = User.find_by email: answerer
    
          if answerer_user
    
            stream_from "chat_#{answerer_user}_channel"    
    
          else
    
            connection.transmit identifier: params, error: "The user #{answerer} not found."
    
      # http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests
    
            reject
    
          end
    
        else
    
            connection.transmit identifier: params, error: "No params specified."
    
      # http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests
    
            reject
    
        end     
    
      end
    end
    

    【讨论】:

      【解决方案3】:

      之前的答案允许您拒绝订阅频道的尝试。但是他们不会让您在订阅后强行取消订阅连接。例如,用户可能会被逐出聊天室,因此您需要取消他们对聊天室频道的订阅。我向 Rails 提出了this Pull Request 来支持这一点。

      本质上,它向remote_connections 添加了一个取消订阅方法,因此您可以调用:

      subscription_identifier = "{\"channel\":\"ChatChannel\", \"chat_id\":1}"
      remote_connection = ActionCable.server.remote_connections.where(current_user: User.find(1))
      remote_connection.unsubscribe(subscription_identifier)
      

      这会在internal_channel(所有连接都订阅)上发送一条消息,相关连接通过删除其对指定频道的订阅来响应该消息。

      【讨论】:

        【解决方案4】:

        就像 Ollie 的回答正确指出的那样,这里的其他答案是拒绝 ActionCable 连接成功之前,但问题是在订阅已经订阅后断开订阅。

        这个问题非常重要,因为它涉及用户被踢出他之前所在的聊天室的场景。除非您断开他与该订阅的连接,否则他将继续通过 WebSocket 接收该频道的消息,直到他关闭他的窗口/选项卡或重新加载页面(因为随后将启动新订阅并且服务器不会为他订阅聊天他没有权限了)。

        Ollie 的回答指出他提出了一个很棒的拉取请求,因为它允许断开特定的,而不是用户拥有的所有打开的 WebSockets 连接;问题是它还没有合并到 Rails 中。

        我的解决方案是使用已经存在的文档化 API 功能。即使很难,它也不允许您选择要断开的 stream,您可以断开与用户的所有打开的 websocket 连接。

        在我的测试中,这很好用,因为一旦发生断开连接,所有选项卡都会在几秒钟内尝试重新订阅,它会触发每个 ActionCable 频道中的subscribed 方法,从而重新启动连接,但现在基于来自服务器的最新权限(当然,这不会让他重新订阅他被踢出的聊天)。

        解决方案是这样的,假设您有一个加入记录 ChatroomUser,用于跟踪特定用户是否可以阅读特定聊天室中的聊天:

        class ChatroomUser < ApplicationRecord
          belongs_to :chatroom
          belongs_to :user
        
          after_destroy :disconnect_action_cable_connections
        
          private
        
            def disconnect_action_cable_connections
        
              ActionCable.server.remote_connections.where(current_user: self.user).disconnect
        
            end
        end
        
        

        这使用此 API (https://api.rubyonrails.org/classes/ActionCable/RemoteConnections.html),并假设您在 ApplicationCable::Connection 中设置了 current_user,正如大多数人所做的那样(根据教程)。

        【讨论】:

          猜你喜欢
          • 2017-04-29
          • 2021-06-16
          • 2014-11-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-22
          • 1970-01-01
          相关资源
          最近更新 更多