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

How would you subscribe to specific stream using ActionCable

我有一个本机 rails 网络应用程序和一个具有聊天组件的 iOS 应用程序。我正在使用 ActionCable 提供实时消息传递。

当在 MessageController 中创建消息时,服务器向 MessageChannel 中的两个流广播

你能创建流特定订阅吗?也就是在客户端,能不能从json广播中过滤掉html广播?

或者我应该创建一个 ApiMessageChannel 和一个 web MessageChannel 吗?这感觉像是不必要的重复,因为创建将始终广播到网络和 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
            }
    ```

根据文档,您可以知道如下:

found out that the subscribed method is called via client-side javascript, not by the rails controller.

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

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

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)
})

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