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?
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.