Packages
grizzly
9.1.4
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/requests/request_runner.ex
defmodule Grizzly.Requests.RequestRunner do
@moduledoc false
# TODO: document ownership and timeouts
use GenServer
alias Grizzly.Report
alias Grizzly.Requests.Request
alias Grizzly.ZWave.Command, as: ZWaveCommand
def child_spec([_command, _node_id, _opts] = args) do
# Don't restart the command if there is a failure
# TODO: type out opts correctly!!
%{id: __MODULE__, start: {__MODULE__, :start_link, args}, restart: :temporary}
end
@spec start_link(Request.t(), [Grizzly.command_opt()]) :: GenServer.on_start()
def start_link(request, node_id, opts \\ []) do
opts = Keyword.merge([owner: self(), timeout: 15_000], opts)
GenServer.start_link(__MODULE__, [request, node_id, opts])
end
@spec handle_zip_command(pid(), ZWaveCommand.t()) ::
Report.t()
| :continue
| {:error, :nack_response}
| :retry
def handle_zip_command(runner, zip_packet) do
GenServer.call(runner, {:handle_zip_command, zip_packet})
end
@spec encode_command(pid()) :: binary()
def encode_command(runner) do
GenServer.call(runner, :encode)
end
@spec seq_number(pid()) :: Grizzly.seq_number()
def seq_number(runner) do
GenServer.call(runner, :seq_number)
end
@spec reference(pid()) :: reference()
def reference(runner) do
GenServer.call(runner, :reference)
end
def stop(runner) do
GenServer.stop(runner, :normal)
catch
:exit, {:noproc, _} -> :ok
end
@impl GenServer
def init([command, node_id, opts]) do
owner = Keyword.fetch!(opts, :owner)
timeout = Keyword.fetch!(opts, :timeout)
timeout_ref = start_timeout_counter(timeout)
opts = Keyword.merge(opts, timeout_ref: timeout_ref)
{:ok, Request.from_zwave_command(command, node_id, owner, opts)}
end
@impl GenServer
def handle_call(:seq_number, _from, request), do: {:reply, request.seq_number, request}
def handle_call({:handle_zip_command, zip_packet}, _from, request) do
case Request.handle_zip_command(request, zip_packet) do
{%Report{status: :inflight} = report, new_request} ->
new_request = update_timeout(new_request, report.queued_delay)
{:reply, report, new_request}
{%Report{status: :complete} = report, new_request} ->
{:stop, :normal, report, new_request}
{:continue, new_request} ->
{:reply, :continue, new_request}
{:retry, new_request} ->
{:reply, :retry, new_request}
end
end
def handle_call(:reference, _from, request) do
{:reply, request.ref, request}
end
def handle_call(:encode, _from, request) do
{:reply, Request.to_binary(request), request}
end
@impl GenServer
def handle_info(:timeout, request) do
# TODO: :command_timeout -> :request_timeout?
send(request.owner, {:grizzly, :command_timeout, self(), request})
{:stop, :normal, request}
end
defp update_timeout(%Request{} = request, time_in_seconds) do
_ = Process.cancel_timer(request.timeout_ref)
new_timeout_ref = start_timeout_counter(time_in_seconds * 1000 + 500)
%Request{request | timeout_ref: new_timeout_ref}
end
defp start_timeout_counter(timeout), do: Process.send_after(self(), :timeout, timeout)
end