Packages
livebook
0.8.0
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/livebook/web_socket/server.ex
defmodule Livebook.WebSocket.Server do
@moduledoc false
use GenServer
require Logger
import Livebook.WebSocket.Client, only: [is_frame: 1]
alias Livebook.WebSocket.Client
defstruct [
:conn,
:websocket,
:caller,
:status,
:resp_headers,
:resp_body,
:ref,
closing?: false
]
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts)
end
@doc """
Connects the WebSocket client.
"""
def connect(pid, url, headers \\ []) do
GenServer.call(pid, {:connect, url, headers})
end
@doc """
Disconnects the WebSocket client.
"""
def disconnect(pid) do
GenServer.cast(pid, :close)
end
@doc """
Sends a message to the WebSocket server the message request.
"""
def send_message(socket, frame) when is_frame(frame) do
GenServer.cast(socket, {:send_message, frame})
end
## GenServer callbacks
@impl true
def init(_) do
{:ok, %__MODULE__{}}
end
@impl true
def handle_call({:connect, url, headers}, from, state) do
case Client.connect(url, headers) do
{:ok, conn, ref} -> {:noreply, %{state | conn: conn, ref: ref, caller: from}}
{:error, _reason} = error -> {:reply, error, state}
{:error, conn, reason} -> {:reply, {:error, reason}, %{state | conn: conn}}
end
end
@impl true
def handle_cast(:close, state) do
Client.disconnect(state.conn, state.websocket, state.ref)
{:stop, :normal, state}
end
def handle_cast({:send_message, frame}, state) do
case Client.send(state.conn, state.websocket, state.ref, frame) do
{:ok, conn, websocket} ->
{:noreply, %{state | conn: conn, websocket: websocket}}
{:error, %Mint.WebSocket{} = websocket, _reason} ->
{:noreply, %{state | websocket: websocket}}
{:error, conn, _reason} ->
{:noreply, %{state | conn: conn}}
end
end
@impl true
def handle_info(message, state) do
case Client.receive(state.conn, state.ref, state.websocket, message) do
{:ok, conn, websocket, response} ->
state = %{state | conn: conn, websocket: websocket}
{:noreply, reply(state, {:ok, response})}
{:error, conn, websocket, response} ->
state = %{state | conn: conn, websocket: websocket}
{:noreply, reply(state, {:error, response})}
{:error, conn, response} ->
state = %{state | conn: conn}
{:noreply, reply(state, {:error, response})}
{:error, _} ->
{:noreply, state}
end
end
# Private
defp reply(%{caller: nil} = state, response) do
Logger.warning("The caller is nil, so we can't reply the message: #{inspect(response)}")
state
end
defp reply(state, response) do
GenServer.reply(state.caller, response)
state
end
end