nitro_n2o.erl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. -module(nitro_n2o).
  2. %% N2O Nitrogen Web Framework Protocol
  3. -include_lib("nitro/include/n2o.hrl").
  4. -export([
  5. info/3,
  6. render_actions/1,
  7. io/1,
  8. io/2,
  9. event/1
  10. ]).
  11. % Nitrogen pickle handler
  12. %% todo mv this from nitro
  13. % todo compare with n2o (n4u) and cx without token
  14. info({text, <<"N2O,", Auth/binary>>}, Req, State) ->
  15. info(#init{token = Auth}, Req, State);
  16. info(#init{token = Auth}, Req, State) ->
  17. {'Token', Token} = authenticate([], Auth),
  18. Sid = case nitro:depickle(Token) of
  19. {{S, _}, _} -> S;
  20. X -> X
  21. end,
  22. New = State#cx{session = Sid, token = Auth},
  23. erlang:put(context, New),
  24. {reply, {bert,
  25. case io(init, State) of
  26. {io, _, {stack, _}} = Io -> Io;
  27. {io, Code, _} -> {io, Code, {'Token', Token}}
  28. end},
  29. Req, New};
  30. info(#client{data = Message}, Req, State) ->
  31. erlang:put(actions, []),
  32. {reply, {bert, io(#client{data = Message}, State)}, Req, State};
  33. info(#pickle{} = Event, Req, State) ->
  34. erlang:put(actions, []),
  35. {reply, {bert, html_events(Event, State)}, Req, State};
  36. info(#flush{data = Actions}, Req, State) ->
  37. erlang:put(actions, Actions),
  38. {reply, {bert, io(<<>>)}, Req, State};
  39. info(#direct{data = Message}, Req, State) ->
  40. erlang:put(actions, []),
  41. {reply, {bert,
  42. case io(Message, State) of
  43. {io, _, {stack, _}} = Io -> Io;
  44. {io, Code, Res} -> {io, Code, {direct, Res}}
  45. end},
  46. Req, State};
  47. info(Message, Req, State) -> {unknown, Message, Req, State}.
  48. %% double render: actions could generate actions
  49. render_actions(Actions) ->
  50. erlang:put(actions, []),
  51. First = nitro:render(Actions),
  52. Second = nitro:render(erlang:get(actions)),
  53. erlang:put(actions, []),
  54. nitro:to_binary([First, Second]).
  55. %% n2o events
  56. html_events(#pickle{source = Source, pickled = Pickled, args = Linked}, State = #cx{token = Token}) ->
  57. Ev = nitro:depickle(Pickled),
  58. L = prolongate(),
  59. Res = case Ev of
  60. #ev{} when L =:= false ->
  61. render_ev(Ev, Source, Linked, State),
  62. <<>>;
  63. #ev{} ->
  64. render_ev(Ev, Source, Linked, State),
  65. authenticate([], Token);
  66. _CustomEnvelop ->
  67. %?LOG_ERROR("EV expected: ~p~n",[CustomEnvelop]),
  68. {error, "EV expected"}
  69. end,
  70. io(Res).
  71. %% todo move work with session to n2o (n4u)
  72. prolongate() -> %% todo mv this from nitro
  73. case application:get_env(n2o, session) of
  74. {ok, M} -> M:prolongate();
  75. undefined -> false
  76. end.
  77. authenticate(I, Auth) -> %% todo mv this from nitro
  78. (application:get_env(n2o, session, n2o_session)):authenticate(I, Auth).
  79. %% calling user code in exception-safe manner
  80. -ifdef(OTP_RELEASE).
  81. render_ev(#ev{module = M, name = F, msg = P, trigger = T}, _Source, Linked, State) ->
  82. try case F of
  83. api_event ->
  84. M:F(P, Linked, State);
  85. event ->
  86. [erlang:put(K, V) || {K, V} <- Linked],
  87. M:F(P);
  88. _ ->
  89. M:F(P, T, State)
  90. end
  91. catch E:R:S ->
  92. ?LOG_EXCEPTION(E, R, S),
  93. {stack, S}
  94. end.
  95. io(Event, #cx{module = Module}) ->
  96. try
  97. X = Module:event(Event),
  98. {io, render_actions(erlang:get(actions)), X}
  99. catch E:R:S ->
  100. ?LOG_EXCEPTION(E, R, S),
  101. {io, [], {stack, S}}
  102. end.
  103. io(Data) ->
  104. try {io, render_actions(erlang:get(actions)), Data}
  105. catch E:R:S ->
  106. ?LOG_EXCEPTION(E, R, S),
  107. {io, [], {stack, S}}
  108. end.
  109. -else.
  110. render_ev(#ev{module = M, name = F, msg = P, trigger = T}, _Source, Linked, State) ->
  111. try
  112. case F of
  113. api_event ->
  114. M:F(P, Linked, State);
  115. event ->
  116. [erlang:put(K, V) || {K, V} <- Linked],
  117. M:F(P);
  118. _ ->
  119. M:F(P, T, State)
  120. end
  121. catch E:R ->
  122. S = erlang:get_stacktrace(),
  123. ?LOG_EXCEPTION(E, R, S),
  124. {stack, S}
  125. end.
  126. io(Event, #cx{module = Module}) ->
  127. try
  128. X = Module:event(Event),
  129. {io, render_actions(erlang:get(actions)), X}
  130. catch E:R ->
  131. S = erlang:get_stacktrace(),
  132. ?LOG_EXCEPTION(E, R, S),
  133. {io, <<>>, {stack, S}}
  134. end.
  135. io(Data) ->
  136. try {io, render_actions(erlang:get(actions)), Data}
  137. catch E:R ->
  138. S = erlang:get_stacktrace(),
  139. ?LOG_EXCEPTION(E, R, S),
  140. {io, <<>>, {stack, S}}
  141. end.
  142. -endif.
  143. %% event Nitrogen Web Framework protocol
  144. event(_) -> [].