JavaScriptを有効にしてください

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

 ·  ☕ 3 分で読めます

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

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

確認環境

  • Elixir 1.14.2
  • Phoenix 1.6.3

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

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

チャネルの生成

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

1
mix phx.gen.channel Notifications

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

  • lib/sample_web/channels/notifications_channel.ex
  • test/sample_web/channels/notifications_channel_test.exs
  • lib/sample_web/channels/user_socket.ex
  • assets/js/user_socket.js

WebSocket追加

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

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

Javascriptの用意

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

1
import "./user_socket.js"

チャネルの設定

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 を出すだけにします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 接続先のチャンネル
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!関数を使用して特定のユーザーに送信されます。

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Sample.Endpoint.broadcast(
  # 対象チャンネル
  "notifications:lobby",
  # 対象のhandle_in
  "shout",
  # payload
  %{
    title: title,
    message: message
  }
)

まとめ

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

参考

共有

こぴぺたん
著者
こぴぺたん
Copy & Paste Engineer