Current section

Files

Jump to
phoenix_client lib phoenix_client channel.ex
Raw

lib/phoenix_client/channel.ex

defmodule PhoenixClient.Channel do
use GenServer
alias PhoenixClient.{Socket, Message}
@default_timeout 5_000
def child_spec({socket, topic, genserver_opts}) do
%{
id: genserver_opts[:id] || __MODULE__,
start: {__MODULE__, :start_link, [socket, topic, genserver_opts]}
}
end
def child_spec({socket, topic}) do
child_spec({socket, topic, []})
end
def start_link(socket, topic, genserver_opts \\ []) do
GenServer.start_link(__MODULE__, {socket, topic}, genserver_opts)
end
def stop(pid) do
GenServer.call(pid, :leave)
GenServer.stop(pid)
end
def join(pid, params \\ %{}) do
GenServer.call(pid, {:join, params})
end
def leave(pid) do
GenServer.call(pid, :leave)
end
def push(pid, event, payload, timeout \\ @default_timeout) do
GenServer.call(pid, {:push, event, payload}, timeout)
end
def push_async(pid, event, payload) do
GenServer.cast(pid, {:push, event, payload})
end
def init({socket, topic}) do
{:ok,
%{
sender: nil,
socket: socket,
topic: topic,
pushes: []
}}
end
def handle_call({:join, params}, {pid, _ref} = from, %{socket: socket, topic: topic} = state) do
Socket.channel_link(socket, self(), topic)
push =
Socket.push(socket, %Message{
topic: topic,
event: "phx_join",
payload: params,
channel_pid: self()
})
{:noreply, %{state | sender: pid, pushes: [{from, push} | state.pushes]}}
end
def handle_call(:leave, _from, %{socket: socket, topic: topic} = state) do
Socket.channel_unlink(socket, self(), state.topic)
Socket.push(socket, %Message{
topic: topic,
event: "phx_leave",
payload: %{},
channel_pid: self()
})
{:reply, :ok, state}
end
def handle_call({:push, event, payload}, from, %{socket: socket, topic: topic} = state) do
push =
Socket.push(socket, %Message{
topic: topic,
event: event,
payload: payload,
channel_pid: self()
})
{:noreply, %{state | pushes: [{from, push} | state.pushes]}}
end
def handle_cast({:push, event, payload}, %{socket: socket, topic: topic} = state) do
message = %Message{topic: topic, event: event, payload: payload, channel_pid: self()}
Socket.push(socket, message)
{:noreply, state}
end
def handle_info(%Message{event: "phx_reply", ref: ref} = msg, %{pushes: pushes} = s) do
pushes =
case Enum.split_with(pushes, &(elem(&1, 1).ref == ref)) do
{[{from_ref, _push}], pushes} ->
%{"status" => status, "response" => response} = msg.payload
GenServer.reply(from_ref, {String.to_atom(status), response})
pushes
{_, pushes} ->
pushes
end
{:noreply, %{s | pushes: pushes}}
end
def handle_info(%Message{} = message, %{sender: pid, topic: topic} = state) do
send(pid, %{message | channel_pid: pid, topic: topic})
{:noreply, state}
end
end