ejabberd的config模块
-record(state, {opts = [] :: [acl:acl() | local_config()], hosts = [] :: [binary()], override_local = false :: boolean(), override_global = false :: boolean(), override_acls = false :: boolean()}).
-callback opt_type(atom()) -> function() | [atom()].
如果要behaviour这个模块 则要实现 opt_type方法
ejabberd_config:start 创建local_config 数据表,读取配置文件
读取顺序为:1、application:get_env(config)
2、application:get_env(ejabberd, file)
3、os:getenv("EJABBERD_CONFIG_PATH") 默认的此为 "//etc/ejabberd/ejabberd.yml"
4、CONFIG_PATH -> <<"ejabberd.cfg">>
然后根据配置文件路径读取(read_file):
读取过程中会分析文件的路径(相对或者绝对、filename:pathtype),用到了filename、file模块
然后进行到consult 方法 1、如果配置文件为.yml .yaml结尾则利用p1_yaml:decode_from_file方法(p1_yaml为项目的扩展application)
-module(p1_yaml). decode_from_file(File, Opts) -> case file:read_file(File) of {ok, Data} -> decode(Data, Opts); Err -> Err end. decode(Data, Opts) -> nif_decode(Data, make_flags(Opts)).
可以看到最后的nif_decode方法进入了c的扩展
static ErlNifFunc nif_funcs[] = { {"nif_decode", 2, decode} };
然后利用parserl方法解析
2、其他的则为file:consult,利用file模块的consult方法读取
读取后根据include_modules_configs参数决定是否加在扩展模块的配置文件(默认开启)
则要执行以下代码
Files = [{filename:rootname(filename:basename(F)), F} || F <- filelib:wildcard(ext_mod:config_dir() ++ "/*.{yml,yaml}") ++ filelib:wildcard(ext_mod:modules_dir() ++ "/*/conf/*.{yml,yaml}")], [proplists:get_value(F,Files) || F <- proplists:get_keys(Files)];
根据include_files参数决定配置文件里面是否包含配置子文件(默认开启)
根据replace_macros是否开启决定是否替换macros
然后执行下面的代码
State1 = lists:foldl(fun process_term/2, State, Head ++ Tail), State1#state{opts = compact(State1#state.opts)}.
然后对module顾虑无用的参数validate_opts
然后执行下面代码则执行完毕
{MegaSecs, Secs, _} = now(), UnixTime = MegaSecs*1000000 + Secs, SharedKey = case erlang:get_cookie() of nocookie -> p1_sha:sha(randoms:get_string()); Cookie -> p1_sha:sha(jlib:atom_to_binary(Cookie)) end, State1 = set_option({node_start, global}, UnixTime, State), State2 = set_option({shared_key, global}, SharedKey, State1), set_opts(State2).
set_opts把配置文件内容写入数据表local_config中