Skip to content

Commit

Permalink
Configuration rework
Browse files Browse the repository at this point in the history
  • Loading branch information
kalta committed Jun 13, 2014
1 parent 20d58dc commit 7f1c0e6
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 129 deletions.
5 changes: 0 additions & 5 deletions include/nksip.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,8 @@
%% ===================================================================

-define(VERSION, "0.4.0").
-define(SUPPORTED, [<<"100rel">>, <<"timer">>, <<"path">>, <<"outbound">>, <<"gruu">>]).
-define(ACCEPT, [{<<"*/*">>, []}]).
-define(ALLOW, <<"INVITE,ACK,CANCEL,BYE,OPTIONS,INFO,PRACK,UPDATE,"
"SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH">>).

-define(MSG_ROUTERS, 8).
-define(SRV_TIMEOUT, 45000).
-define(DEFAULT_TCP_KEEPALIVE, 120).
-define(DEFAULT_UDP_KEEPALIVE, 25).
-define(DEFAULT_EVENT_EXPIRES, 60).
Expand Down
2 changes: 2 additions & 0 deletions priv/app.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[
{nksip, [
{sync_call_time, 5000},
{other, other}
]},

{lager, [
Expand Down
2 changes: 1 addition & 1 deletion samples/nksip_pbx/src/nksip_pbx_sipapp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
-define(TIME_CHECK, 10000).

-include("../../../include/nksip.hrl").
-include("../../../plugins/include/nksip_registrar.hrl").
-include("../../../plugins/nksip_registrar/include/nksip_registrar.hrl").


%% @doc Starts a new SipApp, listening on port 5060 for udp and tcp and 5061 for tls,
Expand Down
1 change: 0 additions & 1 deletion src/nksip.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@
cowboy
]},
{env, [
{sync_call_time, 0}
]}
]}.
2 changes: 1 addition & 1 deletion src/nksip.erl
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ call(App, Term, Time) ->
case find_app(App) of
{ok, AppId} ->
Time1 = case Time of
default -> AppId:config_sync_call_time();
default -> nksip_config_cache:sync_call_time();
_ -> Time
end,
gen_server:call(AppId, Term, Time1);
Expand Down
8 changes: 6 additions & 2 deletions src/nksip_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

-compile({no_auto_import,[put/2]}).

-define(MINUS_CSEQ, 46111468). % Lower values to debug
-define(MINUS_CSEQ, 46111468). % Generate lower values to debug


%% ===================================================================
Expand Down Expand Up @@ -132,9 +132,13 @@ init([]) ->
?MODULE:put(current_cseq, nksip_lib:cseq()-?MINUS_CSEQ),
case parse_config(application:get_all_env(nksip), []) of
{ok, EnvConfig1} ->

?P("ENV: ~p", [EnvConfig1]),

EnvConfig2 = nksip_lib:defaults(EnvConfig1, default_config()),
GlobalOpts = [Key || {Key, _} <- default_config()],
AppConfig = nksip_lib:delete(EnvConfig2, GlobalOpts),
AppConfig = nksip_lib:delete(EnvConfig2,
[included_applications|GlobalOpts]),
CacheConfig = [
{global_id, nksip_lib:luid()},
{local_ips, nksip_lib:get_local_ips()},
Expand Down
6 changes: 3 additions & 3 deletions src/nksip_outbound.erl
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ make_contact(Req, Contact, _Opts) ->
{ok, nksip:optslist()} | {error, Error}
when Error :: flow_failed | forbidden.

proxy_opts(#sipmsg{class={req, 'REGISTER'}}=Req, Opts) ->
proxy_opts(#sipmsg{app_id=AppId, class={req, 'REGISTER'}}=Req, Opts) ->
#sipmsg{
app_id = AppId,
vias = Vias,
transport = Transp,
contacts = Contacts
} = Req,
Supported = nksip_lib:get_value(supported, Opts, ?SUPPORTED),
Supported = AppId:config_supported(),
Opts1 = case
lists:member(path, Opts) andalso
nksip_sipmsg:supported(<<"path">>, Req) andalso
Expand Down Expand Up @@ -107,7 +107,7 @@ proxy_opts(#sipmsg{class={req, 'REGISTER'}}=Req, Opts) ->

proxy_opts(Req, Opts) ->
#sipmsg{app_id=AppId, routes=Routes, contacts=Contacts, transport=Transp} = Req,
Supported = nksip_lib:get_value(supported, Opts, ?SUPPORTED),
Supported = AppId:config_supported(),
case
nksip_sipmsg:supported(<<"outbound">>, Req) andalso
lists:member(<<"outbound">>, Supported)
Expand Down
237 changes: 123 additions & 114 deletions src/nksip_sipapp_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@

default_config() ->
[
{allow, "INVITE,ACK,CANCEL,BYE,OPTIONS,INFO,PRACK,UPDATE,"
"SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH"},
{supported, "100rel,timer,path,outbound,gruu"},
{timer_t1, 500}, % (msecs) 0.5 secs
{timer_t2, 4000}, % (msecs) 4 secs
{timer_t4, 5000}, % (msecs) 5 secs
Expand All @@ -62,20 +65,23 @@ default_config() ->
%% @private
parse_config(Opts) ->
try
Environment = nksip_config_cache:app_config(),
Defaults = nksip_lib:defaults(Environment, default_config()),
Opts1 = nksip_lib:defaults(Opts, Defaults),
{Opts2, RestOpts} = parse_opts(Opts1, [], []),
Plugins0 = proplists:get_all_values(plugins, Opts),
Plugins = parse_plugins(lists:flatten(Plugins0), []),
Opts1 = apply_defaults(Opts, Plugins),
Opts2 = parse_opts(Opts1, lists:reverse(Plugins), Opts1, []),
Plugins = sort_plugins(lists:flatten(Plugins0), []),
Opts3 = [{plugins, Plugins}|Opts2],
Cache = cache_syntax(Opts3),
Opts4 = parse_plugins_opts(RestOpts, Plugins, Opts3),
Cache = cache_syntax(Opts4),
PluginCallbacks = plugin_callbacks_syntax([nksip|Plugins]),
AppName = nksip_lib:get_value(name, Opts3, nksip),
AppName = nksip_lib:get_value(name, Opts4, nksip),
AppId = nksip_sipapp_srv:get_appid(AppName),
PluginModules = [
list_to_atom(atom_to_list(Plugin) ++ "_sipapp")
|| Plugin <- Plugins
],
Module = nksip_lib:get_value(module, Opts3, nksip_sipapp),
Module = nksip_lib:get_value(module, Opts4, nksip_sipapp),
AppModules = [Module|PluginModules++[nksip_sipapp]],
AppCallbacks = get_all_app_callbacks(AppModules),
SipApp = [
Expand All @@ -90,36 +96,95 @@ parse_config(Opts) ->
end.


%% @private Computes all default config
apply_defaults(Opts, Plugins) ->
Base = nksip_lib:defaults(nksip_config_run:app_config(), default_config()),
Opts1 = nksip_lib:defaults(Opts, Base),
apply_defaults_plugins(Opts1, Plugins).
%% @private Parte the plugins list for the application
%% For each plugin, calls Plugin:version() to get the version, and
%% Plugin:deps() to get the dependency list ([Name::atom(), RE::binary()]).
%% it then builds a list of sorted list of plugin names, where every plugin
%% is inserted after all of its dependencies.
sort_plugins([Name|Rest], PlugList) when is_atom(Name) ->
case lists:keymember(Name, 1, PlugList) of
true ->
sort_plugins(Rest, PlugList);
false ->
case catch Name:version() of
Ver when is_list(Ver); is_binary(Ver) ->
case catch Name:deps() of
Deps when is_list(Deps) ->
case insert_plugins(PlugList, Name, Ver, Deps, []) of
{ok, PlugList1} ->
sort_plugins(Rest, PlugList1);
{insert, BasePlugin} ->
sort_plugins([BasePlugin, Name|Rest], PlugList)
end;
_ ->
throw({invalid_plugin, Name})
end;
_ ->
throw({invalid_plugin, Name})
end
end;

sort_plugins([], PlugList) ->
[Name || {Name, _} <- PlugList].


%% @private
apply_defaults_plugins(Opts, []) ->
Opts;
insert_plugins([{CurName, CurVer}=Curr|Rest], Name, Ver, Deps, Acc) ->
case lists:keytake(CurName, 1, Deps) of
false ->
insert_plugins(Rest, Name, Ver, Deps, Acc++[Curr]);
{value, {_, DepVer}, RestDeps} when is_list(DepVer); is_binary(DepVer) ->
case re:run(CurVer, DepVer) of
{match, _} ->
insert_plugins(Rest, Name, Ver, RestDeps, Acc++[Curr]);
nomatch ->
throw({incompatible_plugin, {CurName, CurVer, DepVer}})
end;
_ ->
throw({invalid_plugin, Name})
end;

apply_defaults_plugins(Opts, [Plugin|Rest]) ->
Opts1 = case catch Plugin:default_config() of
List when is_list(List) -> nksip_lib:defaults(Opts, List);
_ -> Opts
end,
apply_defaults_plugins(Opts1, Rest).
insert_plugins([], Name, Ver, [], Acc) ->
{ok, Acc++[{Name, Ver}]};

insert_plugins([], _Name, _Ver, [{DepName, _}|_], _Acc) ->
{insert, DepName}.



% %% @private Updates the configuration applying all defaults
% %% For config elements not defined in Opts, a default is taken from
% %% the environment's config, default_config() or the default_config() of each plugin
% apply_defaults(Opts, Plugins) ->
% Environment = nksip_config_cache:app_config(),
% Base = nksip_lib:defaults(Environment, default_config()),
% Opts1 = nksip_lib:defaults(Opts, Base),
% apply_defaults_plugins(Opts1, Plugins).


% %% @private
% apply_defaults_plugins(Opts, []) ->
% Opts;

% apply_defaults_plugins(Opts, [Plugin|Rest]) ->
% Opts1 = case catch Plugin:default_config() of
% List when is_list(List) -> nksip_lib:defaults(Opts, List);
% _ -> Opts
% end,
% apply_defaults_plugins(Opts1, Rest).


%% @private Parse the list of app start options
parse_opts([], _Plugins, _AllOpts, Opts) ->
Opts;
parse_opts([], RestOpts, Opts) ->
{Opts, RestOpts};

parse_opts([{plugins, _}|Rest], Plugins, AllOpts, Opts) ->
parse_opts(Rest, Plugins, AllOpts, Opts);
parse_opts([{plugins, _}|Rest], RestOpts, Opts) ->
parse_opts(Rest, RestOpts, Opts);

parse_opts([Atom|Rest], Plugins, AllOpts, Opts) when is_atom(Atom) ->
parse_opts([{Atom, true}|Rest], Plugins, AllOpts, Opts);
parse_opts([Atom|Rest], RestOpts, Opts) when is_atom(Atom) ->
parse_opts([{Atom, true}|Rest], RestOpts, Opts);

parse_opts([Term|Rest], Plugins, AllOpts, Opts) ->
parse_opts([Term|Rest], RestOpts, Opts) ->
Op = case Term of

% Internal options
Expand Down Expand Up @@ -243,39 +308,39 @@ parse_opts([Term|Rest], Plugins, AllOpts, Opts) ->
{store_trace, Trace} when is_boolean(Trace) ->
{update, Trace};

Other ->
case parse_external_opt(Term, Plugins, AllOpts) of
error ->
lager:notice("Ignoring unknown option ~p starting SipApp",
[Other]),
update;
ExtUpdate ->
ExtUpdate
end
_Other ->
unknown
end,
{Key, Val} = case Op of
update -> {element(1, Term), element(2, Term)};
{update, Val1} -> {element(1, Term), Val1};
{update, Key1, Val1} -> {Key1, Val1};
error -> throw({invalid, element(1, Term)})
{Opts1, RestOpts1} = case Op of
unknown ->
{Opts, [Term|RestOpts]};
_ ->
{Key, Val} = case Op of
update -> {element(1, Term), element(2, Term)};
{update, Val1} -> {element(1, Term), Val1};
{update, Key1, Val1} -> {Key1, Val1};
error -> throw({invalid, element(1, Term)})
end,
{lists:keystore(Key, 1, Opts, {Key, Val}), RestOpts}
end,
Opts1 = lists:keystore(Key, 1, Opts, {Key, Val}),
parse_opts(Rest, Plugins, AllOpts, Opts1).
parse_opts(Rest, RestOpts1, Opts1).


%% @doc
-spec parse_external_opt([{term(), term()}], [atom()], nksip:optslist()) ->
update | {update, term()} | {update, atom(), term()} | error.

parse_external_opt(_Term, [], _Opts) ->
error;

parse_external_opt(Term, [Plugin|Rest], Opts) ->
case catch Plugin:parse_config(Term, Opts) of
update -> update;
{update, Value} -> {update, Value};
{update, Key, Value} -> {update, Key, Value};
_ -> parse_external_opt(Term, Rest, Opts)
%% @private
parse_plugins_opts([], ConfigOpts, []) ->
ConfigOpts;

parse_plugins_opts([], ConfigOpts, PluginOpts) ->
lager:notice("Ignoring unrecognized options starting ~p SipApp: \n~p",
[nksip_lib:get_value(name, ConfigOpts), PluginOpts]),
ConfigOpts;

parse_plugins_opts([Plugin|RestPlugins], ConfigOpts, PluginOpts) ->
case catch Plugin:parse_config(PluginOpts, ConfigOpts) of
{ok, RestPluginOpts, ConfigOpts1} ->
parse_plugins_opts(RestPlugins, ConfigOpts1, RestPluginOpts);
_ ->
parse_plugins_opts(RestPlugins, ConfigOpts, PluginOpts)
end.


Expand Down Expand Up @@ -322,60 +387,6 @@ parse_transports([Transport|Rest], Acc) ->
parse_transports(Rest, [{Scheme, Ip1, Port1, TOpts}|Acc]).


%% @private Parte the plugins list for the application
%% For each plugin, calls Plugin:version() to get the version, and
%% Plugin:deps() to get the dependency list ([Name::atom(), RE::binary()]).
%% it then builds a list of sorted list of plugin names, where every plugin
%% is inserted after all of its dependencies.
parse_plugins([Name|Rest], PlugList) when is_atom(Name) ->
case lists:keymember(Name, 1, PlugList) of
true ->
parse_plugins(Rest, PlugList);
false ->
case catch Name:version() of
Ver when is_list(Ver); is_binary(Ver) ->
case catch Name:deps() of
Deps when is_list(Deps) ->
case parse_plugins_insert(PlugList, Name, Ver, Deps, []) of
{ok, PlugList1} ->
parse_plugins(Rest, PlugList1);
{insert, BasePlugin} ->
parse_plugins([BasePlugin, Name|Rest], PlugList)
end;
_ ->
throw({invalid_plugin, Name})
end;
_ ->
throw({invalid_plugin, Name})
end
end;

parse_plugins([], PlugList) ->
[Name || {Name, _} <- PlugList].


%% @private
parse_plugins_insert([{CurName, CurVer}=Curr|Rest], Name, Ver, Deps, Acc) ->
case lists:keytake(CurName, 1, Deps) of
false ->
parse_plugins_insert(Rest, Name, Ver, Deps, Acc++[Curr]);
{value, {_, DepVer}, RestDeps} when is_list(DepVer); is_binary(DepVer) ->
case re:run(CurVer, DepVer) of
{match, _} ->
parse_plugins_insert(Rest, Name, Ver, RestDeps, Acc++[Curr]);
nomatch ->
throw({incompatible_plugin, {CurName, CurVer, DepVer}})
end;
_ ->
throw({invalid_plugin, Name})
end;

parse_plugins_insert([], Name, Ver, [], Acc) ->
{ok, Acc++[{Name, Ver}]};

parse_plugins_insert([], _Name, _Ver, [{DepName, _}|_], _Acc) ->
{insert, DepName}.


%% @private Generates a ready-to-compile config getter functions
cache_syntax(Opts) ->
Expand All @@ -395,13 +406,11 @@ cache_syntax(Opts) ->
nksip_lib:get_value(timer_t2, Opts),
nksip_lib:get_value(timer_t4, Opts),
1000*nksip_lib:get_value(timer_c, Opts)}},
{config_sync_call_time, 1000*nksip_lib:get_value(sync_call_time, Opts)},
% {config_sync_call_time, 1000*nksip_lib:get_value(sync_call_time, Opts)},
{config_from, nksip_lib:get_value(from, Opts)},
{config_no_100, lists:member({no_100, true}, Opts)},
{config_supported,
nksip_lib:get_value(supported, Opts, ?SUPPORTED)},
{config_allow,
nksip_lib:get_value(allow, Opts, ?ALLOW)},
{config_supported, nksip_lib:get_value(supported, Opts)},
{config_allow, nksip_lib:get_value(allow, Opts)},
{config_accept, nksip_lib:get_value(accept, Opts)},
{config_events, nksip_lib:get_value(events, Opts, [])},
{config_route, nksip_lib:get_value(route, Opts, [])},
Expand Down
Loading

0 comments on commit 7f1c0e6

Please sign in to comment.