Copy & Paste Engineer

【Elixir】Phoenix サーバーサイドからリアルタイム通知する

【Elixir】Phoenix サーバーサイドからユーザーにリアルタイム通知する

Elixir Phoenix サーバーサイドからユーザーに簡単にリアルタイム通知することが可能です。

確認環境

Elixir Phoenixでの通知システムの作成

ElixirとPhoenixを使用して、リアルタイムの通知システムを作成する方法を探求します。このシステムは、特定のユーザーに対してメッセージの通知を送ることができ、ログイン中の全画面に適用されます。さらに、サーバーから特定のユーザーに通知を送ることも可能です。

チャネルの生成

まず、新しいチャネルを生成します。Phoenixでは、mix phx.gen.channelコマンドを使用してチャネルを生成ができます。この例では、Notificationsという名前のチャネルを生成します。

mix phx.gen.channel Notifications

このコマンドを実行すると、以下のファイルが生成されます。

WebSocket追加

通知用のWebSocketを endpoint.ex に追加します。

socket "/socket", SampleWeb.UserSocket,
  websocket: true,
  longpoll: false

Javascriptの用意

app.js に生成されたJavaScriptを追加します。

import "./user_socket.js"

チャネルの設定

生成されたnotifications_channel.ex です。 今回は notifications:lobby というチャンネルで全体通知をしてみます。

defmodule SampleWeb.NotificationsChannel do
  use SampleWeb, :channel

  # "notifications:lobby" が接続するための部屋
  # "notifications:" <> user_id などにすることで特定のユーザのみの通知も可能になる
  @impl true
  def join("notifications:lobby", payload, socket) do
    if authorized?(payload) do
      # 認証OKであれば接続
      {:ok, socket}
    else
      # エラー
      {:error, %{reason: "unauthorized"}}
    end
  end

  # PING
  @impl true
  def handle_in("ping", payload, socket) do
    {:reply, {:ok, payload}, socket}
  end

  # 通知
  @impl true
  def handle_in("shout", payload, socket) do
    broadcast(socket, "shout", payload)
    {:noreply, socket}
  end

  # 認証
  defp authorized?(_payload) do
    true
  end
end

この関数は、ユーザーがチャネルに参加時に呼び出されます。 ユーザーIDをチャネルのトピックに含めることで、特定のユーザーに対して通知を送ることができます。

JavaScript 側の設定

JavaScript側でメッセージの通知処理を作成します。 今回は console.log を出すだけにします。

// 接続先のチャンネル
let channel = socket.channel("notifications:lobby", {})

channel.join()
  .receive("ok", resp => { console.log("Joined successfully", resp) })
  .receive("error", resp => { console.log("Unable to join", resp) })

// 処理
channel.on("shout", payload => {
  console.log("New message:", payload.message)
})

この関数は、クライアントから shout というイベントが送られてきたときに呼び出されます。 イベントにはメッセージが含まれており、このメッセージはbroadcast_to!関数を使用して特定のユーザーに送信されます。

サーバーサイドから通知する

以下のコードを使用することによってサーバーサイドからフロントに対して通知を行うことができます。 今回は全通知です。

Sample.Endpoint.broadcast(
  # 対象チャンネル
  "notifications:lobby",
  # 対象のhandle_in
  "shout",
  # payload
  %{
    title: title,
    message: message
  }
)

まとめ

ElixirとPhoenixを使用して接続ユーザーに通知を送るシステムを作成する方法です。 このシステムは、リアルタイムの通知を可能にし、ログイン中の全画面に適用されます。 さらに、サーバーから特定のユーザーに通知を送ることも可能です。

参考