Current section
Files
Jump to
Current section
Files
lib/slipstream/events.ex
defmodule Slipstream.Events do
@moduledoc false
require Logger
alias Phoenix.Socket.Message
alias __MODULE__.{
MessageReceived,
ReplyReceived,
HeartbeatAcknowledged,
TopicJoinSucceeded,
TopicJoinFailed,
TopicJoinClosed,
TopicLeft,
TopicLeaveAccepted,
PingReceived,
PongReceived,
ChannelClosed
}
alias Slipstream.Connection.State
@doc """
Maps a message from the remote websocket server to an internally known
Slipstream event
The connection state may need to be taken into consideration. It holds
information about the `ref` fields on messages and whether or not they belong
to joins or leaves.
`server_message` is either a `%Phoenix.Socket.Message{}` or `:ping` or `:pong`.
`connection_state` is the GenServer state of the connection process.
"""
@spec map(atom() | %Message{}, %State{}) :: struct()
def map(server_message, connection_state)
# coveralls-ignore-start
def map(:ping, _state), do: %PingReceived{}
def map(:pong, _state), do: %PongReceived{}
def map({:close, _, _}, _state), do: %ChannelClosed{reason: :closed_by_remote}
# coveralls-ignore-stop
def map(
%Message{
topic: topic,
event: event,
payload: payload,
ref: ref
},
_state
)
when ref == nil do
%MessageReceived{topic: topic, event: event, payload: payload}
end
def map(
%Message{
topic: "phoenix",
event: "phx_reply",
payload: %{"response" => response, "status" => "ok"},
ref: ref
},
_state
)
when map_size(response) == 0 do
%HeartbeatAcknowledged{ref: ref}
end
# a reply in which join_ref == ref is a reply to a request to join a topic
def map(
%Message{
topic: topic,
event: "phx_reply",
payload: %{"response" => response, "status" => status},
ref: ref,
join_ref: join_ref
},
_state
)
when ref != nil and ref == join_ref do
type = if status == "ok", do: TopicJoinSucceeded, else: TopicJoinFailed
struct(type, topic: topic, ref: ref, response: response)
end
def map(
%Message{
topic: topic,
event: "phx_reply",
payload: %{"response" => _response, "status" => _status} = payload,
ref: ref
},
state
)
when ref != nil do
if State.leave_ref?(state, ref) do
%TopicLeaveAccepted{topic: topic}
else
%ReplyReceived{
topic: topic,
reply: ReplyReceived.to_reply(payload),
ref: ref
}
end
end
def map(
%Message{
topic: topic,
event: "phx_error",
payload: payload,
ref: ref
},
state
) do
true = State.join_ref?(state, ref)
%TopicJoinClosed{topic: topic, reason: {:error, payload}, ref: ref}
end
def map(
%Message{
topic: topic,
event: "phx_close",
payload: payload,
ref: _ref
},
_state
)
when map_size(payload) == 0 do
%TopicLeft{topic: topic}
end
def map(message, _state) do
# coveralls-ignore-start
Logger.debug(
"#{inspect(__MODULE__)} received unknown message #{inspect(message)}"
)
# coveralls-ignore-stop
nil
end
end