遅ればせながら。 Phoenix Playground の存在に気づきました。
以前から。 状態の変化を LiveView を使ってブラウザ上で閲覧できるようにすることを考えているのですが、ごく簡単な情報を表示するために Phoenix app を構築するのが割に合わず、結局コンソール表示で妥協するのが常となっています。
Phoenix Playground を使えば、1 ファイルで LiveView のページが作れるので、シェルスクリプトを書くくらいの気持ちでそういったツールを作れるのではないか、と思った次第。
と、いうわけで。
試しにディレクトリの状態を監視するツールを雑な感じに書いてみました。
ディレクトリの監視には file_system を使いました。
また、時刻を日本時間で表示するために tzdata を使っています。
そして書いたコードがこちら。
Mix.install( [ {:phoenix_playground, "~> 0.1.0"}, {:file_system, "~> 1.0"}, {:tzdata, "~> 1.1"} ], config: [ elixir: [time_zone_database: Tzdata.TimeZoneDatabase] ] ) defmodule DirWatcherLive do use Phoenix.LiveView require Logger def mount(_params, _session, socket) do if connected?(socket) do FileSystem.subscribe(:dir_watcher) end {:ok, assign(socket, items: [])} end def render(assigns) do ~H""" <table> <thead> <th style="width: 180px;">timestamp</th> <th style="width: 240px;">filename</th> <th>events</th> </thead> <tbody> <tr :for={item <- @items}> <td style="width: 180px;"><tt><%= item.time %></tt></td> <td style="width: 240px;"><tt><%= item.basename %></tt></td> <td><%= item.events %></td> </tr> </tbody> </table> <style type="text/css"> body { padding: 1em; } </style> """ end def handle_info({:file_event, _worker_pid, {file_path, events}}, socket) do Logger.info("file_path: #{file_path}, events: #{inspect(events)}") {:noreply, assign(socket, :items, [to_item(file_path, events) | socket.assigns.items])} end defp to_item(file_path, events) do %{ basename: Path.basename(file_path), time: current_time(), events: events_to_string(events) } end defp current_time do DateTime.now!("Asia/Tokyo") |> Calendar.strftime("%Y-%m-%d %H:%M:%S") end defp events_to_string(events) do for event <- events, event in [:created, :modified, :removed, :renamed] do event end |> Enum.join(", ") end end {:ok, _pid} = FileSystem.start_link(dirs: ["."], name: :dir_watcher) PhoenixPlayground.start(live: DirWatcherLive)
Phoenix Playground のリポジトリにある demo_live.exs
に FileSystem プロセスを加え、LiveView プロセス内でFileSystem.subscribe/1
を使って購読を登録し、handle_info/2
でイベントをハンドリングする、という愚直な実装です。
スクリプトを実行します。
$ elixir dir_watcher.exs
デフォルトの指定では、自動的に作成したページがブラウザで開きます。
スクリプトを実行したディレクトリでファイルの操作をしてみます。
$ echo Hi > hi.txt $ echo Hello >> hi.txt $ mv hi.txt hello.txt $ rm hello.txt
ブラウザに表示されている LiveView の内容が更新されることが確認できると思います。