69 lines
1.8 KiB
Elixir
69 lines
1.8 KiB
Elixir
defmodule FarmbotCore.DepTracker.Table do
|
|
use GenServer
|
|
|
|
@doc false
|
|
def start_link({table, _registry_name} = args) do
|
|
GenServer.start_link(__MODULE__, args, name: table)
|
|
end
|
|
|
|
@doc "put data"
|
|
def put(table, {identifier, status}) do
|
|
GenServer.call(table, {:put, identifier, status})
|
|
end
|
|
|
|
@doc "get data"
|
|
def get(table, {kind, _} = identifier) do
|
|
:ets.match(table, {identifier, :"$2"})
|
|
|> Enum.map(fn
|
|
[local_id, status] -> {{kind, local_id}, status}
|
|
other -> raise("unknown data in ets table: #{table} data: #{inspect(other)}")
|
|
end)
|
|
end
|
|
|
|
def get(table, service_name) do
|
|
:ets.match(table, {service_name, :"$2"})
|
|
|> Enum.map(fn
|
|
[status] -> {service_name, status}
|
|
other -> raise("unknown data in ets table: #{table} data: #{inspect(other)}")
|
|
end)
|
|
end
|
|
|
|
@impl GenServer
|
|
def init({table, registry_name}) do
|
|
^table = :ets.new(table, [:named_table, read_concurrency: true])
|
|
|
|
state = %{table: table, registry: registry_name}
|
|
{:ok, state}
|
|
end
|
|
|
|
@impl GenServer
|
|
def handle_call({:put, identifier, status}, _from, state) do
|
|
case :ets.lookup(state.table, identifier) do
|
|
[{^identifier, ^status}] ->
|
|
# No change, so no notifications
|
|
:ok
|
|
|
|
[{^identifier, old_status}] ->
|
|
:ets.insert(state.table, {identifier, status})
|
|
dispatch(state, identifier, old_status, status)
|
|
|
|
[] ->
|
|
:ets.insert(state.table, {identifier, status})
|
|
dispatch(state, identifier, nil, status)
|
|
end
|
|
|
|
{:reply, :ok, state}
|
|
end
|
|
|
|
defp dispatch(state, identifier, old, new) do
|
|
kind = case identifier do
|
|
{kind, _} -> kind
|
|
kind -> kind
|
|
end
|
|
Registry.dispatch(state.registry, kind, fn entries ->
|
|
message = {state.table, identifier, old, new}
|
|
for {pid, _} <- entries, do: send(pid, message)
|
|
end)
|
|
:ok
|
|
end
|
|
end |