Packages
nova
0.9.23
0.15.1
0.14.3
0.14.1
0.13.7
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.11
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.4.4
0.4.3
0.4.2
0.4.1
0.2.2
0.1.0
0.0.1
0.0.0
Nova is a web application framework
Current section
Files
Jump to
Current section
Files
src/nova_sup.erl
%%% @author Niclas Axelsson <niclas@burbas.se>
%%% @doc
%%% Nova supervisor
%%% @end
-module(nova_sup).
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
-include_lib("kernel/include/logger.hrl").
-include("nova.hrl").
-define(SERVER, ?MODULE).
%%%===================================================================
%%% API functions
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Starts the supervisor
%%
%% @end
%%--------------------------------------------------------------------
-spec start_link() -> {ok, Pid :: pid()} | ignore | {error, Error :: any()}.
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart intensity, and child
%% specifications.
%%
%% @end
%%--------------------------------------------------------------------
init([]) ->
%% This is a bit ugly, but we need to do this anyhow(?)
SupFlags = #{strategy => one_for_one,
intensity => 1,
period => 5},
Environment = nova:get_environment(),
nova_pubsub:start(),
?LOG_NOTICE(#{msg => <<"Starting nova">>, environment => Environment}),
Configuration = application:get_env(nova, cowboy_configuration, #{}),
SessionManager = application:get_env(nova, session_manager, nova_session_ets),
Children = [
child(nova_handlers, nova_handlers),
child(SessionManager, SessionManager),
child(nova_watcher, nova_watcher)
],
setup_cowboy(Configuration),
{ok, {SupFlags, Children}}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
child(Id, Type, Mod, Args) ->
#{id => Id,
start => {Mod, start_link, Args},
restart => permanent,
shutdown => 5000,
type => Type,
modules => [Mod]}.
child(Id, Type, Mod) ->
child(Id, Type, Mod, []).
child(Id, Mod) ->
child(Id, worker, Mod).
setup_cowboy(Configuration) ->
case start_cowboy(Configuration) of
{ok, App, Host, Port} ->
Host0 = inet:ntoa(Host),
CowboyVersion = get_version(cowboy),
NovaVersion = get_version(nova),
UseStacktrace = application:get_env(nova, use_stacktrace, false),
persistent_term:put(nova_use_stacktrace, UseStacktrace),
?LOG_NOTICE(#{msg => <<"Nova is running">>,
url => unicode:characters_to_list(io_lib:format("http://~s:~B", [Host0, Port])),
cowboy_version => CowboyVersion, nova_version => NovaVersion, app => App});
{error, Error} ->
?LOG_ERROR(#{msg => <<"Cowboy could not start">>, reason => Error})
end.
-spec start_cowboy(Configuration :: map()) ->
{ok, BootstrapApp :: atom(), Host :: string() | {integer(), integer(), integer(), integer()},
Port :: integer()} | {error, Reason :: any()}.
start_cowboy(Configuration) ->
Middlewares = [
nova_router, %% Lookup routes
nova_plugin_handler, %% Handle pre-request plugins
nova_security_handler, %% Handle security
nova_handler, %% Controller
nova_plugin_handler %% Handle post-request plugins
],
StreamHandlers = maps:get(stream_handlers, Configuration, [nova_stream_h, cowboy_compress_h, cowboy_stream_h]),
Options = maps:get(options, Configuration, #{compress => true}),
%% Build the options map
CowboyOptions1 = Options#{middlewares => Middlewares,
stream_handlers => StreamHandlers},
BootstrapApp = application:get_env(nova, bootstrap_application, undefined),
%% Compile the routes
Dispatch =
case BootstrapApp of
undefined ->
?LOG_ERROR(#{msg => <<"You need to define bootstrap_application option in configuration">>}),
throw({error, no_nova_app_defined});
App ->
ExtraApps = application:get_env(App, nova_apps, []),
nova_router:compile([nova|[App|ExtraApps]])
end,
CowboyOptions2 =
case application:get_env(nova, use_persistent_term, true) of
true ->
CowboyOptions1;
_ ->
CowboyOptions1#{env => #{dispatch => Dispatch}}
end,
Host = maps:get(ip, Configuration, { 0, 0, 0, 0}),
case maps:get(use_ssl, Configuration, false) of
false ->
Port = maps:get(port, Configuration, ?NOVA_STD_PORT),
case cowboy:start_clear(
?NOVA_LISTENER,
[{port, Port},
{ip, Host}],
CowboyOptions2) of
{ok, _Pid} ->
{ok, BootstrapApp, Host, Port};
Error ->
Error
end;
_ ->
CACert = maps:get(ca_cert, Configuration),
Cert = maps:get(cert, Configuration),
Port = maps:get(ssl_port, Configuration, ?NOVA_STD_SSL_PORT),
?LOG_NOTICE(#{msg => <<"Nova starting SSL">>, port => Port}),
case cowboy:start_tls(
?NOVA_LISTENER, [
{port, Port},
{ip, Host},
{certfile, Cert},
{cacertfile, CACert}
],
CowboyOptions2) of
{ok, _Pid} ->
{ok, BootstrapApp, Host, Port};
Error ->
Error
end
end.
get_version(Application) ->
case lists:keyfind(Application, 1, application:loaded_applications()) of
{_, _, Version} ->
Version;
false ->
not_found
end.