% This LaTeX document was generated using the LaTeX backend of PlDoc,
% The SWI-Prolog documentation system



\section{library(http/websocket): WebSocket support}

\label{sec:websocket}

\begin{tags}
    \tag{See also}
RFC 6455, \url{http://tools.ietf.org/html/rfc6455}
    \tag{To be done}
Deal with protocol extensions.
\end{tags}

WebSocket is a lightweight message oriented protocol on top of TCP/IP
streams. It is typically used as an \textit{upgrade} of an HTTP connection to
provide bi-directional communication, but can also be used in isolation
over arbitrary (Prolog) streams.

The SWI-Prolog interface is based on \textit{streams} and provides \predref{ws_open}{3} to
create a \textit{websocket stream} from any Prolog stream. Typically, both an
input and output stream are wrapped and then combined into a single
object using \predref{stream_pair}{3}.

The high-level interface provides \predref{http_upgrade_to_websocket}{3} to realise
a websocket inside the HTTP server infrastructure and
\predref{http_open_websocket}{3} as a layer over \predref{http_open}{3} to realise a client
connection. After establishing a connection, \predref{ws_send}{2} and \predref{ws_receive}{2}
can be used to send and receive messages. The predicate \predref{ws_close}{2} is
provided to perform the closing handshake and dispose of the stream
objects.\vspace{0.7cm}

\begin{description}
    \predicate[det]{http_open_websocket}{3}{+URL, -WebSocket, +Options}
Establish a client websocket connection. This predicate calls
\predref{http_open}{3} with additional headers to negotiate a websocket
connection. In addition to the options processed by http_open,
the following options are recognised:

\begin{description}
    \termitem{subprotocols}{+List}
\arg{List} of subprotocols that are acceptable. The selected
protocol is available as ws_property(\arg{WebSocket},
\verb$subprotocol(Protocol)$.
\end{description}

The following example exchanges a message with the
html5rocks.websocket.org echo service:

\begin{code}
?- URL = 'ws://html5rocks.websocket.org/echo',
   http_open_websocket(URL, WS, []),
   ws_send(WS, text('Hello World!')),
   ws_receive(WS, Reply),
   ws_close(WS, 1000, "Goodbye").
URL = 'ws://html5rocks.websocket.org/echo',
WS = <stream>(0xe4a440,0xe4a610),
Reply = websocket{data:"Hello World!", opcode:text}.
\end{code}

\begin{arguments}
\arg{WebSocket} & is a stream pair (see \predref{stream_pair}{3}) \\
\end{arguments}

    \predicate{http_upgrade_to_websocket}{3}{:Goal, +Options, +Request}
Create a websocket connection running \verb$call(Goal, WebSocket)$,
where WebSocket is a socket-pair. \arg{Options}:

\begin{description}
    \termitem{guarded}{+Boolean}
If \const{true} (default), guard the execution of \arg{Goal} and close
the websocket on both normal and abnormal termination of \arg{Goal}.
If \const{false}, \arg{Goal} itself is responsible for the created
websocket. This can be used to create a single thread that
manages multiple websockets using I/O multiplexing.
    \termitem{subprotocols}{+List}
\arg{List} of acceptable subprotocols.
    \termitem{timeout}{+TimeOut}
Timeout to apply to the input stream. Default is \const{infinite}.
\end{description}

Note that the \arg{Request} argument is the last for cooperation with
\predref{http_handler}{3}. A simple \textit{echo} server that can be accessed at
=/ws/= can be implemented as:

\begin{code}
:- use_module(library(http/websocket)).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).

:- http_handler(root(ws),
                http_upgrade_to_websocket(echo, []),
                [spawn([])]).

echo(WebSocket) :-
    ws_receive(WebSocket, Message),
    (   Message.opcode == close
    ->  true
    ;   ws_send(WebSocket, Message),
        echo(WebSocket)
    ).
\end{code}

\begin{tags}
    \tag{throws}
\verb$switching_protocols(Goal, Options)$. The recovery from
this exception causes the HTTP infrastructure to call
\verb$call(Goal, WebSocket)$.
    \tag{See also}
\predref{http_switch_protocol}{2}.
\end{tags}

    \predicate[det]{ws_send}{2}{+WebSocket, +Message}
Send a message over a websocket. The following terms are allowed
for \arg{Message}:

\begin{description}
    \termitem{text}{+Text}
Send a text message. \arg{Text} is serialized using \predref{write}{1}.
    \termitem{binary}{+Content}
As \verb$text(+Text)$, but all character codes produced by \arg{Content}
must be in the range [0..255]. Typically, \arg{Content} will be
an atom or string holding binary data.
    \termitem{prolog}{+Term}
Send a Prolog term as a text message. Text is serialized
using \predref{write_canonical}{1}.
    \termitem{json}{+JSON}
Send the Prolog representation of a \arg{JSON} term using
\predref{json_write_dict}{2}.
    \termitem{string}{+Text}
Same as \verb$text(+Text)$, provided for consistency.
    \termitem{close}{+Code, +Text}
Send a close message. \arg{Code} is 1000 for normal close. See
websocket documentation for other values.
    \termitem{\arg{Dict}}{}
A dict that minimally contains an \const{opcode} key. Other keys
used are:

\begin{description}
    \infixtermitem{\Smodule}{\term{format}{}}{\arg{Format}}
Serialization format used for \arg{Message}.data. \arg{Format} is
one of \const{string}, \const{prolog} or \const{json}. See \predref{ws_receive}{3}.
    \infixtermitem{\Smodule}{\term{data}{}}{\arg{Term}}
If this key is present, it is serialized according
to \arg{Message}.format. Otherwise it is serialized using
\predref{write}{1}, which implies that string and atoms are just
sent verbatim.
\end{description}
\end{description}

Note that \predref{ws_start_message}{3} does not unlock the stream. This is
done by \predref{ws_send}{1}. This implies that multiple threads can use
\predref{ws_send}{2} and the messages are properly serialized.

\begin{tags}
    \tag{To be done}
Provide serialization details using options.
\end{tags}

    \predicate[det]{ws_receive}{2}{+WebSocket, -Message:dict}
\nodescription
    \predicate[det]{ws_receive}{3}{+WebSocket, -Message:dict, +Options}
Receive the next message from \arg{WebSocket}. \arg{Message} is a dict
containing the following keys:

\begin{description}
    \infixtermitem{\Smodule}{\term{opcode}{}}{\arg{OpCode}}
\arg{OpCode} of the message. This is an atom for known opcodes
and an integer for unknown ones. If the peer closed the
stream, \arg{OpCode} is bound to \const{close} and data to the atom
\verb$end_of_file$.
    \infixtermitem{\Smodule}{\term{data}{}}{\arg{String}}
The data, represented as a string. This field is always
present. \arg{String} is the empty string if there is no data
in the message.
    \infixtermitem{\Smodule}{\term{rsv}{}}{\arg{RSV}}
Present if the \arg{WebSocket} \arg{RSV} header is not 0. \arg{RSV} is an
integer in the range [1..7].
\end{description}

If \const{ping} message is received and \arg{WebSocket} is a stream pair,
\predref{ws_receive}{1} replies with a \const{pong} and waits for the next
message.

The predicate \predref{ws_receive}{3} processes the following options:

\begin{description}
    \termitem{format}{+Format}
Defines how \textit{text} messages are parsed. \arg{Format} is one of

\begin{description}
    \termitem{string}{}
Data is returned as a Prolog string (default)
    \termitem{json}{}
Data is parsed using \predref{json_read_dict}{3}, which also receives
\arg{Options}.
    \termitem{prolog}{}
Data is parsed using \predref{read_term}{3}, which also receives
\arg{Options}.
\end{description}
\end{description}

\begin{tags}
    \tag{To be done}
Add a hook to allow for more data formats?
\end{tags}

    \predicate[det]{ws_close}{3}{+WebSocket:stream_pair, +Code, +Data}
Close a \arg{WebSocket} connection by sending a \const{close} message if
this was not already sent and wait for the close reply.

\begin{arguments}
\arg{Code} & is the numerical code indicating the close status.
This is 16-bit integer. The codes are defined in
section \textit{7.4.1. Defined Status Codes} of RFC6455.
Notably, 1000 indicates a normal closure. \\
\arg{Data} & is currently interpreted as text. \\
\end{arguments}

\begin{tags}
    \tag{Errors}
\verb$websocket_error(unexpected_message, Reply)$ if
the other side did not send a close message in reply.
\end{tags}

    \predicate[det]{ws_open}{3}{+Stream, -WSStream, +Options}
Turn a raw TCP/IP (or any other binary stream) into a websocket
stream. \arg{Stream} can be an input stream, output stream or a stream
pair. \arg{Options} includes

\begin{description}
    \termitem{mode}{+Mode}
One of \const{server} or \const{client}. If \const{client}, messages are sent
as \textit{masked}.
    \termitem{buffer_size}{+Count}
Send partial messages for each \arg{Count} bytes or when flushing
the output. The default is to buffer the entire message before
it is sent.
    \termitem{close_parent}{+Boolean}
If \const{true} (default), closing \arg{WSStream} also closes \arg{Stream}.
    \termitem{subprotocol}{+Protocol}
Set the subprotocol property of WsStream. This value can be
retrieved using \predref{ws_property}{2}. \arg{Protocol} is an atom. See
also the \const{subprotocols} option of \predref{http_open_websocket}{3} and
\predref{http_upgrade_to_websocket}{3}.
\end{description}

A typical sequence to turn a pair of streams into a WebSocket is
here:

\begin{code}
    ...,
    Options = [mode(server), subprotocol(chat)],
    ws_open(Input, WsInput, Options),
    ws_open(Output, WsOutput, Options),
    stream_pair(WebSocket, WsInput, WsOutput).
\end{code}

    \predicate[nondet]{ws_property}{2}{+WebSocket, ?Property}
True if \arg{Property} is a property \arg{WebSocket}. Defined properties
are:

\begin{description}
    \termitem{subprotocol}{Protocol}
\arg{Protocol} is the negotiated subprotocol. This is typically set
as a property of the websocket by \predref{ws_open}{3}.
\end{description}
\end{description}

