./ct_report/coverage/mongoose_config.COVER.html

1 -module(mongoose_config).
2
3 %% API
4 -export([start/0,
5 stop/0,
6 get_config_path/0,
7 lookup_opt/1,
8 get_opt/2,
9 get_opt/1]).
10
11 %% Test API, do not use outside of test suites, options set here are not cleaned up by stop/0
12 -export([set_opt/2,
13 unset_opt/1]).
14
15 %% Shell utilities intended for debugging and system inspection
16 -export([config_state/0,
17 config_states/0]).
18
19 -ignore_xref([set_opt/2, unset_opt/1, config_state/0, config_states/0]).
20
21 -include("mongoose.hrl").
22
23 -type key() :: atom() | host_type_key().
24 -type host_type_key() :: {atom(), mongooseim:host_type_or_global()}.
25
26 %% Top-level key() followed by inner_key() for each of the nested maps
27 -type key_path() :: [key() | inner_key()].
28 -type inner_key() :: atom() | binary() | integer() | string() | tuple().
29
30 -type value() :: atom() | binary() | integer() | string() | [value()] | tuple() | map().
31
32 -export_type([host_type_key/0, key/0, key_path/0, value/0]).
33
34 -spec start() -> ok.
35 start() ->
36 76 Path = get_config_path(),
37 76 State = mongoose_config_parser:parse_file(Path),
38 76 persistent_term:put(mongoose_config_state, State),
39 76 set_opts(State).
40
41 -spec stop() -> ok | {error, not_started}.
42 stop() ->
43 76 try persistent_term:get(mongoose_config_state) of
44 State ->
45 76 unset_opts(State),
46 76 persistent_term:erase(mongoose_config_state),
47 76 ok
48 catch
49 _:_ ->
50
:-(
{error, not_started}
51 end.
52
53 %% @doc Get the filename of the ejabberd configuration file.
54 %% The filename can be specified with: erl -config "/path/to/mongooseim.toml".
55 %% It can also be specified with the environment variable EJABBERD_CONFIG_PATH.
56 %% If not specified, the default value 'mongooseim.toml' is assumed.
57 -spec get_config_path() -> string().
58 get_config_path() ->
59 109 DefaultPath = case os:getenv("EJABBERD_CONFIG_PATH") of
60
:-(
false -> ?CONFIG_PATH;
61 109 Path -> Path
62 end,
63 109 application:get_env(mongooseim, config, DefaultPath).
64
65 -spec set_opts(mongoose_config_parser:state()) -> ok.
66 set_opts(State) ->
67 76 Opts = mongoose_config_parser:get_opts(State),
68 76 lists:foreach(fun({Key, Value}) -> set_opt(Key, Value) end, Opts).
69
70 -spec unset_opts(mongoose_config_parser:state()) -> ok.
71 unset_opts(State) ->
72 76 Opts = mongoose_config_parser:get_opts(State),
73 76 lists:foreach(fun unset_opt/1, proplists:get_keys(Opts)).
74
75 -spec set_opt(key() | key_path(), value()) -> ok.
76 set_opt([Key], Value) ->
77
:-(
set_opt(Key, Value);
78 set_opt([Key | Rest], Value) ->
79 13 set_opt(Key, set_nested_opt(get_opt(Key), Rest, Value));
80 set_opt(Key, Value) ->
81 6312 persistent_term:put({?MODULE, Key}, Value).
82
83 -spec unset_opt(key() | key_path()) -> ok.
84 unset_opt([Key]) ->
85
:-(
unset_opt(Key);
86 unset_opt([Key | Rest]) ->
87 1 set_opt(Key, unset_nested_opt(get_opt(Key), Rest));
88 unset_opt(Key) ->
89 3898 persistent_term:erase({?MODULE, Key}),
90 3898 ok.
91
92 %% @doc Use instead of get_opt(Key, undefined)
93 -spec lookup_opt(key() | key_path()) -> {ok, value()} | {error, not_found}.
94 lookup_opt(Key) ->
95 67348 try get_opt(Key) of
96 50111 Value -> {ok, Value}
97 catch
98 3517 error:badarg -> {error, not_found}; % missing persistent term
99 13720 error:{badkey, _} -> {error, not_found} % missing map key
100 end.
101
102 % @doc Returns Default if the option does not exist
103 -spec get_opt(key() | key_path(), value()) -> value().
104 get_opt(Key, Default) ->
105 65575 try
106 65575 get_opt(Key)
107 catch
108 12 error:badarg -> Default; % missing persistent term
109 37650 error:{badkey, _} -> Default % missing map key
110 end.
111
112 %% @doc Fails if the option does not exist
113 -spec get_opt(key() | key_path()) -> value().
114 get_opt([Key | Rest]) ->
115 457799 Config = persistent_term:get({?MODULE, Key}),
116 457696 lists:foldl(fun maps:get/2, Config, Rest);
117 get_opt(Key) ->
118 1045440 persistent_term:get({?MODULE, Key}).
119
120 -spec config_state() -> mongoose_config_parser:state().
121 config_state() ->
122
:-(
persistent_term:get(mongoose_config_state).
123
124 -spec config_states() -> [mongoose_config_parser:state()].
125 config_states() ->
126
:-(
config_states(mongoose_cluster:all_cluster_nodes()).
127
128 -spec config_states([node()]) -> [mongoose_config_parser:state()].
129 %% @doc Returns config states from all nodes in cluster
130 %% State from the local node comes as head of a list
131 config_states(Nodes) ->
132
:-(
{States, FailedNodes} = rpc:multicall(Nodes, ?MODULE, config_state, [], 30000),
133
:-(
case FailedNodes of
134 [] ->
135
:-(
States;
136 [_|_] ->
137
:-(
erlang:error(#{issue => config_state_failed,
138 cluster_nodes => Nodes,
139 failed_nodes => FailedNodes})
140 end.
141
142 %% Internal functions
143
144 set_nested_opt(M, [Key], Value) ->
145 13 M#{Key => Value};
146 set_nested_opt(M, [Key | Path], Value) ->
147
:-(
M#{Key => set_nested_opt(maps:get(Key, M), Path, Value)}.
148
149 unset_nested_opt(M, [Key]) ->
150 1 maps:remove(Key, M);
151 unset_nested_opt(M, [Key | Path]) ->
152
:-(
M#{Key := unset_nested_opt(maps:get(Key, M), Path)}.
Line Hits Source