前回の続きです。
前回、「バージョン 0.1 が公開され…」と書いたばかりなのに、今回の記事を書くまでの十日足らずの間にバージョン 0.2 が公開されてしまいました。
それはそれとして。
今回は Phoenix.LiveView の app で subscribe と broadcast を使って、複数のユーザ(ブラウザ)で通信させようという試みです。
使うサンプルはクリックしたセルの色が同期して変化する Phoenix app です。
モジュールを追加する手前まで進む
LiveView を利用できるように設定するところまでは同じですので前回の記事を参照しながら、「準備」「パッケージを追加する」「Endpoint を編集する」「ソケットのクライアントを設定する」「salt を設定する」まで進みます。
ここでは live_click
という app 名で作成しています。
$ mix phx.new live_click --no-ecto
まずは単独の app を作成する
live モジュール
ディレクトリ lib/live_click_web/live
を作成し、そこに click_live.ex
を作成してモジュール LiveClickWeb.ClickLive
を定義します。
defmodule LiveClickWeb.ClickLive do use Phoenix.LiveView def mount(_session, socket) do new_socket = socket |> assign(:effects, %{}) {:ok, new_socket} end def render(assigns) do Phoenix.View.render(LiveClickWeb.ClickView, "index.html", assigns) end def handle_event("cell", %{"row" => row, "col" => col}, socket) do new_socket = socket |> assign_cell_color(String.to_integer(row), String.to_integer(col)) {:noreply, new_socket} end def assign_cell_color(socket, row, col) do effects = socket.assigns.effects new_effect = case Map.get(effects, {row, col}) do :red -> :blue :blue -> :green :green -> :white _ -> :red end socket |> assign(:effects, Map.put(effects, {row, col}, new_effect)) end end
view モジュール
lib/live_click_web/views/click_view.ex
を作成してモジュール LiveClickWeb.ClickView
を定義します。
defmodule LiveClickWeb.ClickView do use LiveClickWeb, :view end
テンプレートとスタイル
lib/live_click_web/templates/click/index.html.leex
を作成してテンプレートを定義します。
<div> <%= Enum.map (0..9), fn row -> %> <div> <%= Enum.map (0..9), fn col -> %> <div class="cell <%= Map.get(@effects, {row, col}) %>" phx-click="cell" phx-value-row="<%= row %>" phx-value-col="<%= col %>"> <%= row %><%= col %> </div> <% end %> </div> <% end %> </div>
また assets/css/app.css
を編集してスタイルを追加します。
@import "./phoenix.css"; /* ここから下を追加 */ .cell { display: inline-block; height: 50px; width: 50px; border: solid thin #ccc; text-align: center; line-height: 50px; margin-bottom: 5px; } .red { background-color: red; } .green { background-color: green; } .blue { background-color: blue; } .white { background-color: white; }
ルーティングを変更する
lib/live_click_web/router.ex
を編集します。
scope "/", LiveClickWeb do pipe_through :browser - get "/", PageController, :index + live "/", ClickLive end
動作を確認する
iex コマンドあるいは mix コマンドで Phoenix app をローカルに起動し、http://localhost:4000
にアクセスして動作を確認します。
$ iex -S mix phx.server
セルをクリックすると、クリックしたセルの色がクリックのたびに 白 → 赤 → 青 → 緑 → 白 と変化すれば成功です。
subscribe と broadcast と handler を追加する。
Phoenix.LiveView 自体が WebSocket を利用しているため、ここから少しコードを追加するだけで他のブラウザにイベントを送ることができるようになります。
subscribe
イベントを subscribe するために LiveClickWeb.ClickLive.mount/2
に LiveClickWeb.Endpoint.subscribe(@topic)
の一行を追加します。
これだけで broadcast されたイベントを受け取ることができるようになります。
@topic "live_click:cells" def mount(_session, socket) do LiveClickWeb.Endpoint.subscribe(@topic) new_socket = socket |> assign(:effects, %{}) {:ok, new_socket} end
関数の詳細はドキュメントを参照してください。
broadcast
イベントを broadcast するために LiveClickWeb.Endpoint.broadcast_from/4
の一行を追加します。
今回は LiveClickWeb.ClickLive. assign_cell_color/3
でローカルで発生したイベントを処理をしているのでここに追加します。
関数の第二引数には subscribe したトピックを文字列で、第三引数にはイベントを文字列で、第四引数には送信したいパラメータをマップで設定します。
def assign_cell_color(socket, row, col) do effects = socket.assigns.effects new_effect = case Map.get(effects, {row, col}) do :red -> :blue :blue -> :green :green -> :white _ -> :red end LiveClickWeb.Endpoint.broadcast_from(self(), @topic, "click", %{key: {row, col}, value: new_effect}) socket |> assign(:effects, Map.put(effects, {row, col}, new_effect)) end
broadcast 元以外にイベントを送るために broadcast_from/4
を利用しましたが、全体に送るには broadcast/3
を利用します。
関数の詳細はドキュメントを参照してください。
handler
broadcast されたイベントはモジュール LiveClickWeb.ClickLive
へのメッセージとして届きます。メッセージをハンドリングするため LiveClickWeb.ClickLive.handle_info/2
を記述します。
第一引数は broadcast の引数の内容を格納したマップになります。
:topic
にトピックが、:event
にイベントが、:payload
にその他のパラメータが格納されます。
def handle_info(%{topic: @topic, event: "click", payload: %{key: key, value: value}}, socket) do effects = socket.assigns.effects new_socket = socket |> assign(:effects, Map.put(effects, key, value)) {:noreply, new_socket} end
関数の詳細はドキュメントを参照してください。
実行
app を起動し、ブラウザのウィンドウを二つ以上開きます。 一つのブラウザでクリックした内容が他のブラウザにも反映されることが確認できます。
一つ注意点。 このサンプルではセルの状態を永続化しているわけではないので、表示の内容のすべてが同期されるわけではありません。 あるセルをクリックしたことによるそのセルの状態の変化のみが伝わるようになっています。
いつか読むはずっと読まない:THE LONG WAY TO A ...
銀河共同体の中で、様々な星系出身の容姿も文化も価値観も違うクルーが一つの船で目的地に向かう。古典的なスペオペがわくわく感を誘います。
とはいえ。「古典的」とはあえて書いてみました。設定だけを切り出すと懐かしいスペオペの雰囲気があるのですが、書かれた時代背景が作品に現れるのはこの作品にも違いはなく、やはり現代の作品なのだな、と感じます。
- 作者: ベッキー・チェンバーズ,細美遙子
- 出版社/メーカー: 東京創元社
- 発売日: 2019/06/28
- メディア: 文庫
- この商品を含むブログを見る
- 作者: ベッキー・チェンバーズ,細美遙子
- 出版社/メーカー: 東京創元社
- 発売日: 2019/06/28
- メディア: 文庫
- この商品を含むブログを見る