Phoenix websocket: how to send message to one user

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

okay :slight_smile:

1 Like

I have a Notifier acting like a gateway between the chat system and Phoenix.

Whenever a user receive a message, it will be notified like this…

defmodule AppApiWeb.Notifier do
  require Logger
  alias AppApiWeb.Endpoint

  def notify(%{payload: %{from: from, to: to}, type: :ping}) do
    Endpoint.broadcast!("user:#{to}", "ping", %{from: from})
  end

  def notify(message) do
    Logger.debug(fn -> "Unknown notification #{inspect(message)}" end)
  end
end

Only the user of the channel can receive the message.

Here it is just a ping, but You can add a message if You want.

okay bro