Difference between revisions of "WebSockets"

From BaseX Documentation
Jump to navigation Jump to search
Line 1: Line 1:
 
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.  
 
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.  
  
After an initial HTTP-request it communicates over a single TCP connection. The WebSocket protocol was standardized in RFC 6455 by the IETF. It creates the possibility to transponse real-time data from the server to the client and the client to the server.  
+
The WebSocket protocol was standardized in [https://tools.ietf.org/html/rfc6455 RFC 6455] by the IETF. After an initial HTTP-request, all communication takes place over a single TCP connection. In contrast to the HTTP protocol, a connection will be kept alive, and a server can send unsolicited data to the client.
  
In contrast to the HTTP protocol it enables the server to send unsolicited data to the client. For establishing a WebSocket connection there is a WebSocket handshake request, send by the client. The server returns a WebSocket handshake response. This will be handled by jetty. After a successful handshake, the annotation <code>ws:connect</code> will be called. The persistent connection is now open until an the client or the server closes it, an error occures or a timeout happens. How long this timeout goes can be set in the web.xml. It is possible to transmit all kind of data, binary or text.
+
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 an the client or the server closes it, an error occurs or a timeout happens. The timeout can be specified in the <code>web.xml</code> configuration file. It is possible to transmit all kind of data, binary or text.  
 
 
For further information about the WebSocket protocol check out the RFC6455 spec.
 
  
 
=Introduction=
 
=Introduction=
Line 16: Line 14:
  
 
To speed up processing, the functions of the existing XQuery modules are automatically cached in main memory:
 
To speed up processing, the functions of the existing XQuery modules are automatically cached in main memory:
 +
 
* Functions will be invalidated and parsed again if the timestamp of their module changes.
 
* Functions will be invalidated and parsed again if the timestamp of their module changes.
  
Line 22: Line 21:
 
<pre class="brush:xquery">
 
<pre class="brush:xquery">
 
module namespace page = 'http://basex.org/modules/web-page';
 
module namespace page = 'http://basex.org/modules/web-page';
 +
 +
import module namespace ws = "http://basex.org/modules/Websocket";
 +
 
declare
 
declare
 
%ws:connect("/")
 
%ws:connect("/")
function wsdba:connect(
+
function page:connect(
 
) {
 
) {
 
   (: Do something after a client connects to the path "/" :)
 
   (: Do something after a client connects to the path "/" :)
 
};
 
};
</pre>
 
  
<pre class="brush:xquery">
 
module namespace page = 'http://basex.org/modules/web-page';
 
 
declare
 
declare
 
   %ws:message("/","{$message}")
 
   %ws:message("/","{$message}")
function chat:message(
+
function page:message(
 
   $message as xs:string
 
   $message as xs:string
 
) {
 
) {
 
   (: Do something if a message arrives at the server :)
 
   (: Do something if a message arrives at the server :)
 
};
 
};
</pre>
 
 
<pre class="brush:xquery">
 
module namespace page = 'http://basex.org/modules/web-page';
 
import module namespace ws = "http://basex.org/modules/Websocket";
 
  
 
declare  
 
declare  
 
   %ws:close("/")
 
   %ws:close("/")
 
function chat:close() {
 
function chat:close() {
    (: Build a close message with the id of the client who closes the connection :)
+
  (: Return a close message with the id of the client who closes the connection :)
    let $client-id := ws:id()
+
  let $client-id := ws:id()
    let $msg := json:serialize(
+
  let $msg := json:serialize(
      <json type="object">
+
    <json type="object">
        <type>WebsocketClosed</type>
+
      <type>WebsocketClosed</type>
        <idThatClosed>{$client-id}</idThatClosed>
+
      <idThatClosed>{$client-id}</idThatClosed>
      </json>
+
    </json>
    )
+
  )
    (: Broadcast the message to all connected users except the client who closes the connection :)
+
  (: Broadcast the message to all connected users except the client who closes the connection :)
    return ws:broadcast($msg)
+
  return ws:broadcast($msg)
  };
+
};
 
</pre>
 
</pre>
  
Line 65: Line 59:
 
* Enable the WebSocket servlet in the web.xml. You can set here the maxIdleTime, maxTextMessageSize and maxBinaryMessageSize too.
 
* Enable the WebSocket servlet in the web.xml. You can set here the maxIdleTime, maxTextMessageSize and maxBinaryMessageSize too.
 
* If you get a message that exceeds the maxTextMessageSize/maxBinaryMessageSize or, if not set, the default messageSize of Jetty of 65 536 bytes (64 kB) then the connection will close. In this case, the ws:error annotation will be called.  
 
* If you get a message that exceeds the maxTextMessageSize/maxBinaryMessageSize or, if not set, the default messageSize of Jetty of 65 536 bytes (64 kB) then the connection will close. In this case, the ws:error annotation will be called.  
 +
 
<pre class="brush:xml">
 
<pre class="brush:xml">
 
<servlet>
 
<servlet>
Line 89: Line 84:
 
==ws:connect(path)==
 
==ws:connect(path)==
  
Called when a client WebSocket connection successfully connected to the server. The <code>path</code> specifies the path the client connected to.
+
Called directly after a successful WebSocket handshake. The <code>path</code> specifies the path to which a client is connected to.
  
 
==ws:message(path,message)==
 
==ws:message(path,message)==
  
Called when a <code>message</code> arrives at the server. The <code>path</code> specifies the <code>path</code> the client is connected to. The <code>message</code> is the <code>message</code> sent by the client. Could be a text-message or a binary-message.
+
Called when a <code>message</code> arrives at the server. The <code>path</code> specifies the path to which a client is connected to. The <code>message</code> is the <code>message</code> sent by the client. Could be a text-message or a binary-message.
  
 
==ws:close(path)==
 
==ws:close(path)==
  
Called when the WebSocket closes. The <code>path</code> specifies the <code>path</code> the client is connected to.
+
Called when the WebSocket closes. The <code>path</code> specifies the path to which a client is connected to.
 
The WebSocket is already closed when this annotation is called so there can be no return.
 
The WebSocket is already closed when this annotation is called so there can be no return.
  
==ws:error(path,message)==
+
==ws:error(path, message)==
Called when an error occurred. Usually, this happens because of bad/malformed incoming packets. The <code>path</code> specifies the <code>path</code> the client is connected to. The <code>message</code> is the error-message.
 
The WebSocket gets closed after an error occurred.
 
 
 
==ws:path(name,variable[,default]==
 
  
The value of the first parameter will be assigned to the variable specified as the second parameter. The third parameter can be a default value.  
+
Called when an error has occurred. Usually, this happens because of bad/malformed incoming packets. The <code>path</code> specifies the path to which a client is connected to. The <code>message</code> is the error message. The WebSocket connection gets closed after the error handling.
  
 
==ws:header-param(name,variable[,default]==
 
==ws:header-param(name,variable[,default]==

Revision as of 16:31, 31 August 2018

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.

The WebSocket protocol was standardized in RFC 6455 by the IETF. After an initial HTTP-request, all communication takes place over a single TCP connection. In contrast to the HTTP protocol, a connection will be kept alive, and a server can send unsolicited data to the 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 an the client or the server closes it, an error occurs or a timeout happens. The timeout can be specified in the web.xml configuration file. It is possible to transmit all kind of data, binary or text.

Introduction

Preliminaries

There are a bunch of annotations depending to WebSockets for annotating XQuery functions. When a WebSocket message arrives at the server, an XQuery function will be invoked that matches the constraints indicated by its annotations.

If a WebSocket function is requested (like connecting to the path '/', message to the path '/path', ...), the module directory and its sub-directories will be traversed, and all XQuery files will be parsed for functions with WebSocket annotations. Sub-directories that include an .ignore the file will be skipped.

To speed up processing, the functions of the existing XQuery modules are automatically cached in main memory:

  • Functions will be invalidated and parsed again if the timestamp of their module changes.

Examples

module namespace page = 'http://basex.org/modules/web-page';

import module namespace ws = "http://basex.org/modules/Websocket";

declare
%ws:connect("/")
function page:connect(
) {
  (: Do something after a client connects to the path "/" :)
};

declare
  %ws:message("/","{$message}")
function page:message(
  $message as xs:string
) {
  (: Do something if a message arrives at the server :)
};

declare 
  %ws:close("/")
function chat:close() {
  (: Return a close message with the id of the client who closes the connection :)
  let $client-id := ws:id()
  let $msg := json:serialize(
    <json type="object">
      <type>WebsocketClosed</type>
      <idThatClosed>{$client-id}</idThatClosed>
    </json>
  )
  (: Broadcast the message to all connected users except the client who closes the connection :)
  return ws:broadcast($msg)
};

Usage

  • Enable the WebSocket servlet in the web.xml. You can set here the maxIdleTime, maxTextMessageSize and maxBinaryMessageSize too.
  • If you get a message that exceeds the maxTextMessageSize/maxBinaryMessageSize or, if not set, the default messageSize of Jetty of 65 536 bytes (64 kB) then the connection will close. In this case, the ws:error annotation will be called.
<servlet>
  <servlet-name>wsservlet</servlet-name>
  <servlet-class>org.basex.http.ws.WsServlet</servlet-class>
  <init-param>
    <param-name>maxIdleTime</param-name>
    <param-value>100000</param-value>
  </init-param>
  <init-param>
    <param-name>maxTextMessageSize</param-name>
    <param-value>3000</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>wsservlet</servlet-name>
  <url-pattern>/ws/*</url-pattern>
</servlet-mapping>
  • Annotate your specific XQuery-Functions with WebSocketAnnotations.

Annotations

ws:connect(path)

Called directly after a successful WebSocket handshake. The path specifies the path to which a client is connected to.

ws:message(path,message)

Called when a message arrives at the server. The path specifies the path to which a client is connected to. The message is the message sent by the client. Could be a text-message or a binary-message.

ws:close(path)

Called when the WebSocket closes. The path specifies the path to which a client is connected to. The WebSocket is already closed when this annotation is called so there can be no return.

ws:error(path, message)

Called when an error has occurred. Usually, this happens because of bad/malformed incoming packets. The path specifies the path to which a client is connected to. The message is the error message. The WebSocket connection gets closed after the error handling.

ws:header-param(name,variable[,default]

For accessing specific parameters like the Http-Version or the Sec-WebSocket-Version.

Parameters

  • Http-Version -> f.e.: ```%ws:param("Http-Version", "{$version}")```
  • Origin
  • Protocol-Version
  • QueryString
  • IsSecure
  • RequestURI
  • Host
  • Sec-WebSocket-Version
  • offset -> just for binary-Messages
  • len -> just for binary-Messages

Tipps

  • For interacting with other clients or manage specific clients you should check out the WebSocket Module as well.