-
Notifications
You must be signed in to change notification settings - Fork 36
/
registry.ex
121 lines (107 loc) · 3.39 KB
/
registry.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
defmodule GSS.Registry do
@moduledoc """
Google spreadsheets core authorization.
Automatically updates access token after expiration.
"""
use GenServer
@typedoc """
State of Google Cloud API :
%{
auth: %Goth.Token{
expires: 1453356568,
token: "ya29.cALlJ4HHWRvMkYB-WsAR-CZnexE459yA7QPqKg3nei1y2T7-iqmbcgxb8XrTATNn_Blim",
type: "Bearer"
}
}
"""
@type state :: map()
@auth_scope "https://www.googleapis.com/auth/spreadsheets"
@spec start_link() :: {:ok, pid}
def start_link do
initial_state = %{
active_sheets: %{}
}
GenServer.start_link(__MODULE__, initial_state, name: __MODULE__)
end
@spec init(state) :: {:ok, state}
def init(state) do
{:ok, state}
end
@doc """
Get account authorization token.
"""
@spec token() :: String.t
def token do
GenServer.call(__MODULE__, :token)
end
@doc """
Add or replace Google Spreadsheet in a registry.
"""
@spec new_spreadsheet(String.t, pid, Keyword.t) :: :ok
def new_spreadsheet(spreadsheet_id, pid, opts \\ []) do
GenServer.call(__MODULE__, {:new_spreadsheet, spreadsheet_id, pid, opts})
end
@doc """
Fetch Google Spreadsheet proccess by it's id in the registry.
"""
@spec spreadsheet_pid(String.t, Keyword.t) :: pid
def spreadsheet_pid(spreadsheet_id, opts \\ []) do
GenServer.call(__MODULE__, {:spreadsheet_pid, spreadsheet_id, opts})
end
@doc """
Get account authorization token, issue new token in case old has expired.
"""
def handle_call(:token, _from, %{auth: %{
token: token,
expires: expires
}} = state) do
if (expires < :os.system_time(:seconds)) do
new_state = Map.put(state, :auth, refresh_token())
{:reply, new_state.auth.token, new_state}
else
{:reply, token, state}
end
end
def handle_call(:token, _from, state) do
new_state = Map.put(state, :auth, refresh_token())
{:reply, new_state.auth.token, new_state}
end
@doc """
Update :active_sheets registry record.
"""
def handle_call(
{:new_spreadsheet, spreadsheet_id, pid, opts},
_from,
%{active_sheets: active_sheets} = state
) when is_bitstring(spreadsheet_id) and is_pid(pid) do
registry_id = id(spreadsheet_id, opts)
new_active_sheets = Map.put(active_sheets, registry_id, pid)
new_state = Map.put(state, :active_sheets, new_active_sheets)
{:reply, :ok, new_state}
end
@doc """
Get pid of sheet in :active_sheets registry.
"""
def handle_call(
{:spreadsheet_pid, spreadsheet_id, opts},
_from,
%{active_sheets: active_sheets} = state
) when is_bitstring(spreadsheet_id) do
registry_id = id(spreadsheet_id, opts)
{:reply, Map.get(active_sheets, registry_id, nil), state}
end
@spec refresh_token() :: map()
defp refresh_token do
{:ok, token} = Goth.Token.for_scope(@auth_scope)
token
end
@spec id(String.t, Keyword.t) :: String.t
defp id(spreadsheet_id, opts) do
list_name = Keyword.get(opts, :list_name)
if is_bitstring(list_name) do
"#{spreadsheet_id}!#{list_name}"
else
spreadsheet_id
end
end
end