Current section

Files

Jump to
phoenix lib phoenix transports websocket.ex
Raw

lib/phoenix/transports/websocket.ex

defmodule Phoenix.Transports.WebSocket do
use Phoenix.Controller
use Phoenix.WebSocket
@moduledoc """
Handles WebSocket clients for the Channel Transport layer
## Configuration
By default, JSON encoding is used to broker messages to and from clients,
but the serializer is configurable via the Router's transport configuration:
config :my_app, MyApp.Router, transports: [
websocket_serializer: MySerializer
]
The `websocket_serializer` module needs only to implement the `encode!/1` and
`decode!/1` functions defined by the `Phoenix.Transports.Serializer` behaviour.
"""
alias Phoenix.Channel.Transport
alias Phoenix.Socket.Message
plug :action
def upgrade_conn(conn, _) do
put_private(conn, :phoenix_upgrade, {:websocket, __MODULE__}) |> halt
end
@doc """
Handles initalization of the websocket
"""
def ws_init(conn) do
router = router_module(conn)
serializer = Dict.fetch!(router.config(:transports), :websocket_serializer)
{:ok, %{router: router, sockets: HashDict.new, serializer: serializer}}
end
@doc """
Receives JSON encoded `%Phoenix.Socket.Message{}` from client and dispatches
to Transport layer
"""
def ws_handle(text, state = %{router: router, sockets: sockets, serializer: serializer}) do
text
|> serializer.decode!
|> Transport.dispatch(sockets, self, router)
|> case do
{:ok, sockets} -> %{state | sockets: sockets}
{:error, sockets, _reason} -> %{state | sockets: sockets}
end
end
@doc """
Receives `%Phoenix.Socket.Message{}` and sends encoded message JSON to client
"""
def ws_info(message = %Message{}, state = %{serializer: serializer}) do
reply(self, serializer.encode!(message))
state
end
@doc """
Handles Elixir messages sent to the socket process
Dispatches `"info"` event back through Tranport layer to all socket's channels
"""
def ws_info(data, state = %{sockets: sockets}) do
sockets = case Transport.dispatch_info(sockets, data) do
{:ok, socks} -> socks
{:error, socks, _reason} -> socks
end
%{state | sockets: sockets}
end
@doc """
Called on WS close. Dispatches the `leave` event back through Transport layer
"""
def ws_terminate(reason, %{sockets: sockets}) do
:ok = Transport.dispatch_leave(sockets, reason)
:ok
end
end