Sassa
Sassa

Reputation: 2023

How to architecture a web-socket server with client subscription of specific responses in Phoenix?

I'm developing a web-socket server that I need to send real-time messages using Phoenix Framework to my clients.

The basic idea of my web-socket server is that a client can subscribe for some type of information and expect to receive only it, other clients would never receive it unless they subscribe to it too, the same information is broadcasted to every (and only) client subscribed to it in real-time.

Also, these information are separated in categories and sub categories, going down to 4 levels of categories.

So, for example, let's say I have 2 types of category information CatA, and CatB, each category can have sub categories, so CatA can have CatA.SubCatA and CatA.SubCatB sub categories, each sub categories can also have other subcategories and so on.

These information are generated by services, one for each root category (they handle all the information for the subcategories too), so we have CatAService and CatBService. These services needs to run as the server starts, always generating new information and broadcasting it to anyone that is subscribed to it.

Now, I have clients that will try to subscribe to these information, my solution for now is to have a channel for each information type available, so a client can join a channel to receive information of the channel's type.

For that I have something like that in the js code:

let channel = socket.channel("CatA:SubCatA:SubSubCatA", {})
channel.join()
channel.on("new_info", (payload) => { ... }

In this case, I would have a channel that all clients interested in SubSubCatA from SubCatA from CatA can join and a service for CatA that would generate and broadcast the information for all it's sub categories and so on.

I'm not sure if I was able to explain exactly what I want, but if something is not clear, please tell me what so I can better explain it, also, I made this (very bad) image as an example of how all the communication would happen https://ibb.co/fANKPb .

Also, note that I could only have one channel for each category and broadcast all the subcategories information for everyone that joined that category channel, but I'm very concerned about performance and network bandwidth, So my objective is to only send the information to only the clients that requested it.

Doing some tests here, it seems that If the client joins the channel as shown in the js code above, I can do this:

MyServerWeb.Endpoint.broadcast "CatA:SubCatA:SubSubCatA", "new_info", message

and that client (and all the other clients listening to that channel, but only then) will receive that message.

So, my question is divided in two parts, one is more generic and is what are the correct ways to achieve what I described above.

The second is if the solution I already came up is a good way to solve this since I'm not sure if the length of the string "CatA:SubCatA:SubSubCatA" creates an overhead when the server parses it or if there is some other limitation that I'm not aware.

Thanks!

Upvotes: 1

Views: 167

Answers (1)

script
script

Reputation: 2167

You have to make separate channels for each class of clients and depending upon the ids which you are getting, you can broadcast the messages after checking about the clients joining the channel

 def join("groups:" <> group_slug, _params, socket) do
%{team_id: team_id, current_user: user} = socket.assigns

case Repo.get_by(Group, slug: group_slug, team_id: team_id) do
  nil ->
    {:error, %{message: "group not found"}}
  group ->
    case GroupAuthorization.can_view?(group.id, user.id) do
      true ->
        messages = MessageQueries.group_latest_messages(group.id, user)
        json = MessageView.render("index.json", %{messages: messages})
        send self(), :after_join
        {:ok, %{messages: json}, assign(socket, :group, group)}
      false ->
        {:error, %{message: "unauthorized"}}
    end
end

end

This is an example of sending messages only to the users in groups which are subscribed and joined to the group. Hope this helps.

Upvotes: 1

Related Questions