Как бы вы подписались на определенный поток, используя ActionCable

#ios #ruby-on-rails #swift #actioncable

#iOS #ruby-on-rails #swift #actioncable

Вопрос:

У меня есть собственное веб-приложение rails и приложение iOS, в котором есть компонент чата. Я использую ActionCable для обмена сообщениями в режиме реального времени.

Сервер передает на два потока в MessageChannel, когда сообщение создается в MessageController

  • визуализированный html для перехода в веб-чат
  • объект json для перехода в приложение iOS

Можете ли вы создать подписку на конкретный поток? То есть на стороне клиента вы можете отфильтровать трансляцию html из трансляции json?

Или я должен создать ApiMessageChannel и web MessageChannel? Это похоже на ненужное дублирование, потому что create всегда будет транслироваться как в 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 = ''
  }
}
  

Быстрая 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
            }
    ```
  

Ответ №1:

Чтобы подписаться на определенный именованный поток, вы можете:

 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»

Ответ №2:

Основываясь на документе, вы можете узнать, как показано ниже:

обнаружил, что подписанный метод вызывается через клиентский javascript, а не контроллером rails.

исходя из вашего вопроса, вы должны подписаться на специальные ресурсы, верно?

Комментарии:

1. Что вы имеете в виду под специальными ресурсами? Есть ли способ фильтровать поток на стороне клиента? Есть ли способ подписаться без создания 2 отдельных каналов?