はじめに
PhoenixのChannelを使ったチャットの作成をするとき、jsでフロントの部分を作成していることが多かったが、jsのページを用意したりしなくても動作確認ができるようにしようと思ってwscat
を使ってみました。
まだ1対1のチャットを作成しようとしてる途中なので、1対1のチャットとしてはまだ機能ができていませんが、とりあえずwscatで動いてくれたので記事を書きました。(private_chatなのにlobbyがあって個別のchannelを用意できていない)
このように、2つのクライアントがChannelに接続されており、チャットの状態を共有しています。
左側のクライアントでチャットを送信すると右側にも反映されます。
Websocketについて
このチャットで使うようなWebsocket
というのは、通信で使われるプロトコルの一種です。
いつも使っているようなHTTP
は、クライアントからサーバーへリクエストを送ってデータをもらうというのが基本の型です。
リアルタイムなチャットを作成する際は、リクエストを送らずにデータを受信できるようにしたいので、HTTPではなく双方向通信が可能なWebsocketを使います。
Phoenix側のコード
mix phx.new
で何かしらのプロジェクトは作成してあるとして、Channelの部分を書いていきます。
defmodule PappapWeb.UserSocket do
use Phoenix.Socket
## Channels
# channel "room:*", PappapWeb.RoomChannel
channel "private_chat:*", PappapWeb.PrivateChatChannel
...
end
defmodule PappapWeb.PrivateChatChannel do
use Phoenix.Channel
# This function is called when client connects to this server.
def join("private_chat:lobby", _msg, socket) do
{:ok, socket}
end
def join("private_chat:" <> _private_room_id, _auth_msg, _socket) do
{:error, %{reason: "unauthorized"}}
end
def handle_in("new_msg", %{"body" => body}, socket) do
broadcast!(socket, "new_msg", %{body: body})
{:noreply, socket}
end
end
Websocketでサーバーに接続するときに、join/3
が呼び出されます。
join/3
の第一引数の"private_chat:lobby"
というのは、topicと呼ばれます。
このtopicが一致しているチャンネルに接続すると、いずれかのクライアントが送信したメッセージがもう片方にも送信されます。
wscat
wscatは、Websocketのサーバー/クライアントで、コマンドラインから利用できます。
npm
でインストールして利用することができます。
npm i -g wscat
インストールが完了したら、このようにしてwscatを動かしてみることができます。
wscat -c http://localhost:4000/socket/websocket/
オプションの-c
を指定すると、wscatをwebsocketを利用するクライアントとして動かすことができます。
では、実際にサーバーを起動して動かしてみます。
動作確認
まずはPhoenixのサーバーを起動します。
mix phx.server
サーバーが正常に起動できたら、次はwscatを使ってWebsocketでサーバーに接続します。
wscat -c http://localhost:4000/socket/websocket/
このように表示されたら接続成功です。
次は、チャットルームに入ってみます。
{"topic":"private_chat:lobby","ref":1, "payload":{},"event":"phx_join"}
このリクエストをwscatを使ってサーバーへ送信します。
topicの部分が、さっきphoenixに書いたjoin/3
の引数のものと一致すれば成功すると思います。
次は、チャットを送信します。
{"topic":"private_chat:lobby","ref":1, "payload":{"body": {"msg": "hello"}},"event":"new_msg"}
wscatでこのリクエストを送信することで、チャットをサーバーへ送信できると思います。
ターミナルを2つ以上開いて、同時にwscatでサーバーに接続して同じトピックのチャンネルに接続すると、リアルタイムでチャットの様子を見ることができると思います。
ぼくはiTerm2を使っているので、Command+d
で画面を分割して様子を見ました。
さいごに
まだ完全なチャットは全然できていませんが、
とりあえずjsのページ以外からWebsocketを動かしてみることができました。
参考リンク
https://qiita.com/south37/items/6f92d4268fe676347160
https://tricknotes.hateblo.jp/entry/20120227/p1