Current section
Files
Jump to
Current section
Files
lib/pidex_server.ex
defmodule Pidex.PdxServer do
require Logger
use GenServer
@type proc_state :: %{output: number, pidex: Pidex.t(), state: Pidex.State.t()}
def set_time_units(pid, ts_unit) when is_atom(ts_unit) do
GenServer.cast(pid, {:put_ts, nil, ts_unit})
end
@spec set_time(GenServer.server(), number) :: :ok
def set_time(pid, ts) when is_number(ts) do
GenServer.cast(pid, {:put_ts, ts, nil})
end
def set_time(pid) do
GenServer.cast(pid, {:put_ts, nil, nil})
end
@spec set( GenServer.server(), Enum.t() ) :: :ok
def set(pid, opts) do
pidex = GenServer.call(pid, {:get, :pidex})
pidex = struct!(pidex, opts)
GenServer.cast(pid, {:put, :pidex, pidex})
end
@spec settings( GenServer.server() ) :: :ok
def settings(pid) do
GenServer.call(pid, {:get, :pidex})
end
@spec state( GenServer.server() ) :: any
def state(pid) do
GenServer.call(pid, {:get, :state})
end
@spec reset(GenServer.server(), any) :: :ok
def reset(pid, state \\ %Pidex.State{}) do
GenServer.cast(pid, {:put, :state, state})
pid |> set_time()
end
@spec output(GenServer.server()) :: number
def output(pid) do
GenServer.call(pid, {:get, :output})
end
@spec update_async(GenServer.server(), number, Pidex.timestamp() | nil ) :: :ok
def update_async(pid, process_value, ts \\ nil) when is_number(process_value) do
GenServer.cast(pid, {:process_update, process_value, ts})
end
@spec update(GenServer.server(), number, Pidex.timestamp() | nil) :: any
def update(pid, process_value, ts \\ nil) when is_number(process_value) do
GenServer.call(pid, {:process_update, process_value, ts})
end
def start_link(args \\ [], opts \\ []) do
# IO.puts("pidex server args: #{inspect args}")
# IO.puts("pidex server opts: #{inspect opts}")
GenServer.start_link(__MODULE__, args, opts ++ [name: __MODULE__])
end
def init(args) do
# IO.puts("pidex server args: #{inspect args}")
# GenServer(self(), :update_time)
ts_unit = args[:ts_unit] || :second
set_time(self())
{:ok,
%{pidex: args[:pidex] || args[:settings] || %Pidex{},
state: args[:state] || %Pidex.State{},
ts_unit: ts_unit,
ts_factor: args[:ts_factor] || 1.0,
output: nil}}
end
def handle_call({:get, key}, _from, proc_state) do
{:reply, Map.get(proc_state, key), proc_state }
end
def handle_call({:process_update, process_value, ts}, _from, proc_state) do
# IO.puts "process_update: #{System.monotonic_time(:second)} "
proc_state = process_update(proc_state, process_value, ts)
{:reply, proc_state[:output], proc_state}
end
def handle_cast({:put, key, value}, proc_state) do
{:noreply, Map.put(proc_state, key, value)}
end
def handle_cast({:put_ts, ts, ts_unit}, proc_state) do
# IO.puts "update_time: #{ts}"
ts = ts || System.monotonic_time(proc_state.ts_unit || ts_unit)
state = %{ proc_state.state | ts: ts }
proc_state =
proc_state
|> Map.put(:ts_unit, ts_unit || proc_state.ts_unit)
|> Map.put(:state, state)
{:noreply, proc_state}
end
def handle_cast({:process_update, process_value, ts}, proc_state) do
proc_state = process_update(proc_state, process_value, ts)
{:noreply, proc_state}
end
def process_update(proc, process_value, ts) when is_nil(ts) do
ts = System.monotonic_time(proc.ts_unit)
# IO.puts "process_update ts set: #{ts}"
process_update(proc, process_value, ts)
end
def process_update(proc, process_value, ts) do
# IO.puts "process_update ts!: #{ts}"
{output, state} =
{proc.pidex, proc.state, process_value, ts}
|> Pidex.update()
# IO.puts "pid out: #{inspect output} <#{inspect state}>"
%{ proc | state: state, output: output}
end
end