3

私はリアルタイムイベントを処理するためにエリクシールチャンネルを使ってアプリケーションを書いています。クライアントあたり1つのソケットが開かれ、複数のチャネルを多重化することができると私は理解しています。だから私のアプリは、ユーザーが複数のグループチャットの一部であるチャットアプリケーションです。私はMessageChannelという1つのPhoenix Channelを持っています。そこでは、joinメソッドがダイナミックトピックを扱います。フェニックスチャンネル - ソケットごとに複数のチャンネル

def join("groups:" <> group_id, payload, socket) do 
.... 

あまりにも正しいのは!/ 3もボブにそのメッセージを送信する放送、ジョンはグループ/トピックAにメッセージを送信すると、ボブが唯一のグループ/トピックB.に参加しながら、ジョンはグループ/トピックAとBに参加しましょう? handle_inにはメッセージが送信されたトピック/グループのコンテキストがありません。

グループAに送信されたイベントをBobが受信しないようにするにはどうすればよいでしょうか?

答えて

4

handle_inにはメッセージが送信されたトピック/グループのコンテキストがありません。

Phoenix.Channel.broadcast/3が呼び出されると、明らかにそれないいる(署名から明らかではない)メッセージに関連付けられたトピック。 broadcast/3への呼び出しは、ソケットを使用して作られているので、

def broadcast(socket, event, message) do 
    %{pubsub_server: pubsub_server, topic: topic} = assert_joined!(socket) 
    Server.broadcast pubsub_server, topic, event, message 
end 

は、そのパターンは、現在のトピックをマッチし、その後、基礎となるServer.broadcast/4を呼び出します:あなたはon this line of channel.exを開始するコードを見ることができます。

(私が好きな人は好奇心が強いですが、これは基本的にの呼び出しを行い、設定されたpubsub実装サーバーにコールをルーティングします。おそらくpg2を使用しますが...だから、)

、私はPhoenix.Channel docsを読んでから、この動作は明らかではありません見つけましたが、彼らはIncoming Eventsにphoenixframeworkチャンネルページで明示的に状態ください:

broadcast!/3はこのソケットのトピックに関するすべての参加クライアントに通知し、起動しますそのhandle_out/3コールバック。

「これはこのソケットのトピックでしか放送されていません。 、あなたの例では

ので:サブトピックペアの名前空間、例えば「メッセージ」、「123メッセージ:」 - 文字列のトピックまたはトピック

トピック:彼らはのように、同じページ上のトピックを定義しますサブトピックペアの名前空間文字列は"groups:A""groups:B"です。ジョンは、クライアント上でこれらのトピックを両方とも個別にサブスクライブする必要があります。したがって、同じソケットを使用していても、実際には2つの異なるチャネルへの参照があります。あなたは、クライアントからのチャネル上でメッセージを送信するために行くとき、あなたはトピックを持っている唯一のチャネルを使用している次に

let channelA = this.socket.channel("groups:A", {}); 
let channelB = this.socket.channel("groups:B", {}); 

:だからあなたはjavascriptのクライアントを使用していると仮定すると、チャネルの作成は次のようになります上で見たように、サーバー上でパターンを一致させます。

channelA.push(msgName, msgBody); 
1

免責事項:チャネルの内部動作を見たことはありません。この情報は、アプリケーションでチャネルを初めて使用したときのものです。

誰かが別のグループに参加すると(join/3のパターンマッチングに基づいて)、別のチャンネル(ソケット)を介した接続が行われます。したがって、AへのブロードキャストはAのメンバーにのみメッセージを送信しません。

チャンネルモジュールはGenServerと似ていますが、結合は若干start_linkと似ています。新しいサーバー(プロセス)がスピンされます(ただし、まだ存在していない場合のみ)。

モジュールの内部動作を無視して、既存のチャネルとは異なる名前でチャネルに参加すると、一意のチャネルに参加していることを理解することができます。チャンネルにブロードキャストする場合、そのチャンネルのメンバーだけがメッセージを受け取ることを信頼することもできます。

たとえば、私のアプリケーションでは、1人のユーザーだけに接続したいユーザーチャネルがあります。結合はdef join("agent:" <> _agent, payload, socket)のようになります。エージェントは単なる電子メールアドレスです。このチャネルにメッセージをブロードキャストすると、単一のエージェントだけがメッセージを受信します。また、すべてのエージェントが参加するオフィスチャネルがあり、すべてのエージェントにメッセージを受信させたいときにブロードキャストします。

これが役に立ちます。

+0

など、私はまた、クライアントの状態、エラーメッセージなどの特定のユーザーに関連するすべてのイベントのためにuser_channelを使用

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 

しかし、私から1つのソケットが複数のトピックを処理することを理解している。リクエストがhandle_inに来ると、どのトピックがメッセージを受信して​​送信しているのか分からない。ブロードキャストはソケットレベルで発生します。 – ed1t

+1

私はこのコメントで答えようとしていましたが、大きすぎました。ソケットレベルで 'broadcast/3'が発生するのは間に合わないが、ソケットは@Jason Harrelsonと同じように現在の話題を知っている。 (私は楽しいチャンネルの内部に潜んでいたが、それは必要ではない。) – ibgib

0

実際には、ソケットのルーティングはchannel APIを使用して、プロジェクトのソケットモジュールであなたのトピックを定義する方法に基づいて行われます。スラッククローンについては、私は3つのチャンネルを使います。私は、プレゼンス更新、ユーザーチャネル、ルームチャネルを処理するシステムレベルのチャネルを持っています。

任意のユーザは、0または1チャネルに加入しています。ただし、ユーザーは複数のチャンネルを購読することができます。

特定の部屋に出るメッセージについては、ルームチャンネルでブロードキャストします。

特定の部屋の未読メッセージ、通知、バッジを検出すると、私はユーザーチャネルを使用します。各ユーザーチャネルには、ユーザーが購読しているルームの一覧も保存されます(クライアントのサイドバーに表示されます)。

このすべてのトリックは、カップルのチャンネルAPIを使用して、主intercepthandle_outMy.Endpoint.subscribe、およびhandle_info(%Broadcast{},socket)されます。

  • 私は、ブロードキャストされたメッセージをキャッチして無視したい、または送信する前にそれを送信するために使用します。ユーザチャネルで
  • 、私はあなたが購読すると、あなたがトピック、イベント、および放送メッセージのペイロードを含ん%Broadcast{}構造体でhandle_infoコールを取得する部屋のチャンネル
  • から放送イベントをサブスクライブ。ここで

私のコードのいくつ一部です:

+0

ヘルプ/フィードバックありがとう。スタックオーバーフローの最初の日(寄稿者として)。 –

関連する問題