-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathsettings_storage.ex
More file actions
155 lines (132 loc) · 3.82 KB
/
settings_storage.ex
File metadata and controls
155 lines (132 loc) · 3.82 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
defmodule LiveDebugger.API.SettingsStorage do
@available_settings [
:dead_view_mode,
:garbage_collection,
:debug_button,
:tracing_enabled_on_start,
:dead_liveviews,
:highlight_in_browser
]
@moduledoc """
API for managing settings storage. In order to properly use invoke `init/0` at the start of application.
It uses Erlang's DETS (Disk Erlang Term Storage).
Settings are retrieved in this order:
1. locally saved file (inside `_build/*/live_debugger/` directory)
2. default values
Available settings are: `#{Enum.join(@available_settings, ", ")}`.
"""
@callback init() :: :ok
@callback save(atom(), any()) :: :ok | {:error, term()}
@callback get(atom()) :: any()
@callback get_all() :: map()
@doc """
Initializes dets table and read config values to fetch initial settings.
It should be called when application starts.
"""
@spec init() :: :ok
def init(), do: impl().init()
@doc """
Saves a setting into the storage.
"""
@spec save(setting :: atom(), value :: any()) :: :ok | {:error, term()}
def save(setting, value) when setting in @available_settings do
impl().save(setting, value)
end
@doc """
Gets a setting from the storage.
If the setting is not found, it returns default value.
"""
@spec get(setting :: atom()) :: any()
def get(setting) when setting in @available_settings do
impl().get(setting)
end
@doc """
Gets all settings from the storage.
"""
@spec get_all() :: map()
def get_all() do
impl().get_all()
end
@doc """
List of available settings
"""
@spec available_settings() :: [atom()]
def available_settings(), do: @available_settings
defp impl() do
Application.get_env(
:live_debugger,
:api_settings_storage,
__MODULE__.Impl
)
end
defmodule Impl do
@moduledoc false
alias LiveDebugger.API.SettingsStorage
@behaviour SettingsStorage
@default_settings %{
dead_view_mode: true,
garbage_collection: true,
debug_button: true,
tracing_enabled_on_start: true,
dead_liveviews: false,
highlight_in_browser: true
}
@table_name :lvdbg_settings
@filename "live_debugger_saved_settings"
@impl true
def init() do
{:ok, _} =
:dets.open_file(@table_name,
auto_save: :timer.seconds(1),
file: file_path()
)
# On init we populate dets in the following order:
# 1. Check if user has set value in config, if so, we prioritize it
# 2. Otherwise, we check if value is saved in dets
# 3. If value is not saved in dets, we use default value
#
# This way when user specifies setting value in config, it will be always used on start.
# User still can change it in settings, and until next app restart it will be used.
SettingsStorage.available_settings()
|> Enum.map(fn setting ->
{setting, fetch_setting(setting)}
end)
|> Enum.each(fn {setting, value} -> save(setting, value) end)
:ok
end
@impl true
def save(setting, value) do
:dets.insert(@table_name, {setting, value})
end
@impl true
def get(setting) do
fetch_setting(setting)
end
@impl true
def get_all() do
SettingsStorage.available_settings()
|> Enum.map(fn setting ->
{setting, fetch_setting(setting)}
end)
|> Enum.into(%{})
end
defp fetch_setting(setting) do
with {:error, :not_saved} <- get_from_dets(setting) do
@default_settings[setting]
end
end
defp get_from_dets(setting) do
case :dets.lookup(@table_name, setting) do
[{^setting, value}] ->
value
_ ->
{:error, :not_saved}
end
end
defp file_path() do
:live_debugger
|> Application.app_dir(@filename)
|> String.to_charlist()
end
end
end