83 lines
2.2 KiB
Elixir
83 lines
2.2 KiB
Elixir
defmodule Frajtano.Agent do
|
|
alias Frajtano.BackingAgent
|
|
use GenServer
|
|
require Logger
|
|
|
|
def start_link(args) do
|
|
GenServer.start_link(__MODULE__, nil, [{:name, __MODULE__} | args])
|
|
end
|
|
|
|
@impl true
|
|
def init(_) do
|
|
{
|
|
:ok,
|
|
%{},
|
|
}
|
|
end
|
|
|
|
def initial_backing_agents() do
|
|
initial_backing_agents = Application.fetch_env!(:frajtano, :initial_backing_agents)
|
|
|> Enum.map(&GenServer.call(__MODULE__, {:add_backing_agent, &1}))
|
|
Logger.info("Started initial backing_agents: #{inspect initial_backing_agents}")
|
|
end
|
|
|
|
# select: list of specs, where specs are a tuple of match, guards, and outputs
|
|
# match is {key, pid, value}, :"$1" is a match variable
|
|
def backing_agent_paths() do
|
|
Registry.select(Frajtano.BackingAgents, [{{:"$1", :_, :_}, [], [:"$1"]}])
|
|
end
|
|
|
|
def backing_agent_pids() do
|
|
Registry.select(Frajtano.BackingAgents, [{{:_, :"$1", :_}, [], [:"$1"]}])
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:identities}, _from, _state) do
|
|
idents =
|
|
Task.async_stream(
|
|
backing_agent_pids(),
|
|
&{&1, BackingAgent.identities(&1)},
|
|
ordered: false,
|
|
on_timeout: :kill_task
|
|
)
|
|
|
|
idents = for {:ok, {backing_agent, {:ok, idents}}} <- idents, do: {idents, backing_agent}
|
|
|
|
{
|
|
:reply,
|
|
{:ok, idents |> Enum.flat_map(&elem(&1, 0)) |> Enum.uniq},
|
|
for({idents, backing_agent} <- idents, {key, _comment} <- idents, into: %{}, do: {key, backing_agent})
|
|
}
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:sign, {key, _, _} = req}, _from, state) do
|
|
{:reply, BackingAgent.sign(state[key], req), state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:add_backing_agent, spec}, _from, state) do
|
|
case BackingAgent.start(spec) do
|
|
{:ok, _} -> {:reply, :ok, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
def identities() do
|
|
GenServer.call(__MODULE__, {:identities})
|
|
end
|
|
|
|
def sign(request) do
|
|
# Signing can take some time, as a password may need to be entered or similar
|
|
GenServer.call(__MODULE__, {:sign, request}, :infinity)
|
|
end
|
|
|
|
def assimilate(path) do
|
|
GenServer.call(__MODULE__, {:add_backing_agent, {:socket, path}})
|
|
end
|
|
|
|
def spawn_backing_agent(spec) do
|
|
GenServer.call(__MODULE__, {:add_backing_agent, {:spawn, spec}})
|
|
end
|
|
end
|