您如何使用ActionCable订阅特定的流

问题描述

我有一个本地Rails Web应用程序和一个带有聊天组件的iOS应用程序。我正在使用ActionCable提供实时消息传递。

在MessageController中创建消息后,服务器将广播到MessageChannel中的两个流

  • 渲染HTML以进行网络聊天
  • 用于访问iOS应用的json对象

您可以创建流特定的订阅吗?也就是说,在客户端,您可以从json广播中过滤html广播吗?

还是应该创建ApiMessageChannel和Web MessageChannel?这感觉像是不必要的重复,因为创建将始终广播到Web和api。

MessageChannel

class MessageChannel < ApplicationCable::Channel
  def subscribed
    stop_all_streams
    stream_for Group.find(params["id"])
    stream_from "message:messages_api_#{params["id"]}"
  end
end

MessageController

def create
# ... 

MessageChannel.broadcast_to group,message: render_to_string(message,locals: { prevIoUs_message: prevIoUs_message,type: group.type,current_user: current_user })

MessageChannel.broadcast_to "messages_api_#{group.id}",message: ApplicationController.render_with_signed_in_user(current_user,json: { sender: current_user.username,content: message.body })
end

聊天室控制器

import { Controller } from "stimulus"
import consumer from "channels/consumer"

export default class extends Controller {
  static targets = [ "messages","newMessage" ]

  connect() {
    this.subscription = consumer.subscriptions.create({ channel: "MessageChannel",id: this.data.get("id") },{
      connected: this._connected.bind(this),disconnected: this._disconnected.bind(this),received: this._received.bind(this)
    })
  }

  disconnect() {
    consumer.subscriptions.remove(this.subscription)
  }

  _connected() {
  }

  _disconnected() {
  }

  _received(data) {
    if (data.message) {
      this.messagesTarget.insertAdjacentHTML('beforeend',data.message);
      $('.js-chat-messages').scrollTop($('.js-chat-messages')[0].scrollHeight);
    }
  }

  clearMessage(event) {
    this.newMessageTarget.value = ''
  }
}

Swift iOS

static var ChannelIdentifier = "MessageChannel"
    let actionCableClient = ActionCableClient(url: URL(string: "wss://localhost:3000/cable")!)

        actionCableClient.headers = [
            "Authorization": token,"Accept": "application/json"
        ]
        
        actionCableClient.connect()

        let room_identifier = ["id" : "12"]
        actionCableChannel = actionCableClient.create(ActionCableController.ChannelIdentifier,parameters: room_identifier,autoSubscribe: true,bufferActions: true )

actionCableChannel?.onReceive = { (data: Any?,error: Error?) in
            print("recieved message!")
            if let error = error {
                print("ERROR: Unable to receive message from ActionCable Channel: \(error.localizedDescription)")
                return
            }
    ```

解决方法

要订阅特定的命名流,您可以:

class MessageChannel < ApplicationCable::Channel
  def subscribed
    # stream_from "message:messages_web"
    # stream_from "message:messages_api"
    # stream_from "message:messages_test"

    stream_from "message:messages_#{params[:type]}"

    # !! can also add in other parameters and add those on the client side for stream specific filtering
    # stream_from "message:messages_#{params[:type]}_#{params[:id]}"

  end
end
class MessagesController < ApplicationController
  def create
    MessageChannel.broadcast_to "messages_web",'web'
    MessageChannel.broadcast_to "messages_api",'api'
    MessageChannel.broadcast_to "messages_test",'test'
  end
end
import consumer from "channels/consumer"
this.subscription = consumer.subscriptions.create({ channel: "MessageChannel",type: 'web'},{
  connected: this._connected.bind(this),disconnected: this._disconnected.bind(this),received: this._received.bind(this)
})

这只会收到来自“ message:messages_web”的消息

,

根据文档,您可以了解以下信息:

发现预订的方法是通过客户端javascript而不是rails控制器调用的。

根据您的问题,您应该订阅特殊资源,对吧?

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...