channel
実際には、 APIを使用してプロジェクトのソケット モジュールでトピックを定義する方法に基づいて、ソケット ルーティングが行われます。私の Slack クローンでは、3 つのチャンネルを使用しています。プレゼンスの更新を処理するシステム レベル チャネル、ユーザー チャネル、およびルーム チャネルがあります。
特定のユーザーは、0 または 1 つのチャネルにサブスクライブされます。ただし、ユーザーは多数のチャンネルに登録することができます。
特定の部屋に送信されるメッセージについては、部屋のチャネルを介してブロードキャストします。
特定のルームの未読メッセージ、通知、またはバッジを検出すると、ユーザー チャネルを使用します。各ユーザー チャネルには、ユーザーがサブスクライブしたルームのリストも保存されます (クライアントのサイド バーに表示されます)。
これらすべての秘訣は、主intercept
に 、handle_out
、My.Endpoint.subscribe
、およびの 2 つのチャネル API を使用することhandle_info(%Broadcast{},socket)
です。
- ブロードキャストされたメッセージを
intercept
キャッチして、無視するか、送信する前に操作します。
- ユーザー チャネルでは、ルーム チャネルからブロードキャストされたイベントをサブスクライブします。
- サブスクライブすると、ブロードキャストされたメッセージのトピック、イベント、およびペイロードを含む構造体を
handle_info
使用して呼び出しが行われます。%Broadcast{}
ここに私のコードのいくつかの部分があります:
defmodule UcxChat.UserSocket do
use Phoenix.Socket
alias UcxChat.{User, Repo, MessageService, SideNavService}
require UcxChat.ChatConstants, as: CC
## Channels
channel CC.chan_room <> "*", UcxChat.RoomChannel # "ucxchat:"
channel CC.chan_user <> "*", UcxChat.UserChannel # "user:"
channel CC.chan_system <> "*", UcxChat.SystemChannel # "system:"
# ...
end
# user_channel.ex
# ...
intercept ["room:join", "room:leave", "room:mention", "user:state", "direct:new"]
#...
def handle_out("room:join", msg, socket) do
%{room: room} = msg
UserSocket.push_message_box(socket, socket.assigns.channel_id, socket.assigns.user_id)
update_rooms_list(socket)
clear_unreads(room, socket)
{:noreply, subscribe([room], socket)}
end
def handle_out("room:leave" = ev, msg, socket) do
%{room: room} = msg
debug ev, msg, "assigns: #{inspect socket.assigns}"
socket.endpoint.unsubscribe(CC.chan_room <> room)
update_rooms_list(socket)
{:noreply, assign(socket, :subscribed, List.delete(socket.assigns[:subscribed], room))}
end
# ...
defp subscribe(channels, socket) do
# debug inspect(channels), ""
Enum.reduce channels, socket, fn channel, acc ->
subscribed = acc.assigns[:subscribed]
if channel in subscribed do
acc
else
socket.endpoint.subscribe(CC.chan_room <> channel)
assign(acc, :subscribed, [channel | subscribed])
end
end
end
# ...
end
クライアントの状態、エラー メッセージなど、特定のユーザーに関連するすべてのイベントにも user_channel を使用します。