Current section

Files

Jump to
nitrogen_core src elements other element_delay_body.erl
Raw

src/elements/other/element_delay_body.erl

% vim: sw=4 ts=4 et ft=erlang
% Nitrogen Web Framework for Erlang
% Copyright (c) 2020 Jesse Gumm
% See MIT-LICENSE for licensing information.
-module (element_delay_body).
-include("wf.hrl").
-export([
reflect/0,
transform_element/1,
event/1
]).
-spec reflect() -> [atom()].
reflect() -> record_info(fields, delay_body).
-spec transform_element(#delay_body{}) -> body().
transform_element(#delay_body{delegate=Delegate, tag=Tag, delay=Delay, placeholder=Placeholder}) when is_integer(Delay) ->
ID = wf:temp_id(),
?PRINT(wf_context:type()),
case wf_context:type() of
comet ->
%% If this is being rendered in a comet session, just trigger it as a normal postback. The problem with queueing it in trhe state is that the comet state is separate from the normal page state. This needs to change
wf:defer(#event{type=timer, delay=Delay, delegate=?MODULE, postback={do_delay_action, ID, Delegate, Tag}});
_ ->
%% If this is a normal request, then we can tell the system to queue it for better performance.
queue_delayed_body(Delegate, ID, Tag, Delay)
end,
#span{id=ID, body=Placeholder}.
queue_delayed_body(Delegate, ID, Tag, Delay) ->
%?PRINT(status(Delay)),
add_to_queue(Delegate, ID, Tag, Delay),
maybe_wire_postback(Delay).
wire_key(Delay) ->
{element_delay_body_wired, Delay}.
tag_key(Delay) ->
{element_delay_tags, Delay}.
add_to_queue(Delegate, ID, Tag, Delay) ->
Key = tag_key(Delay),
Queue = wf:state_default(Key, queue:new()),
NewQ = queue:in({ID, Delegate, Tag}, Queue),
%?PRINT(NewQ),
wf:state(Key, NewQ).
%status(Delay) ->
% {wf:state(wire_key(Delay)), wf:state(tag_key(Delay))}.
maybe_wire_postback(Delay) ->
Key = wire_key(Delay),
case wf:state_default(Key, false) of
true ->
wf:info("we've already wired ~p, so skipping",[Delay]),
do_nothing;
_ ->
wf:state(Key, true),
wf:defer(#event{type=timer, delay=Delay, delegate=?MODULE, postback={do_delay_actions, Delay}})
end.
reset_wire_key(Delay) ->
Key = wire_key(Delay),
wf:state(Key, false).
reset_tag_key(Delay) ->
Key = tag_key(Delay),
wf:state(Key, queue:new()).
event({do_delay_action, ID, Delegate, Tag}) ->
Body = Delegate:delay_body_event(Tag),
wf:replace(ID, Body);
event({do_delay_actions, Delay}) ->
%wf:info("Doing Delay Actions: ~p"),
reset_wire_key(Delay), % we reset this in case we have to queue another action with the same timeout with a later postback
TagKey = tag_key(Delay),
NewQ = queue:new(),
TagQueue = wf:state_default(TagKey, NewQ),
Tags = queue:to_list(TagQueue),
lists:foreach(fun({ID, Delegate, Tag}) ->
Body = Delegate:delay_body_event(Tag),
wf:replace(ID, Body)
end, Tags),
reset_tag_key(Delay).
%?PRINT(status(Delay)).