Action Cable + Flux + React でリアルタイムチャットデモを作ってみた
成果物
デモ(Heroku) http://fluxchat.takeyu-web.com/
ソースコード takeyuweb/rails-fluxchat-example · GitHub
キーワード
- Rails 4.2
- ActionCable
- ES6
- React
- Flux (Alt)
Action Cable?
まだコード全部は読んでないのですが、WebSocketを使ったリアルタイム通信を手軽に実装するためのサーバ・クライアントフレームワーク実装だと感じました。(違ってたらご指摘下さい!)
Railsらしく規約に従ってサーバ・クライアント側で所定のクラスを作っておけば、実際の接続処理や接続の監視・再接続、受け取ったデータのハンドリングなど細かいことはActionCableが良い感じにしてくれるっぽい。
なおAction CableのサーバはこれまでのWebサーバ(rails s
なやつとか)とは別に立ち上げる必要があります。(もちろんポートも空けます)
# cable/config.ru require ::File.expand_path('../../config/environment', __FILE__) Rails.application.eager_load! require 'action_cable/process/logging' run ActionCable.server
で28080番ポートでWebSocketサーバを起動(※ポートは決まってないのでなんでもいいです。ここでは公式のサンプルに合わせました)
$ bundle exec puma -p 28080 cable/config.ru
HTTPサーバはもちろん別
$ bundle exec rails s
なおRails5の新機能ではありますがRails4でも使えます。
gem 'rails', '4.2.4' gem 'actioncable', github: 'rails/actioncable' gem 'puma'
ポイント
FluxとWebScoket(ActionCable)
Fluxについてまだ勉強不足なので理解違いがあるかもしれませんが、図の「Web API Utils」にあてはめて実装してみました。
送信
View (React Component) -> Action Creator -> Channel (ActionCable Subscription)
受信
Channel (ActionCable Subscription) -> Action Creator -> Dispatcher -> Store -> View (React Component)
Action Cable
認証
WebSocketではCookieが使えるので、署名済みCookieを使うのが楽です。
Action Cableで送信するデータ
公式のサンプルアプリではRails5の新しいRendererでアクション外で部分テンプレートを処理しHTMLを送りつける感じですが、Action Cable自体はなんでも送れるので、クライアント側でそれにあわせた処理をすれば良いです。
今回のサンプルでは単に送り側(Ruby/Rails)でモデルインスタンスを.to_json
して、受け取り側(JavaScript/ActionCable.Subscription)でJSON.parse
してみました。
コントローラやバックグラウンド処理からクライアントに通知を送る
ActionCable.server.broadcast
であとはよしなに。時間がかかることもあるので、Active Jobと組み合わせて非同期で実行するのがベター。
class MessageRelayJob < ApplicationJob def perform(message) if message.to.present? # 宛先が指定されている場合はそこと自分に送る ActionCable.server.broadcast "chat_activity:#{message.uuid}", message.to_json ActionCable.server.broadcast "chat_activity:#{message.to}", message.to_json else # そうでなければ全体へ ActionCable.server.broadcast 'chat_activity', message.to_json end end end
実際には全体へのブロードキャストは宛先が死ぬほど増えそうなので、チャットであればチャットルームIDなどで絞り込む必要がありそう。
楽しい
そんな感じでとりあえずやってみたAction CableとFluxですがなかなか楽しいです。
実運用ではコネクション張りっぱなしによるリソースの消費がどんな具合かとか、負荷テストはどうやるの?とか、サーバは何使う?とか、経路上のたとえばELBがどうなっているかとか、Android標準ブラウザの対応が4.4以降で割と非対応端末多そうな問題とかいろいろ考えることはありますが、ぜひ使っていきたいと思っています。
気になるセキュリティ
未調査。
セキュリティ回りで参考になりそうな記事メモ。
IPA セキュア・プログラミング講座:Webアプリケーション編
WebSocket通信のメリットを考える - フレクトのHeroku Lab
近年のJavaScriptプログラミングでは処理全体をdocument#readyのクロージャで括るのが一般的ですが、その場合仮にXSSの脆弱性があったとしても外部から接続済みのWebSocketインスタンスにアクセスすることは不可能です。
DHHのサンプルや今回のデモチャットではwindow.App.cable.connection.webSocket
でWebSocketインスタンスがとれてしまうので、そのあたり取り回しを考えた方がよいかも。