/
registrar.ex
100 lines (82 loc) · 2.57 KB
/
registrar.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
defmodule Notary.Registrar do
use Agent
defmodule CallbackHandle do
@lifetime 60 * 1000
@type t :: %CallbackHandle{
provider: String.t(),
callback: String.t(),
issued_at: number(),
key: String.t(),
for_client: Notary.Client.t()
}
defstruct [:key, :provider, :callback, :issued_at, :for_client]
def is_expired?(%CallbackHandle{:issued_at => issued_at}) do
System.os_time(:millisecond) > issued_at + @lifetime
end
defp rand_key do
for _ <- 1..10, into: "", do: <<Enum.random(~c"0123456789abcdef")>>
end
@spec new(Notary.Client.t(), String.t(), String.t()) :: CallbackHandle.t()
def new(%Notary.Client{} = client, callback, provider) do
%CallbackHandle{
callback: callback,
provider: provider,
for_client: client,
key: rand_key(),
issued_at: System.os_time(:millisecond)
}
end
end
def start_link(_state) do
Agent.start_link(fn -> %{} end, name: __MODULE__)
end
def register(%CallbackHandle{} = handle) do
Agent.update(__MODULE__, fn old -> old |> Map.put(handle.key, handle) end)
handle
end
@spec issue(Notary.Client.t(), Keyword.t()) :: String.t()
@doc """
Issues a new `CallbackHandle` from a client object with a specified provider and callback, returning the handle key.
## Examples
```elixir
iex> client = Notary.Repo.all(from c in "clients", where: c.service == "Some Service") |> List.first
%Notary.Repo.Client{...}
iex> handle = Notary.Registrar.issue(client,
via: :google,
callback: "https://someserver.example.com/auth"
)
"0157650fba"
```
"""
def issue(client, options \\ []) do
provider = options |> Keyword.get(:via)
callback = options |> Keyword.get(:callback)
client
|> Notary.Registrar.CallbackHandle.new(callback, provider)
|> Notary.Registrar.register()
|> Map.get(:key)
end
@spec keys() :: [String.t()]
def keys do
Agent.get(__MODULE__, fn state -> state |> Map.keys() end)
end
@spec find(String.t()) :: {:ok, CallbackHandle.t()} | nil
def find(key) when is_binary(key) do
item = Agent.get(__MODULE__, fn state -> state |> Map.get(key, nil) end)
unless item |> is_nil do
{:ok, item}
else
nil
end
end
@spec unregister(String.t()) :: {:ok, CallbackHandle.t()} | {:not_found}
def unregister(key) do
case find(key) do
{:ok, handle} ->
Agent.update(__MODULE__, fn state -> state |> Map.drop([key]) end)
{:ok, handle}
nil ->
{:not_found}
end
end
end