[[websocket]]
== Websocket
This chapter describes how to use the Gun client for
communicating with a Websocket server.
// @todo recovering from connection failure, reconnecting to Websocket etc.
=== HTTP upgrade
Websocket is a protocol built on top of HTTP. To use Websocket,
you must first request for the connection to be upgraded. Only
HTTP/1.1 connections can be upgraded to Websocket, so you might
need to restrict the protocol to HTTP/1.1 if you are planning
to use Websocket over TLS.
You must use the `gun:ws_upgrade/2,3,4` function to upgrade
to Websocket. This function can be called anytime after connection,
so you can send HTTP requests before upgrading to Websocket.
.Upgrade to Websocket
[source,erlang]
----
gun:ws_upgrade(ConnPid, "/websocket").
----
Gun will set all the necessary headers for performing the
Websocket upgrade, but you can specify additional headers
if needed. For example you can request a custom sub-protocol.
.Upgrade to Websocket and request a protocol
[source,erlang]
----
gun:ws_upgrade(ConnPid, "/websocket", [
{<<"sec-websocket-protocol">>, "mychat"}
]).
----
You can pass the Websocket options as part of the `gun:open/2,3`
call when opening the connection, or using the `gun:ws_upgrade/4`.
The fourth argument is those same options.
When the upgrade succeeds, a `gun_upgrade` message is sent.
If the server does not understand Websocket or refused the
upgrade, a `gun_response` message is sent. If Gun couldn't
perform the upgrade due to an error (for example attempting
to upgrade to Websocket on an HTTP/1.0 connection) then a
`gun_error` message is sent.
When the server does not understand Websocket, it may send
a meaningful response which should be processed. In the
following example we however ignore it:
[source,erlang]
----
receive
{gun_upgrade, ConnPid, StreamRef, [<<"websocket">>], Headers} ->
upgrade_success(ConnPid, StreamRef);
{gun_response, ConnPid, _, _, Status, Headers} ->
exit({ws_upgrade_failed, Status, Headers});
{gun_error, ConnPid, StreamRef, Reason} ->
exit({ws_upgrade_failed, Reason})
%% More clauses here as needed.
after 1000 ->
exit(timeout)
end.
----
=== Sending data
Once the Websocket upgrade has completed successfully, you no
longer have access to functions for performing requests. You
can only send and receive Websocket messages.
Use `gun:ws_send/2` to send messages to the server.
.Send a text frame
[source,erlang]
----
gun:ws_send(ConnPid, {text, "Hello!"}).
----
// @todo Implement sending of N frames
//
//.Send a text frame, a binary frame and then close the connection
//[source,erlang]
//----
//gun:ws_send(ConnPid, [
// {text, "Hello!"},
// {binary, BinaryValue},
// close
//]).
//----
Note that if you send a close frame, Gun will close the connection
cleanly but will attempt to reconnect afterwards.
=== Receiving data
Gun sends an Erlang message to the owner process for every
Websocket message it receives.
[source,erlang]
----
receive
{gun_ws, ConnPid, StreamRef, Frame} ->
handle_frame(ConnPid, StreamRef, Frame)
end.
----
// @todo auto ping has not been implemented yet
//
//Gun will automatically send ping messages to the server to keep
//the connection alive, however if the connection dies and Gun has
//to reconnect it will not upgrade to Websocket automatically, you
//need to perform the operation when you receive the `gun_error`
//message.