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.ex
defmodule Livebook.WebSocket do
@moduledoc false
alias Livebook.WebSocket.Client
alias LivebookProto.{Request, SessionRequest}
defmodule Connection do
defstruct [:conn, :websocket, :ref]
@type t :: %__MODULE__{
conn: Client.conn(),
websocket: Client.websocket(),
ref: Client.ref()
}
end
@type proto :: SessionRequest.t()
@typep header :: {String.t(), String.t()}
@typep headers :: list(header())
@doc """
Connects with the WebSocket server for given URL and headers.
"""
@spec connect(String.t(), headers()) ::
{:ok, Connection.t(), :connected | {atom(), proto()}}
| {:error, Connection.t(), String.t() | LivebookProto.Error.t()}
def connect(url, headers \\ []) do
with {:ok, conn, ref} <- Client.connect(url, headers) do
conn
|> Client.receive(ref)
|> handle_receive(ref)
end
end
@doc """
Disconnects the given WebSocket client.
"""
@spec disconnect(Connection.t()) :: :ok
def disconnect(%Connection{} = connection) do
Client.disconnect(connection.conn, connection.websocket, connection.ref)
end
@doc """
Sends a request to the given server.
"""
@spec send_request(Connection.t(), proto()) ::
{:ok, Connection.t()}
| {:error, Connection.t(), Client.ws_error() | Client.mint_error()}
def send_request(%Connection{} = connection, %struct{} = data) do
type = LivebookProto.request_type(struct)
message = Request.new!(type: {type, data})
binary = {:binary, Request.encode(message)}
case Client.send(connection.conn, connection.websocket, connection.ref, binary) do
{:ok, conn, websocket} ->
{:ok, %{connection | conn: conn, websocket: websocket}}
{:error, %Mint.WebSocket{} = websocket, reason} ->
{:error, %{connection | websocket: websocket}, reason}
{:error, conn, reason} ->
{:error, %{connection | conn: conn}, reason}
end
end
@dialyzer {:nowarn_function, receive_response: 1}
@doc """
Receives a response from the given server.
"""
@spec receive_response(Connection.t()) :: Client.receive_fun()
def receive_response(%Connection{conn: conn, websocket: websocket, ref: ref}) do
conn
|> Client.receive(ref, websocket)
|> handle_receive(ref)
end
defp handle_receive({:ok, conn, websocket, :connected}, ref) do
{:ok, %Connection{conn: conn, websocket: websocket, ref: ref}, :connected}
end
defp handle_receive({:ok, conn, websocket, %Client.Response{body: response}}, ref) do
%{type: result} = LivebookProto.Response.decode(response)
{:ok, %Connection{conn: conn, websocket: websocket, ref: ref}, result}
end
defp handle_receive({:error, conn, %Client.Response{body: nil, status: status}}, ref) do
{:error, %Connection{conn: conn, ref: ref}, Plug.Conn.Status.reason_phrase(status)}
end
defp handle_receive({:error, conn, %Client.Response{body: response}}, ref) do
%{type: {:error, error}} = LivebookProto.Response.decode(response)
{:error, %Connection{conn: conn, ref: ref}, error}
end
end