elixirphoenix-frameworkphoenix-channels

How can I get Phoenix to join channels automatically when a client connects?


I'm using websocket transport with Phoenix Channels, but I'm trying to provide a clean API for consumers without a Phoenix.Socket client to use with just websockets.

For simplicity, I'd like to auto-subscribe users to various channels when they open a session.

Currently I have something like:

defmodule MyWeb.UserSocket do
  require Logger
  use Phoenix.Socket
  alias Exchange.{Account, ApiKey}

  channel "room:time", MyWeb.TimeChannel
  channel "alpha:*", MyWeb.AlphaChannel
  channel "beta:*", MyWeb.BetaChannel

  def connect(%{"api-key" => _} = params, socket, connect_info) do
    with %{"api-key" => api_key, "api-expires" => api_expires, "api-signature" => api_signature} <-
           params,
         {:ok, %ApiKey{} = key} <- ApiKey.fetch(api_key),
         {:ok, %Account{} = account} <-ApiKey.authorize(...)) do
      Logger.info("Authorized account #{account.account_id} via API key on websocket")

      #JOIN CHANNELS HERE

      {:ok, assign(socket, :account, account)}
    else
      {:error, e} ->
        Logger.error("Websocket auth error #{inspect(e)}")
        {:ok, socket}
    end
  end

end

What do I need to put in "Join Channels Here" to get it to subscribe?


Solution

  • The answer to this question was not to use Phoenix Channels on the interface, but write a separate Transport implementation that subscribed to Phoenix.

    I created a new Socket Transport by defining a new module:

    @behaviour Phoenix.Socket.Transport
    

    And provided a socked in endpoint.ex:

    socket "/realtime", MyWeb.MyCustomSocket, websocket: true
    

    This pattern follows a GenServer type layout. I subscribed to the Phoenix Channels I wanted in init and then re-emitted these events to the socket.

    This created a one-way websocket that doesn't require any knowledge of Socket to connect and listen to.