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: %{} }} 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