Current section
Files
Jump to
Current section
Files
lib/locker/agent.ex
defmodule Relocker.Locker.Agent do
use GenServer
@behaviour Relocker.Locker
alias Relocker.Lock
alias Relocker.Utils
def child_spec, do: :none
def start_link(_opts) do
Agent.start_link(fn ->
HashDict.new
end, name: __MODULE__)
end
def lock(name, metadata, lease_time_secs, time) do
Agent.get_and_update(__MODULE__, fn state ->
case read(state, name, time) do
:error ->
lock = %Lock{name: name, secret: Utils.random_string(32), metadata: metadata, valid_until: time + lease_time_secs, lease_time: lease_time_secs}
state = HashDict.put(state, name, lock)
{{:ok, lock}, state}
_any ->
{:error, state}
end
end)
end
def read(name, time) do
Agent.get(__MODULE__, fn state ->
case read(state, name, time) do
:error ->
:error
lock ->
{:ok, lock}
end
end)
end
def extend(%Lock{} = lock, time) do
Agent.get_and_update(__MODULE__, fn state ->
result =
case read(state, lock.name, time) do
:error ->
:error
my_lock ->
if time <= my_lock.valid_until and my_lock.secret == lock.secret do
lock = %{lock | :valid_until => time + lock.lease_time}
state = HashDict.put(state, lock.name, lock)
{:ok, lock}
else
:error
end
end
{result, state}
end)
end
def unlock(%Lock{} = lock, time) do
Agent.get_and_update(__MODULE__, fn state ->
result = if HashDict.has_key? state, lock.name do
entry = HashDict.get state, lock.name
if entry.secret == lock.secret and time <= lock.valid_until do
state = HashDict.delete state, lock.name
:ok
else
:error
end
else
:error
end
{result, state}
end)
end
def reset do
Agent.get_and_update(__MODULE__, fn _ ->
{:ok, HashDict.new}
end)
end
defp read(state, name, time) do
if HashDict.has_key? state, name do
lock = HashDict.get state, name
if time <= lock.valid_until do
lock
else
:error
end
else
:error
end
end
end