| 1 |
|
defmodule Agent.Harness do |
| 2 |
|
@moduledoc "Routes ask/tell messages to agents based on registration kind." |
| 3 |
|
import Agent.Remote, only: [find: 1] |
| 4 |
|
import Registry, only: [lookup: 2] |
| 5 |
|
import String, only: [to_atom: 1] |
| 6 |
|
import :global, only: [whereis_name: 1] |
| 7 |
|
import Enum, only: [find_value: 3] |
| 8 |
|
import Node, only: [list: 0] |
| 9 |
|
import Utils.Normalize, only: [name: 1] |
| 10 |
|
|
| 11 |
|
def dispatch(recipient, message, :ask) do |
| 12 |
17 |
recipient |> locate() |> ask!(recipient, message) |
| 13 |
|
end |
| 14 |
|
|
| 15 |
|
def dispatch(recipient, message, :tell) do |
| 16 |
31 |
recipient |> locate() |> tell!(recipient, message) |
| 17 |
|
end |
| 18 |
|
|
| 19 |
|
defp locate(recipient) do |
| 20 |
48 |
entry(recipient) |> nearby(recipient) |
| 21 |
|
end |
| 22 |
|
|
| 23 |
:-( |
defp nearby([], recipient), do: global(bare(recipient)) |> fallback(recipient) |
| 24 |
48 |
defp nearby(found, _recipient), do: found |
| 25 |
|
|
| 26 |
|
defp global(n) do |
| 27 |
:-( |
atom = to_atom(n) |
| 28 |
:-( |
result = whereis_name({atom |> to_string() |> name(), :puppet}) |
| 29 |
:-( |
result |> local() |> remote(atom, result) |
| 30 |
|
end |
| 31 |
|
|
| 32 |
:-( |
defp local(:undefined), do: :undefined |
| 33 |
:-( |
defp local(found), do: found |> wrap() |
| 34 |
|
|
| 35 |
:-( |
defp remote(:undefined, atom, _), do: list() |> search(atom) |
| 36 |
:-( |
defp remote(found, _, _), do: found |
| 37 |
|
|
| 38 |
:-( |
defp search(nodes, atom), do: find_value(nodes, :undefined, &fetch(&1, atom)) |> wrap() |
| 39 |
|
|
| 40 |
:-( |
defp fetch(node, atom) do |
| 41 |
:-( |
:erpc.call(node, :global, :whereis_name, [{atom |> to_string() |> name(), :puppet}], 5000) |
| 42 |
|
catch |
| 43 |
:-( |
_, _ -> nil |
| 44 |
|
end |
| 45 |
|
|
| 46 |
:-( |
defp fallback([], recipient), do: bare(recipient) |> find() |> wrap() |
| 47 |
:-( |
defp fallback(found, _), do: found |
| 48 |
|
|
| 49 |
:-( |
defp wrap(:undefined), do: [] |
| 50 |
:-( |
defp wrap(pid), do: [{pid, %{kind: :puppet}}] |
| 51 |
|
|
| 52 |
|
defp entry(recipient) do |
| 53 |
48 |
clean = bare(recipient) |
| 54 |
48 |
normalized = clean |> to_atom() |> Kernel.to_string() |> name() |
| 55 |
48 |
lookup(ElitaRegistry, normalized) |
| 56 |
|
end |
| 57 |
|
|
| 58 |
:-( |
defp bare("el." <> n), do: n |
| 59 |
48 |
defp bare(n), do: n |
| 60 |
|
|
| 61 |
48 |
defp impl(:native), do: Agent.Kind.Native |
| 62 |
:-( |
defp impl(:headless), do: Agent.Kind.Puppet |
| 63 |
:-( |
defp impl(:puppet), do: Agent.Kind.Puppet |
| 64 |
|
|
| 65 |
|
defp ask!([{_pid, %{kind: kind}}] = entry, recipient, message) do |
| 66 |
17 |
impl(kind).ask(entry, recipient, message) |
| 67 |
|
end |
| 68 |
|
|
| 69 |
:-( |
defp ask!([], recipient, _message), do: "unknown: #{recipient}" |
| 70 |
|
|
| 71 |
|
defp tell!([{_pid, %{kind: kind}}] = entry, recipient, message) do |
| 72 |
31 |
impl(kind).forward(entry, recipient, message) |
| 73 |
|
end |
| 74 |
|
|
| 75 |
:-( |
defp tell!([], recipient, _message), do: "unknown: #{recipient}" |
| 76 |
|
end |