1::: Handling Websocket connections
2
3A special handler is required for handling Websocket connections.
4Websocket handlers allow you to initialize the connection,
5handle incoming frames from the socket, handle incoming Erlang
6messages and then clean up on termination.
7
8Websocket handlers essentially act as a bridge between the client
9and the Erlang system. They will typically do little more than
10socket communication and decoding/encoding of frames.
11
12:: Initialization
13
14First, the `init/3` callback is called. This callback is common
15to all handlers. To establish a Websocket connection, this function
16must return an `upgrade` tuple.
17
18``` erlang
19init(_, Req, Opts) ->
20	{upgrade, protocol, cowboy_websocket}.
21```
22
23It is also possible to return an update Req object and options
24using the longer form of this tuple.
25
26``` erlang
27init(_Type, Req, Opts) ->
28	{upgrade, protocol, cowboy_websocket, Req, Opts}.
29```
30
31Upon receiving this tuple, Cowboy will switch to the code
32that handles Websocket connections. It does not immediately
33perform the handshake however. First, it calls the `websocket_init/3`
34callback.
35
36This function must be used to initialize the state, and can
37also be used to register the process, start a timer, etc.
38As long as the function returns an `ok` tuple, then Cowboy
39performs the Websocket handshake.
40
41``` erlang
42websocket_init(_Type, Req, _Opts) ->
43    {ok, Req, #state{}}.
44```
45
46A `shutdown` tuple can be returned to refuse to perform the
47handshake. When doing so, Cowboy will send a `400 Bad Request`
48response to the client and close the connection.
49
50``` erlang
51websocket_init(_Type, Req, _Opts) ->
52	{shutdown, Req}.
53```
54
55It is also possible to perform a `cowboy_req:reply/{2,3,4}`
56before returning a `shutdown` tuple, allowing you to override
57the response sent back to the client.
58
59Note that browser support for handling Websocket connection
60failures may vary.
61
62If the sec-websocket-protocol header was sent with the request
63for establishing a Websocket connection, then the Websocket
64handler *must* select one of these subprotocol and send it
65back to the client, otherwise the client might decide to close
66the connection, assuming no correct subprotocol was found.
67
68``` erlang
69websocket_init(_Type, Req, _Opts) ->
70	case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of
71		{ok, undefined, Req2} ->
72			{ok, Req, #state{}};
73		{ok, Subprotocols, Req2} ->
74			case lists:keymember(<<"mychat2">>, 1, Subprotocols) of
75				true ->
76					Req3 = cowboy_req:set_resp_header(<<"sec-websocket-protocol">>,
77						<<"mychat2">>, Req2),
78					{ok, Req3, #state{}};
79				false ->
80					{shutdown, Req2}
81			end
82	end.
83```
84
85It is not recommended to wait too long inside the `websocket_init/3`
86function. Any extra initialization may be done after returning by
87sending yourself a message before doing anything. Any message sent
88to `self()` from `websocket_init/3` is guaranteed to arrive before
89any frames from the client.
90
91It is also very easy to ensure that this message arrives before
92any message from other processes by sending it before registering
93or enabling timers.
94
95``` erlang
96websocket_init(_Type, Req, _Opts) ->
97	self() ! post_init,
98	%% Register process here...
99	{ok, Req, #state{}}.
100
101websocket_info(post_init, Req, State) ->
102	%% Perform post_init initialization here...
103	{ok, Req, State}.
104```
105
106:: Handling frames from the client
107
108Cowboy will call `websocket_handle/3` whenever a text, binary,
109ping or pong frame arrives from the client. Note that in the
110case of ping and pong frames, no action is expected as Cowboy
111automatically replies to ping frames.
112
113The handler can decide to send frames to the socket, shutdown
114or just continue without sending anything.
115
116The following snippet echoes back any text frame received and
117ignores all others.
118
119``` erlang
120websocket_handle(Frame = {text, _}, Req, State) ->
121	{reply, Frame, Req, State};
122websocket_handle(_Frame, Req, State) ->
123	{ok, Req, State}.
124```
125
126:: Handling Erlang messages
127
128Cowboy will call `websocket_info/3` whenever an Erlang message
129arrives.
130
131The handler can decide to send frames to the socket, shutdown
132or just continue without sending anything.
133
134The following snippet forwards any `log` message to the socket
135and ignores all others.
136
137``` erlang
138websocket_info({log, Text}, Req, State) ->
139	{reply, {text, Text}, Req, State};
140websocket_info(_Info, Req, State) ->
141	{ok, Req, State}.
142```
143
144:: Sending frames to the socket
145
146Cowboy allows sending either a single frame or a list of
147frames to the socket. Any frame can be sent: text, binary, ping,
148pong or close frames.
149
150The following example sends three frames using a single `reply`
151tuple.
152
153``` erlang
154websocket_info(hello_world, Req, State) ->
155	{reply, [
156		{text, "Hello"},
157		{text, <<"world!">>},
158		{binary, <<0:8000>>}
159	], Req, State};
160%% More websocket_info/3 clauses here...
161```
162
163Note that the payload for text and binary frames is of type
164`iodata()`, meaning it can be either a `binary()` or an
165`iolist()`.
166
167Sending a `close` frame will immediately initiate the closing
168of the Websocket connection. Be aware that any additional
169frames sent by the client or any Erlang messages waiting to
170be received will not be processed. Also note that when replying
171a list of frames that includes close, any frame found after the
172close frame will not be sent.
173
174:: Ping and timeout
175
176The biggest performance improvement you can do when dealing
177with a huge number of Websocket connections is to reduce the
178number of timers that are started on the server. A common use
179of timers when dealing with connections is for sending a ping
180every once in a while. This should be done exclusively on the
181client side. Indeed, a server handling one million Websocket
182connections will perform a lot better when it doesn't have to
183handle one million extra timers too!
184
185Cowboy will automatically respond to ping frames sent by the
186client. It will still forward the frame to the handler for
187informative purpose, but no further action is required.
188
189Cowboy can be configured to automatically close the Websocket
190connection when no data arrives on the socket. It is highly
191recommended to configure a timeout for it, as otherwise you
192may end up with zombie "half-connected" sockets that may
193leave the process alive forever.
194
195A good timeout value is 60 seconds.
196
197``` erlang
198websocket_init(_Type, Req, _Opts) ->
199	{ok, Req, #state{}, 60000}.
200```
201
202This value cannot be changed once it is set. It defaults to
203`infinity`.
204
205:: Hibernate
206
207Most tuples returned from handler callbacks can include an
208extra value `hibernate`. After doing any necessary operations
209following the return of the callback, Cowboy will hibernate
210the process.
211
212It is highly recommended to hibernate processes that do not
213handle much traffic. It is a good idea to hibernate all
214connections by default and investigate only when you start
215noticing increased CPU usage.
216
217:: Supporting older browsers
218
219Unfortunately Websocket is a relatively recent technology,
220which means that not all browsers support it. A library like
221^"Bullet^https://github.com/extend/bullet^ can be used to
222emulate Websocket connections on older browsers.
223