Files
frajtano/lib/agent.ex
2024-09-20 16:00:22 +01:00

79 lines
1.8 KiB
Elixir

defmodule Frajtano.Agent do
alias Frajtano.Peer
use GenServer
def start_link(args) do
GenServer.start_link(__MODULE__, nil, [{:name, __MODULE__} | args])
end
@impl true
def init(_) do
{
:ok,
%{
keys: %{}
},
{:continue, :init_peers}
}
end
@impl true
def handle_continue(:init_peers, state) do
for peer <- Application.fetch_env!(:frajtano, :initial_peers), do: {:ok, _} = Peer.start(peer)
{:noreply, state}
end
@impl true
def handle_call({:identities}, _from, state) do
idents =
for(
{_, peer, :worker, _} <- DynamicSupervisor.which_children(Frajtano.Peer),
is_pid(peer),
do: peer
)
|> Task.async_stream(fn peer ->
with {:ok, idents} <- Peer.identities(peer),
do: {:ok, {idents, peer}}
end)
# Double :ok-wrapping because of Task.async_stream
idents = for {:ok, {:ok, {idents, peer}}} <- idents, do: {idents, peer}
{
:reply,
{:ok, for({idents, _} <- idents, ident <- idents, do: ident)},
%{
state
| keys:
for({idents, peer} <- idents, {key, _comment} <- idents, into: %{}, do: {key, peer})
}
}
end
@impl true
def handle_call({:sign, {key, _, _} = req}, _from, state) do
{:reply, Peer.sign(state.keys[key], req), state}
end
@impl true
def handle_call({:add_peer, path}, _from, state) do
# TODO: deduplicate peers by socket path
case Peer.start(path) do
{:ok, _} -> {:reply, :ok, state}
{:error, error} -> {:reply, {:error, error}, state}
end
end
def identities(agent \\ __MODULE__) do
GenServer.call(agent, {:identities})
end
def sign(agent \\ __MODULE__, request) do
GenServer.call(agent, {:sign, request})
end
def add_peer(agent \\ __MODULE__, path) do
GenServer.call(agent, {:add_peer, path})
end
end