Phoenix websocket: how to send message to one user

Hello,
I’m new to Phoenix and I’m following this tutorial https://hexdocs.pm/phoenix/channels.html to implement something similar to chat application as described in that tutorial.
That article talks about how to broadcast a message, I want to send a message to a particular user. And I couldn’t find something similar to send. How I can do that.
Also, to do this, do I have to save all the connected socket objects in another process’s state, maybe using a map which maps username -> socket.

1 Like

One way to do it would be to subscribe your users to a particular topic individual to each one of them. Then you would have a way of sending particular messages to them using that topic and simply broadcasting to it, effectively working as if you were “sending” them a message. Of course this only accounts for when the receiving user is online and subscribed to his own topic.

2 Likes

Thanks, this should work.
How costly/cheap is creating a topic?

1 Like

AFAIK the phoenix team is not yet charging for creating topics, so it’s free.

(j/k)

The cost will probably be one entry with one term in an ETS table? How that translates into “really” useful information I’m not sure.

4 Likes

The trick is to broadcast to a specific user with

socket.endpoint.broadcast!(“user:#{id}”, message, payload)

7 Likes

Quite cheap, I wouldn’t worry about it at this point.

3 Likes

video tutorial for user to user private messages

1 Like

I might be able to do this if you’re still interested.

1 Like

I just wonder if there’s a way to do it without having to create additional channels per user/use specific user IDs. In my use case there will be no registration and there will be no preexisting IDs unless I generate a random one for each new user who connects, which is doable but doesn’t feel exactly natural.

I wonder if there’s a way for Presence to actually fetch specific processes/sockets, e.g. to fetch the first socket connection of the first user that joined, and pair her with the second user as soon as the second user joins. It doesn’t seem exactly easy though so far.

I meant to make a new post but the tag selection seems broken at the moment.

You can access the underlying websocket like in Broadcast to socket without channel and communicate with the user directly via it, if that’s what you need.

I guess my problem is how I can keep track of the socket IDs/PIDs. I think I’m still a bit confused over all the terminologies and their relations between each other.

In short, my use case:

  • There is a lobby.
  • Whenever enough number (e.g. 3) of users joined the lobby, they will be teamed up, each assigned a role to start a conversation.
  • They should then be removed from the lobby.
  • The next 3 users to join repeat this process, etc.

My question is, when the third user joins, how can I:

  • know that he’s the third user
  • locate the first two users (i.e. find the PIDs of their sockets I guess)
  • send a customized message to each user (because each has a different role)
  • remove all of them from whatever tracking mechanism I’m using

The problem with normal Channel and Presence mechanisms is that they don’t seem to be able to hold any global state.

One mechanism that I’ve thought of with Presence (likely to be incorrect):

def handle_info(:after_lobby_join, socket) do
  Presence.track(socket, "lobby", %{
    pid: self()
  })

  {:noreply, socket}
end

def handle_info(:start, socket) do
  pid1 = hd(Presence.list(socket)["lobby"][:metas])[:pid]
  # Start the conversation by sending messages individually to pid1 and pid2
  ...
  untrack(pid1, "my_app:lobby", "lobby")
  {:ok, socket}
end

In the example you linked there is the use of Registry. Are you suggesting to record the PIDs of the first two users in Registry under keys such as first_user, second_user, and then look them up and send messages to them via send(socket_pid, {:socket_push, :text, Poison.encode!(%{"oh" => "my"})})?

1 Like

If I didn’t need distribution (although it would be possible to add later), I’d probably have a genserver tracking the new users.

def handle_info({:new_user, socket}, [{us1, ref1}, {us2, ref2}]) do
  # we had 2 users, a new one joined, so that's 3
  user_sockets = [socket, us1, us2]
  # we can create a room for them now
  create_new_room(user_sockets)
  # and clean the state
  Enum.each([ref1, ref2], fn ref ->
    Process.demonitor(ref)
  end)
  {:noreply, []}
end

def handle_info({:new_user, socket}, waiting_user_sockets) do
  # otherwise just add the new users to the waiting users list
  ref = Process.monitor(socket)
  {:noreply, [{socket, ref} | waiting_user_sockets]}
end

def handle_info({:DOWN, ref, :process, _object, _reason}, waiting_user_sockets) do
  # remove the disconnected socket
end
2 Likes

sorry for the late reply but yes

I don’t have the time to do anything like that nowadays.

I could send you a working example, if you’re still interested.

Hi Did u happen to make a video tutorial for user to user private messages?

Can you send me a working example?

I need your help in project i have been assigned ,i have to make api using elixir and Phoenix framework . I have made login / signup api but i have confusion in chat api ,i have to use websocket and store message , this is one to one using postgresql, tables made user and chat table, in which field are
user:
field :email, :string
field :mobileno, :string
field :password_hash, :string
field :username, :string
field :password, :string, virtual: true

chat:
field :message, :string
field :flag, :integer
field :id_from ,belongs_to :user,Talk2me.Accounts.User
field :id_to ,belongs_to :user,Talk2me.Accounts.Users

reply me soon.

used guardian jwt

i need a example to create one to one chatapp
also api for chat

I am not using api for chat, I do it with websocket.

The trick is to have at least a channel per user, identified by id.

Whenever a message occur (either by api, or websocket) You get the id of the destination user, then it’s simple to use the user channel and broadcast to it.

can you plz upload your project in github so i can get idea of websocket

Searching for Phoenix Chat will returns a lot of result.

Like this 3 parts serie about Phoenix and Chat