Packages
nova
0.15.1
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_plugin_handler.erl
-module(nova_plugin_handler).
-behaviour(cowboy_middleware).
-export([
execute/2
]).
-include_lib("kernel/include/logger.hrl").
execute(Req = #{plugins := Plugins}, Env = #{plugin_state := pre_request}) ->
%% This is a post plugin
PostPlugins = proplists:get_value(post_request, Plugins, []),
run_plugins(PostPlugins, post_request, Req, Env);
execute(Req = #{plugins := Plugins}, Env) ->
%% Determine which pre-plugin this is
PrePlugins = proplists:get_value(pre_request, Plugins, []),
run_plugins(PrePlugins, pre_request, Req, Env);
execute(Req, Env) ->
%% The router could not find any match for us
{ok, Req, Env}.
run_plugins([], Callback, Req, Env) ->
{ok, Req, Env#{plugin_state => Callback}};
run_plugins([{Module, Options}|Tl], Callback, Req, Env) when is_atom(Module) ->
run_plugins([{fun Module:Callback/1, Options}|Tl], Callback, Req, Env);
run_plugins([{Callback, Options}|Tl], CallbackType, Req, Env) when is_function(Callback) ->
%% Fetch state
State =
case nova_plugin_manager:get_state(Callback) of
{ok, State0} ->
State0;
{error, _Reason} ->
undefined
end,
try Callback(Req, Env, Options, State) of
Result ->
set_state(Callback, Result),
case Result of
{ok, Req0, _State0} ->
run_plugins(Tl, CallbackType, Req0, Env);
{ok, Reply, Req0, _State0} ->
Req1 = handle_reply(Reply, Req0),
run_plugins(Tl, CallbackType, Req1, Env);
{break, Req0, _State0} ->
{ok, Req0};
{break, Reply, Req0, _State0} ->
Req1 = handle_reply(Reply, Req0),
{ok, Req1};
{stop, Req0, _State0} ->
{stop, Req0};
{stop, Reply, Req0, _State0} ->
Req1 = handle_reply(Reply, Req0),
%% Since we are stopping we need to send the statuscode to the requester. This is a special case for stop.
StatusCode = maps:get(resp_status_code, Req1, 200),
cowboy_req:reply(StatusCode, Req1),
{stop, Req1}
end
catch
Class:Reason:Stacktrace ->
?LOG_ERROR(#{msg => <<"Plugin crashed">>, class => Class, reason => Reason, stacktrace => Stacktrace}),
Req0 = Req#{crash_info => #{class => Class,
reason => Reason,
stacktrace => Stacktrace}},
nova_router:render_status_page('_', 500, #{}, Req0, Env)
end.
handle_reply({reply, Body}, Req) ->
handle_reply({reply, 200, #{}, Body}, Req);
handle_reply({reply, Status, Body}, Req) ->
handle_reply({reply, Status, #{}, Body}, Req);
handle_reply({reply, Status, Headers, Body}, Req) ->
Req0 = cowboy_req:set_resp_headers(Headers, Req),
Req1 = cowboy_req:set_resp_body(Body, Req0),
Req1#{resp_status_code => Status};
handle_reply(_, Req) ->
Req.
set_state(Callback, Return) when is_function(Callback) ->
ReturnList = erlang:tuple_to_list(Return),
State = lists:last(ReturnList),
nova_plugin_manager:set_state(Callback, State).