how to send message to different user in phoenix framework chat app

1.6k Views Asked by At

I am working with phoenix framework to create different type chat app. In my case, we have chat rooms but not functioning as a normal chat room.

Every user has his own room he can join to his room using different devices (mobile, pc, some other sources).

User A has his own room and user B has his own room, these two members do not connect to a single room as in a normal scenario in the real world.

Now my user A wants to send a message to user B

message data eg:

from : A  
to :B  
message : test message   

This is a snippet from app.js I used to connect to the user's specific room :

let room = socket.channel("room:"+  user, {})
room.on("presence_state", state => {
  presences = Presence.syncState(presences, status)
  console.log(presences)
  render(presences)
})

This is the snippet from back-end for join room function
/web/channel/RoomChannel.ex

  def join("room:" <> _user, _, socket) do
    send self(), :after_join
    {:ok, socket}
  end

But now I am stuck in the middle because I cannot find a way to send messages between users. eg: Cannot identify way to deliver User A's message to user B using this specific scenario

This is the basic architect of this chat app :

enter image description here

This is rest of the code in Roomchannel file

def handle_info(:after_join, socket) do
    Presence.track(socket, socket.assigns.user, %{
      online_at: :os.system_time(:millisecond)

    })
    push socket, "presence_state", Presence.list(socket)
    {:noreply, socket}
  end

  def handle_in("message:new", message, socket) do
    broadcast! socket, "message:new", %{
      user: socket.assigns.user,
      body: message,
      timestamp: :os.system_time(:millisecond)
    }
    milisecondstime = :os.system_time(:millisecond)
    [room, user] = String.split(Map.get(socket, :topic), ":")
    data = Poison.encode!(%{"created_at" => :os.system_time(:millisecond), "updated_at" => :os.system_time(:millisecond), "uuid" => UUID.uuid1(), "date" => :os.system_time(:millisecond), "from" => user, "to" => user, "message" => message})
    Redix.command(:redix, ["SET", UUID.uuid1(), data]) 
    {:noreply, socket}
  end

Can anyone show me some way by which I can pass messages between user's chat rooms?

I'm using redis to store data and this is the basic chat app I am following thanks to that developer.

1

There are 1 best solutions below

0
On

Look into Phoenix.Endpoint.broadcast You can send message to a given topic using the broadcast/3 function


Another way you can go about this is to subscribe each user to a unique private topic when the user joins the channel join function

def join("room:" <> _user, _, socket) do
    send self(), :after_join
    MyApp.Endpoint.subscribe("private-room:" <> user) # subscribe the connecting client to their private room
    {:ok, socket}
end

Then in handle_in("message:new",message, socket) extract the receipient user id from the message payload and call

Endpoint.broadcast

def handle_in("message:new", message, socket) do

    MyApp.Endpoint.broadcast!("private-room:" <> to_user , "message:new",%{
        user: socket.assigns.user,
        body: message,
        timestamp: :os.system_time(:millisecond)
   }) #sends the message to all connected clients for the to_user

    {:noreply, socket}
end