Changes

Jump to navigation Jump to search
2,611 bytes added ,  14:18, 27 February 2020
no edit summary
This page presents one of the [[Web Application]] services. It describes how to use the WebSockets API of BaseX. WebSocket is a communication protocol for providing '''full-duplex ''' communication: Data can be sent in both directions and simultaneously. Please note that the current WebSocket implementation relies on Jetty’s WebSocket servlet API. Other web servers may be supported in future versions.
=Introduction=
==WebSocket Protocol==Use WebSockets if you have to exchange data with a high frequency or if you have to send messages from the server to the client without techniques like Polling.In contrast to REST the WebSockets use a single URL for the whole communication.
The WebSocket protocol was standardized in Use WebSockets if you have to exchange data with a high frequency or if you have to send messages from the server to the client without techniques like [polling https://toolsen.ietfwikipedia.org/htmlwiki/rfc6455 RFC 6455Polling_(computer_science)] by the IETF. After an initial HTTP-requestIn contrast to REST, all communication takes place over WebSockets use a single TCP connection. Unlike URL for the HTTP protocol, a connection will be kept alive, and a server can send unsolicited data to the clientwhole communication.
For establishing a The WebSocket connection, a handshake request is sent protocol was standardized in [https://tools.ietf.org/html/rfc6455 RFC 6455] by the clientIETF. The web server returns After an initial HTTP request, all communication takes place over a handshake responsesingle TCP connection. If Unlike the handshake is successfulHTTP protocol, the persistent a connection will be open until the client or the server closes itkept alive, an error occurs or and a timeout happens. It is possible to transmit all kind of server can send unsolicited data, binary or text. '''The BaseX-WebServer handles the handshake completely.''' You just have to define some limits of the connection in the <code>web.xml</code> and specify functions for WebSocket events like ''onConnect'' and ''onMessage''client.
For establishing a WebSocket connection, a handshake request is sent by the client. The web server returns a handshake response. If the handshake is successful, the persistent connection will be open until the client or the server closes it, an error occurs or a timeout happens. It is possible to transmit all kind of data, binary or text. '''The BaseX WebServer handles the handshake completely.''' You just have to define some limits of the connection in the <code>web.xml</code> and specify functions for WebSocket events like ''onConnect'' and ''onMessage''. Notice that there is no specification of a message-protocol. The WebSocket protocol just specifies the message-architecture but not how the payload of the messages is formatted. To agree on a format between the server and the client one can use subprotocolssub-protocols. Some older browsers don’t support the WebSocket protocol. Therefore you can use fallback options like Ajax. JavaScript client libraries like SockJS can be used for building client applications. The library takes care of how to establish the real-time connection. If the WebSocket protocol isn’t supported, it uses polling. You have to provide server functions for the fallback solutions if you have to support fallbacks.
Some older browsers don't support the WebSocket protocol. Therefore you can use fallback options like Ajax. JavaScript client libraries like SockJs can be used for building client applications. The library takes care of how to establish the real-time connection. If the WebSocket protocol isn't supported it uses polling. You have to provide server functions for the fallback solutions if you have to support fallbacks.
==Preliminaries==
To speed up processing, the functions of the existing XQuery modules are automatically cached in main memory. For further information on cache handling, check out the [[RESTXQ#Introduction|RESTXQ introduction]].
=Usage=Configuration==
* The WebSocket servlet has to can be enabled and disabled in the <code>web.xml</code> (which is the default case)configuration file. You can specify the further configuration options, such as <code>maxIdleTime</code>, <code>maxTextMessageSize </code>, and maxBinaryMessageSize here too. Check the standard <code>web.xmlmaxBinaryMessageSize</code> for further informations. * The default limit for messges is 64 KB. If you get a message that exceeds the maxTextMessageSize/maxBinaryMessageSize default orthe specified limit, if not set, the default messageSize of Jetty of 65 536 bytes (64 kB) then an error will be raised and the connection will be closed. In this case, the <code>ws:error</code> annotation will be called. * Annotate your specific XQuery-Functions with WebSocketAnnotations. You have to specify at least one WebSocket function.
=Annotations=
To write functions that act as WebSocket functions you have to use [[XQuery 3.0#Annotations|annotations]]. The annotation is written after the keyword ''declare'' and before the keyword ''function''.
For the context of WebSockets there are some annotations listed below. Functions which are annotated with a WebSocket annotation will be called if the appropriate event occurs. For example the function annotated with <code>ws:connect('/')</code> will be executed if a client establishes a connection with the path <code>'/'</code>.
By using annotations its easy to provide an API for your WebSocket connection. You just have to specify what to do when a WebSocket Event occurs, annotate it with the corresponding annotation and the Servlet will do the rest for you.
==To tag functions as WebSocket functions you have to use [[XQuery 3.0#Annotations|annotations]]. The annotation is written after the keyword ''declare'' and before the keyword ''function''. For the context of WebSockets there are some annotations listed below. Functions which are annotated with a WebSocket annotation will be called if the appropriate event occurs. For example, the function annotated with <code>ws:connect('/')</code> will be executed if a client establishes a connection with the WebSocket root path(which is, by default, <code>ws/</code>)==. By using annotations, it’s easy to provide an API for your WebSocket connection. You just have to specify what to do when a WebSocket Event occurs, annotate it with the corresponding annotation and the Servlet will do the rest for you.
Called directly after a successful WebSocket handshake. The <code>==%ws:connect(path</code> specifies the path which a client is connected to. You can specify here how to handle your users, f.e. save a name as a WebSocket attribute. Furthermore, you can check here some of the header-params for validity. )==
==wsCalled directly after a successful WebSocket handshake. The <code>path</code> specifies the path which a client is connected to:message(path,message)==
Called when a <codesyntaxhighlight lang="xquery">message</code> arrives at the server. The <code>path</code> specifies the path which a client is connected to. The <code>message<declare %ws:connect('/code> is the <code>message') function local:connect() { };</codesyntaxhighlight> sent by the client. Could be a text-message or a binary-message. It should be ensured that the format of the message correct.
You can specify here how to handle your users, e. g. save a name as a WebSocket attribute. Furthermore, you can check header parameters for validity.  ==%ws:message(path, message)== Called when a client message arrives at the server. The <code>path</code> specifies the path which a client is connected to. The <code>message</code> string contains the name of the variable to which the message will be bound: <syntaxhighlight lang="xquery">declare %ws:message('/', '{$info}') function local:message($info) { };</syntaxhighlight> The value will be of type <code>xs:string</code> or <code>xs:base64Binary</code>. As there is no fixed message protocol, the client needs to take care of the message syntax. ==%ws:error(path, message)== Called when an error occurs. The <code>path</code> specifies the path which a client is connected to. The <code>message</code> string contains the name of the variable to which the message will be bound: <syntaxhighlight lang="xquery">declare %ws:error('/', '{$error}') function local:error($error) { };</syntaxhighlight> Usually, errors happen because of bad/malformed incoming packets. The WebSocket connection gets closed after the error handling. ==%ws:close(path)== Called when the WebSocket closes. The <code>path</code> specifies the path which a client is connected to: <syntaxhighlight lang="xquery">declare %ws:close('/') function local:connect() { };</syntaxhighlight>
Called when the WebSocket closes. The <code>path</code> specifies the path which a client is connected to.
The WebSocket is already closed when this annotation is called so there can be no return.
==%ws:errorheader-param(pathname, messagevariable[, default])== For accessing connection-specific properties like the HTTP version. The value will be bound to the specified <code>variable</code>. If the property has no value, an optional <code>default</code> value will be assigned instead: <syntaxhighlight lang="xquery">declare %ws:close('host', '{$host}') %ws:header-param('host', '{$host}')function local:close($host) { admin:write-log('Connection was closed: ' || $host)};</syntaxhighlight> The following parameters are available:
Called when an error has occurred{| class="wikitable" |- valign="top"! Name! Description|- valign="top"| <code>host</code>| The host of the request URI. Usually, this happens because of bad|- valign="top"| <code>http-version</malformed incoming packetscode>| The HTTP version used for the request. The |- valign="top"| <code>pathis-secure</code> specifies | Indicates if the path which a client connection is connected tosecure. |- valign="top"| <code>origin</code>| The WebSocket origin.|- valign="top"| <code>messageprotocol-version</code> is | The version of the error messageused protocol. |- valign="top"| <code>query-string</code>| The WebSocket connection gets closed after query string of the error handlingrequest URI.|- valign="top"| <code>request-uri</code>| The Request URI to use for this request.|- valign="top"| <code>sub-protocols</code>| List of configured sub-protocols.|}
==ws:header-param(name,variableGeneral information on the request can be retrieved via the [,default[Request Module]])==.
For accessing specific parameters like the Http-Version or the Sec-WebSocket-Version.=Writing Applications=
===Parameters===The following list shows the parameters of a [[WebSocketModule]] contains functions for interacting with other clients or manage specific clients. You For example, you can store and access client-specific properties for a WebSocket connection or close the parameters via the annotation <code>%ws:header-param(name,variable[,default])</code>* Http-Version -> fconnection of clients.e.: <code>%ws:param("Http-Version", "{$version}")</code>* Origin* Protocol-Version* QueryString* IsSecure* RequestURI* Host* Sec-WebSocket-Version* offset -> just for binary-Messages* len -> just for binary-Messages
=Tipps=Note that one WebSocket connection can be opened per browser tab. In contrast, only one HTTP session exists for multiple tabs in in a browser. If you want to keep client-specific data on the web server, you can either store them in HTTP sessions or in the WebSocket connection.
* For interacting with other clients or manage specific clients you should check out Note further that the [[WebSocket Module]] as well.* The results of functions annotated with <code>%ws:close</code> or <code>%ws:error</code> will not be transmitted to the client* For keeping the connection alive it is possible . Both annotations have rather been designed to implement heart-beats * Use <code>wss</code> instead of <code>ws</code> for a secure WebSocket connection* If you use a proxy servergracefully close connections, write log data, remove clients from session data, check its configuration if WebSocket support is enabledetc.
=Example=The following chapter explains how For keeping the connection alive it is recommendable to use heart-beats, and send regular pings to create a simple basic webapplication with websockets. You can find another example in the BaseX source codeserver. First of all you have to ensure that the WsServlet There is enabled in your <code>web.xml</code>. no ideal timespan for sending pings: It will should not be enabled if sent too often, but you use the standard <code>web.xml</code>should also consider possible network latencies.
If your HTTP connection is secure, you should use the <code>wss</code> instead of the <code>ws</code> scheme. If you get the <code>[basex:ws] WebSocket connection required</code> error, you may be attempting to call WebSocket functions from a non-WebSocket context. If you use a proxy server, check in the configuration if WebSockets are enabled. =Examples= ==Basic Example== The following chapter explains how to create a simple basic web application with WebSockets. You can find another example in the BaseX source code.  First of all, you have to ensure that the <code>WsServlet</code> is enabled in your <code>web.xml</code> file. It will be enabled if you use the standard configuration of BaseX. For establishing a connection to the WebSocket server , it is necessary that the server provides at least one function annotated with a WebSocket annotation. Lets Let’s start by using the annotation <code>%ws:connect('/')</code>.In the connect function, specific WebSocket a bidirectional communication with the client can be initialized: attributes like such as the id and nameof a client can be set, emit or a welcome message can be emitted to other connected users, write database entries, do nothing, ... can be setand so on.
<pre classsyntaxhighlight lang="brush:xquery">
declare
%ws:connect('/')
function example:connect() as empty-sequence() {
()
};
</presyntaxhighlight>
With The connect function is sufficient for creating the state until now you can create a connection between persistent client and /serverconnection. For doing sth. senseful In order to something sensible with the WebSocket connection , you should implement a function annotated with <code>%ws:message("/")</code>.: <pre classsyntaxhighlight lang="brush:xquery">
import module namespace ws = 'http://basex.org/modules/ws'
 
declare
%ws:message('/', '{$message}')
ws:emit($message)
};
</presyntaxhighlight> In the function above , the [[WebSocket Module]] is imported, and the WebSocketModule function <code>ws:emit</code> is used for forwarding the message to all connected clients. Notice that you have to import  The following client-side code demonstrates a basic application of the [[WebSocket Module]] before using it. connection:
It is possible now to write client functions which connect to a WebSocket, send messages to the WebSocket and receive messages from the WebSocket. <syntaxhighlight lang="javascript">The following client example provides basic code for handling the var ws = new WebSocket connection.("ws://localhost:8984/ws");
<pre>
var ws = new WebSocket("wss://localhost:8984/ws");
ws.onmessage = function(event) {
alert(event.data);
ws.send(message);
};
</presyntaxhighlightThe <code>send</code> function can be called to pass on a string to the server. There are no heart-beats in this example. This means that the connection is terminated if nothing happens for 5 minutes (standard timeout). It will also be closed if you send a message that exceeds the standard text size. ==Chat Application== In the full distributions of BaseX, you will find a little self-contained chat application that demonstrates how WebSockets can be used in practice. =Changelog=
There are no heart-beats in this exampleWebSockets werre introduced with Version 9. This means that the connection is terminated if nothing happens for 5 minutes (standard timeout).If you send a message which exceeds the textsize of 3kb defined in the <code>web.xml</code> the connection gets closed too1.
Bureaucrats, editor, reviewer, Administrators
13,550

edits

Navigation menu