|
@@ -0,0 +1,139 @@
|
|
|
|
+-module(n4u_nitrogen).
|
|
|
|
+-include_lib("n4u/include/n4u.hrl").
|
|
|
|
+
|
|
|
|
+-export([info/3]).
|
|
|
|
+-export([render_actions/1, html_events/2, render_ev/4, receive_actions/1]).
|
|
|
|
+% todo compare here and in nitro - render_actions, html_events, render_ev, receive_actions
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+% nitrogen pickle handler
|
|
|
|
+
|
|
|
|
+info({init, Rest}, Req, State) ->
|
|
|
|
+ Module = State#cx.module,
|
|
|
|
+ InitActionsReply = case Rest of
|
|
|
|
+ <<>> ->
|
|
|
|
+ try Elements = Module:main(),
|
|
|
|
+ nitro:render(Elements),
|
|
|
|
+ {ok, []}
|
|
|
|
+ catch E1:R1:Stk1 ->
|
|
|
|
+ wf:error(?MODULE, "main: E:R:Stk: ~p ~p~n ~p~n", [E1, R1, Stk1]),
|
|
|
|
+ {error, [E1, R1, Stk1]}
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ Binary ->
|
|
|
|
+ Pid = wf:depickle(Binary),
|
|
|
|
+ Pid ! {'N4U', erlang:self()},
|
|
|
|
+ {ok, receive_actions(Req)}
|
|
|
|
+ end,
|
|
|
|
+
|
|
|
|
+ case InitActionsReply of
|
|
|
|
+ {ok, InitActions} ->
|
|
|
|
+ UserCx = try Module:event(init),
|
|
|
|
+ case application:get_env(n4u, auto_session, "") of
|
|
|
|
+ disabled -> skip;
|
|
|
|
+ _ -> n2o_session:ensure_sid([], ?CTX, [])
|
|
|
|
+ end
|
|
|
|
+ catch E2:R2:Stk2 ->
|
|
|
|
+ wf:error(?MODULE, "init: E:R:Stk: ~p ~p~n ~p~n", [E2, R2, Stk2]),
|
|
|
|
+ {stack, [E2, R2, Stk2]}
|
|
|
|
+ end,
|
|
|
|
+ Actions = render_actions(erlang:get(actions)),
|
|
|
|
+ {reply, wf:format({io, erlang:iolist_to_binary([InitActions, Actions]), <<>>}),
|
|
|
|
+ Req, n4u_cx:context(State, ?MODULE, {init, UserCx})};
|
|
|
|
+
|
|
|
|
+ {error, E} ->
|
|
|
|
+ {reply, wf:format({io, <<>>, E}), Req,
|
|
|
|
+ n4u_cx:context(State, ?MODULE, {error, E})}
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+info({pickle, _, _, _} = Event, Req, State) ->
|
|
|
|
+ erlang:put(actions, []),
|
|
|
|
+ Result = try html_events(Event, State)
|
|
|
|
+ catch E:R:Stk ->
|
|
|
|
+ wf:error(?MODULE, "info pickle E:R:Stk: ~p ~p~n ~p~n", [E, R, Stk]),
|
|
|
|
+ {io, render_actions(erlang:get(actions)), [E, R, Stk]}
|
|
|
|
+ end,
|
|
|
|
+ {reply, wf:format(Result), Req,
|
|
|
|
+ n4u_cx:context(State, ?MODULE, {pickle, Result})};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+info({flush, Actions}, Req, State) ->
|
|
|
|
+ erlang:put(actions, []),
|
|
|
|
+ Render = erlang:iolist_to_binary(render_actions(Actions)),
|
|
|
|
+ wf:info(?MODULE, "Flush Message: ~tp~n", [Render]),
|
|
|
|
+ {reply, wf:format({io, Render, <<>>}), Req, State};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+info({direct, Message}, Req, State) ->
|
|
|
|
+ erlang:put(actions, []),
|
|
|
|
+ Module = State#cx.module,
|
|
|
|
+ Result = try Res = Module:event(Message),
|
|
|
|
+ {direct, Res}
|
|
|
|
+ catch E:R:Stk ->
|
|
|
|
+ wf:error(?MODULE, "info direct E:R:Stk: ~p ~p~n ~p~n", [E, R, Stk]),
|
|
|
|
+ {stack, [E, R, Stk]}
|
|
|
|
+ end,
|
|
|
|
+ {reply, wf:format({io, render_actions(erlang:get(actions)), <<>>}),
|
|
|
|
+ Req, n4u_cx:context(State, ?MODULE, Result)};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+info(Message, Req, State) -> {unknown, Message, Req, State}.
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+% double render: actions could generate actions
|
|
|
|
+
|
|
|
|
+render_actions(Actions) ->
|
|
|
|
+ erlang:put(actions, []),
|
|
|
|
+ First = nitro:render(Actions),
|
|
|
|
+ Second = nitro:render(erlang:get(actions)),
|
|
|
|
+ erlang:put(actions, []),
|
|
|
|
+ [First, Second].
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+% N4U events
|
|
|
|
+
|
|
|
|
+html_events({pickle, Source, Pickled, Linked} = Pickle, State) ->
|
|
|
|
+ wf:info(?MODULE, "Pickle: ~tp~n", [Pickle]),
|
|
|
|
+ Ev = wf:depickle(Pickled),
|
|
|
|
+ _Result = case Ev of
|
|
|
|
+ #ev{} ->
|
|
|
|
+ render_ev(Ev, Source, Linked, State);
|
|
|
|
+ Custom_Envelop ->
|
|
|
|
+ wf:error("Only #ev{} events for now: ~p~n", [Custom_Envelop])
|
|
|
|
+ end,
|
|
|
|
+ {io, render_actions(erlang:get(actions)), <<>>}.
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+render_ev(#ev{module = M, name = F, msg = P, trigger = T}, _Source, Linked, State) ->
|
|
|
|
+ case F of
|
|
|
|
+ api_event ->
|
|
|
|
+ M:F(P, Linked, State);
|
|
|
|
+
|
|
|
|
+ event ->
|
|
|
|
+ lists:map(fun({K, V}) ->
|
|
|
|
+ erlang:put(K, nitro:to_binary(V))
|
|
|
|
+ end, Linked),
|
|
|
|
+ M:F(P);
|
|
|
|
+
|
|
|
|
+ _UserCustomEvent ->
|
|
|
|
+ M:F(P, T, State)
|
|
|
|
+ end.
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+receive_actions(Req) ->
|
|
|
|
+ receive
|
|
|
|
+ {actions, A} ->
|
|
|
|
+ n4u_nitrogen:render_actions(A);
|
|
|
|
+ _ ->
|
|
|
|
+ receive_actions(Req)
|
|
|
|
+ after 200 ->
|
|
|
|
+ #{qs := QS} = Req,
|
|
|
|
+ R = case QS of
|
|
|
|
+ <<"">> -> "";
|
|
|
|
+ _ -> "?" ++ nitro:to_list(QS)
|
|
|
|
+ end,
|
|
|
|
+ wf:redirect(R),
|
|
|
|
+ []
|
|
|
|
+ end.
|
|
|
|
+
|