Packages
livebook
0.13.3
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
Current section
Files
Jump to
Current section
Files
lib/livebook/runtime/evaluator/client_tracker.ex
defmodule Livebook.Runtime.Evaluator.ClientTracker do
# Keeps track of connected clients as reported to the runtime by the
# owner.
#
# Sends events to processes monitoring clients presence.
use GenServer
alias Livebook.Runtime
@doc """
Starts a new client tracker.
"""
@spec start_link(keyword()) :: GenServer.on_start()
def start_link(_opts \\ []) do
GenServer.start_link(__MODULE__, {})
end
@doc """
Registeres new connected clients.
"""
@spec register_clients(pid(), list(Runtime.client_id())) :: :ok
def register_clients(client_tracker, client_ids) do
GenServer.cast(client_tracker, {:register_clients, client_ids})
end
@doc """
Unregisteres connected clients.
"""
@spec unregister_clients(pid(), list(Runtime.client_id())) :: :ok
def unregister_clients(client_tracker, client_ids) do
GenServer.cast(client_tracker, {:unregister_clients, client_ids})
end
@doc """
Subscribes the given process to client presence events.
Returns the list of currently connected clients.
"""
@spec monitor_clients(pid(), pid) :: list(Runtime.client_id())
def monitor_clients(client_tracker, pid) do
GenServer.call(client_tracker, {:monitor_clients, pid})
end
@impl true
def init({}) do
{:ok, %{client_ids: MapSet.new(), subscribers: MapSet.new()}}
end
@impl true
def handle_cast({:register_clients, client_ids}, state) do
for client_id <- client_ids, pid <- state.subscribers do
send(pid, {:client_join, client_id})
end
state = update_in(state.client_ids, &Enum.into(client_ids, &1))
{:noreply, state}
end
def handle_cast({:unregister_clients, client_ids}, state) do
for client_id <- client_ids, pid <- state.subscribers do
send(pid, {:client_leave, client_id})
end
state =
update_in(state.client_ids, fn ids ->
Enum.reduce(client_ids, ids, &MapSet.delete(&2, &1))
end)
{:noreply, state}
end
@impl true
def handle_call({:monitor_clients, pid}, _from, state) do
Process.monitor(pid)
state = update_in(state.subscribers, &MapSet.put(&1, pid))
client_ids = MapSet.to_list(state.client_ids)
{:reply, client_ids, state}
end
@impl true
def handle_info({:DOWN, _ref, :process, pid, _reason}, state) do
state = update_in(state.subscribers, &MapSet.delete(&1, pid))
{:noreply, state}
end
end