Phoenix Channels - 每个插槽多个通道

ed1*_*d1t 3 sockets elixir elixir-framework phoenix-framework phoenix-channels

我正在使用Elixir Channels编写一个应用程序来处理实时事件.我知道每个客户端将打开1个套接字,并且可以在其上复用多个通道.所以我的应用程序是一个聊天应用程序,用户是多个群聊的一部分.我有一个名为MessageChannel的Phoenix Channel,其中join方法将处理动态主题.

def join("groups:" <> group_id, payload, socket) do
....
Run Code Online (Sandbox Code Playgroud)

假设John加入群组/主题A和B而Bob只加入群组/主题B.当john向群组/主题A发送消息时,广播!/ 3也会将该消息发送给Bob太正确了吗?因为handle_in没有发送消息的主题/组的上下文.

如何处理它以便Bob不会收到发送给A组的事件.我设计得对吗?

小智 5

因为handle_in没有发送消息的主题/组的上下文.

Phoenix.Channel.broadcast/3被调用时,显然它确实具有与消息相关联的主题(签名中不明显).你可以看到从这行channel.ex开始的代码:

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

因此,当broadcast/3使用套接字进行调用时,它模式匹配当前主题,然后调用底层Server.broadcast/4.

(如果你像我一样好奇,这反过来调用底层PubSub.broadcast/3,它会做一些分配魔术来将调用路由到你配置的pubsub实现服务器,很可能使用pg2,但我离题...)

因此,我发现这种行为在阅读Phoenix.Channel文档时并不明显,但是他们在传入事件的phoenixframework频道页面中明确说明了这一点:

broadcast!/3将通知此套接字主题的所有已加入的客户端并调用其handle_out/3回调.

所以它只是在"这个插座的主题"上播出.他们在同一页面上定义主题:

topic - 字符串主题或主题:子主题对命名空间,例如"messages","messages:123"

所以在你的例子中,"主题"实际上是主题:子主题对命名空间字符串:"groups:A""groups:B".John必须在客户端上单独订阅这两个主题,因此您实际上会引用两个不同的通道,即使它们使用相同的套接字.因此,假设您使用的是javascript客户端,则通道创建看起来像这样:

let channelA = this.socket.channel("groups:A", {});
let channelB = this.socket.channel("groups:B", {});
Run Code Online (Sandbox Code Playgroud)

然后,当您从客户端在通道上发送消息时,您只使用具有在服务器上匹配模式的主题的通道,如上所述.

channelA.push(msgName, msgBody);
Run Code Online (Sandbox Code Playgroud)