Current section

Files

Jump to
nova src nova.erl
Raw

src/nova.erl

%%% @author Niclas Axelsson <niclas@burbas.se>
%%% @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.