Updated documentation.
[erlang-mod_sse.git] / src / mod_sse_worker.erl
1 %%%---------------------------------------------------------------------------
2 %%% @private
3 %%% @doc
4 %%%   Process that receives events and passes them to httpd connection
5 %%%   handler.
6 %%% @end
7 %%%---------------------------------------------------------------------------
8
9 -module(mod_sse_worker).
10
11 -behaviour(gen_server).
12
13 -export([start_link/6]).
14
15 %%% gen_server callbacks
16 -export([init/1, terminate/2]).
17 -export([handle_call/3, handle_cast/2, handle_info/2]).
18 -export([code_change/3]).
19
20 %%%---------------------------------------------------------------------------
21
22 -record(state, {
23   mod :: module(),
24   state :: term(),
25   httpd :: pid()
26 }).
27
28 %%%---------------------------------------------------------------------------
29
30 %% @doc Start the receiver process.
31
32 -spec start_link(module(), [term()], pid(),
33                  string(), string(), [{string(), string()}]) ->
34     {ok, pid()} | ignore | {error, term()}.
35
36 start_link(Handler, HArgs, HTTPD, RootURI, URI, Headers) ->
37   Args = [Handler, HArgs, HTTPD, RootURI, URI, Headers],
38   gen_server:start_link(?MODULE, Args, []).
39
40 %%%---------------------------------------------------------------------------
41 %%% gen_server callbacks
42 %%%---------------------------------------------------------------------------
43
44 %%----------------------------------------------------------
45 %% starting and termination {{{
46
47 %% @private
48 %% @doc Initialize {@link gen_server} state.
49
50 init([Handler, HArgs, HTTPD, RootURI, URI, Headers] = _Args) ->
51   % TODO: monitor HTTPD
52   case Handler:init(RootURI, URI, Headers, HArgs) of
53     {ok, HState} ->
54       State = #state{mod = Handler, state = HState, httpd = HTTPD},
55       {ok, State};
56     {ok, HState, infinity = _Timeout} ->
57       State = #state{mod = Handler, state = HState, httpd = HTTPD},
58       {ok, State};
59     {ok, HState, Timeout} when is_integer(Timeout) ->
60       State = #state{mod = Handler, state = HState, httpd = HTTPD},
61       {ok, State, Timeout};
62     {ok, HState, hibernate} ->
63       State = #state{mod = Handler, state = HState, httpd = HTTPD},
64       {ok, State, hibernate};
65     {stop, Reason} ->
66       {stop, Reason}
67   end.
68
69 %% @private
70 %% @doc Clean up {@link gen_server} state.
71
72 terminate(Reason, _State = #state{mod = Handler, state = HState}) ->
73   Handler:terminate(Reason, HState).
74
75 %% }}}
76 %%----------------------------------------------------------
77 %% communication {{{
78
79 %% @private
80 %% @doc Handle {@link gen_server:call/2}.
81
82 handle_call(Request, From, State = #state{mod = Handler, state = HState}) ->
83   case Handler:handle_call(Request, From, HState) of
84     {reply, Reply, Events, NewHState} ->
85       send_events_if_any(Events, State),
86       NewState = State#state{state = NewHState},
87       {reply, Reply, NewState};
88     {reply, Reply, Events, NewHState, infinity = _Timeout} ->
89       send_events_if_any(Events, State),
90       NewState = State#state{state = NewHState},
91       {reply, Reply, NewState, infinity};
92     {reply, Reply, Events, NewHState, Timeout} when is_integer(Timeout) ->
93       send_events_if_any(Events, State),
94       NewState = State#state{state = NewHState},
95       {reply, Reply, NewState, Timeout};
96     {reply, Reply, Events, NewHState, hibernate} ->
97       send_events_if_any(Events, State),
98       NewState = State#state{state = NewHState},
99       {reply, Reply, NewState, hibernate};
100     {noreply, Events, NewHState} ->
101       send_events_if_any(Events, State),
102       NewState = State#state{state = NewHState},
103       {noreply, NewState};
104     {noreply, Events, NewHState, infinity = _Timeout} ->
105       send_events_if_any(Events, State),
106       NewState = State#state{state = NewHState},
107       {noreply, NewState, infinity};
108     {noreply, Events, NewHState, Timeout} when is_integer(Timeout) ->
109       send_events_if_any(Events, State),
110       NewState = State#state{state = NewHState},
111       {noreply, NewState, Timeout};
112     {noreply, Events, NewHState, hibernate} ->
113       send_events_if_any(Events, State),
114       NewState = State#state{state = NewHState},
115       {noreply, NewState, hibernate};
116     {stop, Reason, Reply, Events, NewHState} ->
117       send_events_if_any(Events, State),
118       NewState = State#state{state = NewHState},
119       {stop, Reason, Reply, NewState};
120     {stop, Reason, Events, NewHState} ->
121       send_events_if_any(Events, State),
122       NewState = State#state{state = NewHState},
123       {stop, Reason, NewState}
124   end.
125
126 %% @private
127 %% @doc Handle {@link gen_server:cast/2}.
128
129 handle_cast(Request, State = #state{mod = Handler, state = HState}) ->
130   case Handler:handle_cast(Request, HState) of
131     {noreply, Events, NewHState} ->
132       send_events_if_any(Events, State),
133       NewState = State#state{state = NewHState},
134       {noreply, NewState};
135     {noreply, Events, NewHState, infinity = _Timeout} ->
136       send_events_if_any(Events, State),
137       NewState = State#state{state = NewHState},
138       {noreply, NewState, infinity};
139     {noreply, Events, NewHState, Timeout} when is_integer(Timeout) ->
140       send_events_if_any(Events, State),
141       NewState = State#state{state = NewHState},
142       {noreply, NewState, Timeout};
143     {noreply, Events, NewHState, hibernate} ->
144       send_events_if_any(Events, State),
145       NewState = State#state{state = NewHState},
146       {noreply, NewState, hibernate};
147     {stop, Reason, Events, NewHState} ->
148       send_events_if_any(Events, State),
149       NewState = State#state{state = NewHState},
150       {stop, Reason, NewState}
151   end.
152
153 %% @private
154 %% @doc Handle incoming messages.
155
156 handle_info({tcp_closed, HTTPD} = _Message, State = #state{httpd = HTTPD}) ->
157   {stop, normal, State};
158
159 handle_info(Message, State = #state{mod = Handler, state = HState}) ->
160   case Handler:handle_info(Message, HState) of
161     {noreply, Events, NewHState} ->
162       send_events_if_any(Events, State),
163       NewState = State#state{state = NewHState},
164       {noreply, NewState};
165     {noreply, Events, NewHState, infinity = _Timeout} ->
166       send_events_if_any(Events, State),
167       NewState = State#state{state = NewHState},
168       {noreply, NewState, infinity};
169     {noreply, Events, NewHState, Timeout} when is_integer(Timeout) ->
170       send_events_if_any(Events, State),
171       NewState = State#state{state = NewHState},
172       {noreply, NewState, Timeout};
173     {noreply, Events, NewHState, hibernate} ->
174       send_events_if_any(Events, State),
175       NewState = State#state{state = NewHState},
176       {noreply, NewState, hibernate};
177     {stop, Reason, Events, NewHState} ->
178       send_events_if_any(Events, State),
179       NewState = State#state{state = NewHState},
180       {stop, Reason, NewState}
181   end.
182
183 %% }}}
184 %%----------------------------------------------------------
185 %% code change {{{
186
187 %% @private
188 %% @doc Handle code change.
189
190 code_change(OldVsn, State = #state{mod = Handler, state = HState}, Extra) ->
191   case Handler:code_change(OldVsn, HState, Extra) of
192     {ok, NewHState} ->
193       NewState = State#state{state = NewHState},
194       {ok, NewState};
195     {error, Reason} ->
196       {error, Reason}
197   end.
198
199 %% }}}
200 %%----------------------------------------------------------
201
202 -spec send_events_if_any([iolist()] | nothing, #state{}) ->
203   ok.
204
205 send_events_if_any(nothing = _Events, _State) ->
206   ok;
207
208 send_events_if_any(Events, _State = #state{httpd = HTTPD}) ->
209   [HTTPD ! {event, E} || E <- Events],
210   ok.
211
212 %%%---------------------------------------------------------------------------
213 %%% vim:ft=erlang:foldmethod=marker