0
Help us understand the problem. What are the problem?

RailsのAction Cableで任意のメッセージ形式でやりとりする

背景

REST API, WebsocketのAPIを提供するとあるサービスのMockを素早く作るため、Railsを選定したが、メッセージの形式がRailsと合わなかった。

メッセージ送信では、 command, data, identifierを送る必要があるが、

{                        
  "command": "message",  
  "data": "{\"message\":\"test message\",\"action\":\"speak\"}",
  "identifier": "{\"channel\":\"RoomChannel\"}"
}

例えば、 command をやめて cmd だけで任意のアクションを指定できるようにしたい。

注意

今回はローカル起動用のMockの作成を目的としていたためoverrideを試しました。
副作用の検証まではしていませんし、通常はRailに乗る方が良いので使い所は注意しましょう。

サーバーが受け取るメッセージを任意の形式に変更する

ActionCable::Conection::Subscriptions#execute_command で受け取る data を元に、 command を決める。

例えば以下のような感じにOverrideする。

module ActionCable
  module Connection
    class Subscriptions
      def execute_command(data)
        if %w[create_message delete_message].include?(data['cmd'])
          perform_action({
            'command' => 'message',
            'identifier' => identifier(data),
            'data' => data.merge({ 'action' => data['cmd'] }).to_json
          })
        else
          logger.error "Received unrecognized message_type in #{data.inspect}"
        end
      rescue Exception => e
        @connection.rescue_with_handler(e)
        logger.error "Could not execute command from (#{data.inspect}) [#{e.class} - #{e.message}]: #{e.backtrace.first(5).join(' | ')}"
      end

      private

      def identifier(data)
        # ...
      end
    end
  end
end

クライアントに送信するメッセージを任意の形式に変更する

例えばチャンネルのアクションで broadcast する場合。
こちらは ActionCable::Channel::Base#transmit なので app/channels/application_cable/channel.rb 等でoverrideできる。

例えば、以下の例ではチャンネル側で送信したメッセージをそのままの形式で送信する。

module ApplicationCable
  class Channel < ActionCable::Channel::Base
    private

    def transmit(data, via: nil)
      status = "[Extended] #{self.class.name} transmitting #{data.inspect.truncate(300)}"
      status += " (via #{via})" if via
      logger.debug(status)

      payload = { channel_class: self.class.name, data:, via: }
      ActiveSupport::Notifications.instrument('transmit.action_cable', payload) do
        connection.transmit data
      end
    end
  end
end

他にも以下は app/channels/application_cable/ 下の ApplicationCable::Xxx でoverrideできる。

その他

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?