nitro_n2o.erl 4.2 KB

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