Packages

A standalone Elixir implementation of the Libp2p networking stack

Current section

Files

Jump to
libp2p_elixir lib libp2p registry.ex
Raw

lib/libp2p/registry.ex

defmodule Libp2p.Registry do
@moduledoc """
Global registry for libp2p connection processes, indexed by PeerID.
"""
use GenServer
@spec start_link(keyword()) :: GenServer.on_start()
def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: Keyword.get(opts, :name, __MODULE__))
end
@spec register(binary(), pid(), atom() | pid()) :: :ok
def register(peer_id, pid, name \\ __MODULE__) when is_binary(peer_id) and is_pid(pid) do
GenServer.cast(name, {:register, peer_id, pid})
end
@spec unregister(binary(), atom() | pid()) :: :ok
def unregister(peer_id, name \\ __MODULE__) when is_binary(peer_id) do
GenServer.cast(name, {:unregister, peer_id})
end
@spec get(binary(), atom() | pid()) :: nil | pid()
def get(peer_id, name \\ __MODULE__) when is_binary(peer_id), do: GenServer.call(name, {:get, peer_id})
@spec list(atom() | pid()) :: [{binary(), pid()}]
def list(name \\ __MODULE__), do: GenServer.call(name, :list)
@impl true
def init(_opts), do: {:ok, %{conns: %{}}}
@impl true
def handle_call({:get, peer_id}, _from, st) do
pid = Map.get(st.conns, peer_id)
pid = if is_pid(pid) and Process.alive?(pid), do: pid, else: nil
{:reply, pid, st}
end
def handle_call(:list, _from, st) do
out =
st.conns
|> Enum.filter(fn {_k, pid} -> is_pid(pid) and Process.alive?(pid) end)
{:reply, out, st}
end
@impl true
def handle_cast({:register, peer_id, pid}, st) do
Process.monitor(pid)
{:noreply, %{st | conns: Map.put(st.conns, peer_id, pid)}}
end
def handle_cast({:unregister, peer_id}, st) do
{:noreply, %{st | conns: Map.delete(st.conns, peer_id)}}
end
@impl true
def handle_info({:DOWN, _ref, :process, pid, _reason}, st) do
conns =
st.conns
|> Enum.reject(fn {_peer_id, p} -> p == pid end)
|> Map.new()
{:noreply, %{st | conns: conns}}
end
end