Hi I am trying to reimplement whatsapp functionality using elixir phoenix. I am having a problem figuring out the following: if all people in the chat room has received the message, I want to send the owner of the message status "received" so that he can show double tick sign. However how do you broadcast to one particular client?
Asked
Active
Viewed 3,647 times
7
-
Check up this question: http://stackoverflow.com/questions/37373766/phoenix-return-ecto-query-results-to-a-specific-client/37375057#37375057 – simo Jun 08 '16 at 10:58
-
@simo The question is a bit off, because there client A sends the message and receives the message as well. What I need is: client A sends the message and only client B receives some feedback – almeynman Jun 08 '16 at 11:51
-
I think its a good idea to dedicate a topic for the client B only, then you can broadcast to that topic, otherwise I don't know how to exclude a specific user, have a look here: http://stackoverflow.com/questions/37279779/how-to-exclude-some-users-when-broadcast – simo Jun 08 '16 at 12:05
-
@simo I see. Dedicating seems quite complicated, especially in a group chat, where each person need his separate topic. I was just thinking that each socket has an id. and If I can contruct socket from id I can push messages at it. However I do not know how to do that – almeynman Jun 08 '16 at 12:21
-
Dedicating a topic for each user is easy, use the pattern matching for the topic name, as `def join("users:" <> user_id, _params, socket) do` – simo Jun 08 '16 at 12:34
-
@simo Actually I might go with your solution. I was just thinking that having a separate topic just for that small use case would be overkill. But I might need it anyways for other stuff. Thanks for help – almeynman Jun 08 '16 at 12:51
-
I don't know if having a topic per each user is would be overkill or not? I am not sure, although I am applying this in my project, after all, its a process for each user.. erlang will do the heavy lifting, but I didn't test that, I will test it using TSung tool if you know it, its very good to test with phoenix.. – simo Jun 08 '16 at 14:00
-
@simo never heard of it, but will give it a try :). You can write an answer about user specific topic and I will accept it. I actually needed user specific topics anyways, so it is natural fit in my case – almeynman Jun 09 '16 at 07:29
1 Answers
13
You can solve this via topic per user, this can be easily implemented by pattern matching, notice the security validation also:
def join("users:" <> user_id, _params, socket) do
{user_id, _} = Integer.parse(user_id)
%{id: id} = socket.assigns[:user]
#prevent connection to solo channel of other users, but allow in development
case id == user_id || Mix.env == :dev do
true ->
{:ok, socket}
false ->
{:error, "This is not your solo channel!"}
end
end
As you would have stored the user from Repo.get
when the user connect to the socket at:
defmodule MyApp.UserSocket do
use Phoenix.Socket
def connect(%{"token" => token}, socket) do
case Phoenix.Token.verify(socket, "user", token, max_age: 1209600) do
{:ok, user_id} ->
socket = assign(socket, :user, Repo.get!(User, user_id))
{:ok, socket}
{:error, _} -> #...
end
end
end
And finally, you can send messages to a specific user out of socket context as:
YourAll.Endpoint.broadcast user_topic, "message", %{details: "etc"}
To test the performance, this is a very informative session in which Gary Rennie shows how to benchmark WebSockets using Tsung tool.

Ludovic Kuty
- 4,868
- 3
- 28
- 42

simo
- 23,342
- 38
- 121
- 218