%%% @author Niclas Axelsson %%% @doc %%% Interface module for nova %%% @end -module(nova). -include_lib("kernel/include/logger.hrl"). -export([ get_main_app/0, get_apps/0, get_environment/0, get_env/2, set_env/2, use_stacktrace/1, format_stacktrace/1, detect_language/0 ]). -type state() :: any(). -export_type([state/0]). %%-------------------------------------------------------------------- %% @doc %% Returns the name of the main bw-application (The one that started %% everything) %% %% @end %%-------------------------------------------------------------------- -spec get_main_app() -> {ok, Application :: atom()} | undefined. get_main_app() -> application:get_env(nova, bootstrap_application). %%-------------------------------------------------------------------- %% @doc %% Returns a proplist with all nova applications and their prefix. This %% function is useful when calulating dynamic routes. %% %% @end %%-------------------------------------------------------------------- -spec get_apps() -> [{App :: atom(), Prefix :: list()}]. get_apps() -> nova_router:compiled_apps(). %%-------------------------------------------------------------------- %% @doc %% Returns which environment nova is started in. This fetches the %% environment-variable in sys.config for Nova and returns the value found. %% Defaults to: dev %% %% @end %%-------------------------------------------------------------------- -spec get_environment() -> any(). get_environment() -> application:get_env(nova, environment, dev). %%-------------------------------------------------------------------- %% @doc %% Works as the regular application:get_env/3 but instead of giving %% a specific application we target the application that started %% nova. %% %% @end %%-------------------------------------------------------------------- -spec get_env(Parameter :: atom(), Default :: any()) -> term() | undefined. get_env(Parameter, Default) -> case get_main_app() of {ok, App} -> application:get_env(App, Parameter, Default); _ -> Default end. %%-------------------------------------------------------------------- %% @doc %% Sets an environment variable for the main application. %% %% @end %%-------------------------------------------------------------------- -spec set_env(Key :: atom(), Value :: any()) -> ok | {error, main_app_not_found}. set_env(Key, Value) -> case get_main_app() of {ok, App} -> application:set_env(App, Key, Value); _ -> {error, main_app_not_found} end. %%-------------------------------------------------------------------- %% @doc %% Enables or disables stacktraces. This is a global setting and %% affects all requests. If stacktraces are enabled, nova will %% try to print a stacktrace when an exception is thrown. %% @end %%-------------------------------------------------------------------- -spec use_stacktrace(Enable :: boolean()) -> ok. use_stacktrace(true) -> persistent_term:put(nova_use_stacktrace, true); use_stacktrace(_) -> persistent_term:erase(nova_use_stacktrace). %%-------------------------------------------------------------------- %% @doc %% Formats a stacktrace into a list of maps. Each map contains %% the module, function, arity, file, and line number of the %% function call. %% @end -spec format_stacktrace(Stacktrace :: [{M :: atom(), F :: atom(), A :: integer(), Info :: list()}]) -> [map()]. format_stacktrace(Stacktrace) -> SingleFun = fun({M, F, A, Info}) -> #{module => M, function => F, arity => A, file => proplists:get_value(file, Info, <<"unknown">>), line => proplists:get_value(line, Info, -1)} end, [SingleFun(S) || S <- Stacktrace]. %%-------------------------------------------------------------------- %% @doc %% Detects the language Nova is running in. It checks for the presence %% of the Elixir and LFE modules, and returns the language. %% @end %%-------------------------------------------------------------------- -spec detect_language() -> elixir | lfe | erlang. detect_language() -> case {code:which('Elixir.System'), code:which(lfe_eval)} of {non_existing, non_existing} -> erlang; {_, non_existing} -> elixir; {non_existing, _} -> lfe; {_, _} -> elixir % prefer Elixir if both are present end.