Packages
nova
0.8.3
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_handler.erl
-module(nova_handler).
-behaviour(cowboy_middleware).
%% Callbacks
-export([
execute/2,
terminate/3
]).
-include_lib("nova/include/nova.hrl").
-include("nova_router.hrl").
-callback init(Req, any()) -> {ok | module(), Req, any()}
| {module(), Req, any(), any()}
when Req::cowboy_req:req().
-callback terminate(any(), map(), any()) -> ok.
-optional_callbacks([terminate/3]).
-spec execute(Req, Env) -> {ok, Req, Env}
when Req::cowboy_req:req(), Env::cowboy_middleware:env().
execute(Req, Env = #{cowboy_handler := Handler, arguments := Arguments}) ->
try Handler:init(Req, Arguments) of
{ok, Req2, _State} ->
Result = terminate(normal, Req2, Handler),
{ok, Req2, Env#{result => Result}};
{Mod, Req2, State} ->
Mod:upgrade(Req2, Env, Handler, State);
{Mod, Req2, State, Opts} ->
Mod:upgrade(Req2, Env, Handler, State, Opts)
catch Class:Reason:Stacktrace ->
Payload = #{status_code => 500,
stacktrace => Stacktrace,
class => Class,
reason => Reason},
?ERROR("Controller crashed (~p, ~p)~nStacktrace: ~p", [Class, Reason, Stacktrace]),
render_response(Req#{crash_info => Payload}, Env, 500)
end;
execute(Req, Env = #{module := Module, function := Function}) ->
try Module:Function(Req) of
RetObj ->
case nova_handlers:get_handler(element(1, RetObj)) of
{ok, Callback} ->
?INFO("Called handler: ~p", [RetObj]),
{ok, Req0} = Callback(RetObj, {Module, Function}, Req),
render_response(Req0, Env);
{error, not_found} ->
?ERROR("Unknown return object1 ~p returned from module: ~p function: ~p",
[RetObj, Module, Function])
end
catch Class:Reason:Stacktrace ->
?ERROR("Controller crashed (~p, ~p)~nStacktrace: ~p", [Class, Reason, Stacktrace]),
terminate(Reason, Req, Module),
%% Build the payload object
Payload = #{status_code => 500,
stacktrace => Stacktrace,
class => Class,
reason => Reason},
render_response(Req#{crash_info => Payload}, Env, 500)
end.
-spec terminate(any(), Req | undefined, module()) -> ok when Req::cowboy_req:req().
terminate(Reason, Req, Module) ->
case erlang:function_exported(Module, terminate, 3) of
true ->
Module:terminate(Reason, Req);
false ->
ok
end.
%%%%%%%%%%%%%%%%%%%%%%%%
%% INTERNAL FUNCTIONS %%
%%%%%%%%%%%%%%%%%%%%%%%%
-spec render_response(Req :: cowboy_req:req(), Env :: map()) -> {ok, Req :: cowboy_req:req(), State :: map()}.
render_response(Req, Env) ->
StatusCode = maps:get(resp_status_code, Req, 200),
cowboy_req:reply(StatusCode, Req),
{ok, Req, Env}.
render_response(Req, Env, StatusCode) ->
case nova_router:lookup_url(StatusCode) of
{error, _} ->
%% Render the internal view of nova
{ok, Req0} = nova_basic_handler:handle_status({status, StatusCode}, {dummy, dummy}, Req),
render_response(Req0, Env);
{ok, _Bindings, A=#nova_handler_value{module = EMod, function = EFunc}} ->
%% Show this view - how?
?INFO("Calling crashview: ~p", [A]),
execute(Req, Env#{app => nova, module => EMod, function => EFunc})
end.