WebSockets

From BaseX Documentation
Revision as of 17:43, 28 August 2018 by CG (talk | contribs)
Jump to navigation Jump to search

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.

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 ws:connect 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 further information about the WebSocket protocol check out the RFC6455 spec.

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';
declare
%ws:connect("/")
function wsdba:connect(
) {
  (: Do something after a client connects to the path "/" :)
};
module namespace page = 'http://basex.org/modules/web-page';
declare
  %ws:message("/","{$message}")
function chat:message(
  $message as xs:string
) {
  (: Do something if a message arrives at the server :)
};
module namespace page = 'http://basex.org/modules/web-page';
import module namespace ws = "http://basex.org/modules/Websocket";

declare 
  %ws:close("/")
function chat:close() {
    (: Build 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 when a client WebSocket connection successfully connected to the server. The path specifies the path the client connected to.

ws:message(path,message)

Called when a message arrives at the server. The path specifies the path the 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 the 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 occurred. Usually, this happens because of bad/malformed incoming packets. The path specifies the path the client is connected to. The message 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.

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.