Difference between revisions of "WebSocket Module"

From BaseX Documentation
Jump to navigation Jump to search
(12 intermediate revisions by 2 users not shown)
Line 3: Line 3:
 
=Conventions=
 
=Conventions=
  
* The {{Code|basex-api}} package must be included in the classpath. This is always the case if you use one of the complete distributions (zip, exe, war) of BaseX.
+
* The module will be available if the {{Code|basex-api}} library is found in the classpath. This is the case if you use one of the complete distributions of BaseX (zip, exe, war).
* All functions and errors are assigned to the <code><nowiki>http://basex.org/modules/ws</nowiki></code> namespace. The module must be imported in the query prolog:
+
* All functions and errors are assigned to the <code><nowiki>http://basex.org/modules/ws</nowiki></code> namespace, which is statically bound to the {{Code|ws}} prefix. Prior to {{Version|9.2}}, the module needed to be imported in the query prolog:
  
 
<pre class="brush:xquery">
 
<pre class="brush:xquery">
Line 10: Line 10:
 
...
 
...
 
</pre>
 
</pre>
 +
 +
* As sessions are side-effecting operations, all functions are flagged as ''non-deterministic''. As a result, some query optimizations will be suppressed.
  
 
=General Functions=
 
=General Functions=
Line 22: Line 24:
 
| '''Summary'''
 
| '''Summary'''
 
|Returns the ID of the current WebSocket.
 
|Returns the ID of the current WebSocket.
 +
|-
 +
| '''Errors'''
 +
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists.
 
|}
 
|}
  
Line 44: Line 49:
 
| '''Summary'''
 
| '''Summary'''
 
|Returns the path of the WebSocket with the specified {{Code|$id}}.
 
|Returns the path of the WebSocket with the specified {{Code|$id}}.
 +
|-
 +
| '''Errors'''
 +
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists.
 
|}
 
|}
  
Line 55: Line 63:
 
| '''Summary'''
 
| '''Summary'''
 
|Closes the connection of the WebSocket with the specified {{Code|$id}}.
 
|Closes the connection of the WebSocket with the specified {{Code|$id}}.
 +
|-
 +
| '''Errors'''
 +
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists.
 
|}
 
|}
  
Line 64: Line 75:
 
|-
 
|-
 
| width='120' | '''Signatures'''
 
| width='120' | '''Signatures'''
|{{Func|ws:send|$message as xs:anyAtomicType, $ids as xs:string*|empty-sequence()}}
+
|{{Func|ws:send|$message as item(), $ids as xs:string*|empty-sequence()}}
 
|-
 
|-
 
| '''Summary'''
 
| '''Summary'''
|Sends a <code>$message</code>, which may be of type xs:string, xs:base64Binary or xs:hexBinary, to the clients with the specified <code>$ids</code>.
+
|Sends a <code>$message</code> to the clients with the specified <code>$ids</code>. Ids that cannot be assigned to clients will be ignored. The message will be handled as follows:
 +
* Items of type {{Code|xs:base64Binary}} and {{Code|xs:hexBinary}} will be transmitted as binary messages.
 +
* Function items (maps, arrays) will be serialized as JSON and transmitted as string messages.
 +
* All other items will be serialized with the default serialization options and transmitted as string messages.
 
|}
 
|}
  
Line 78: Line 92:
 
|-
 
|-
 
| '''Summary'''
 
| '''Summary'''
|Broadcasts a <code>$message</code>, which may be of type xs:string, xs:base64Binary or xs:hexBinary, to all connected clients except to the caller. Invocations of this convenience function are equivalent to <code>ws:send($message, ws:ids()[. != ws:id()])</code>.
+
|Broadcasts a <code>$message</code> to all connected clients except to the caller. Invocations of this convenience function are equivalent to <code>ws:send($message, ws:ids()[. != ws:id()])</code>. See [[#ws:send|ws:send]] for more details on the message handling.
 
|}
 
|}
  
Line 89: Line 103:
 
|-
 
|-
 
| '''Summary'''
 
| '''Summary'''
|Emits a <code>$message</code>, which may be of type xs:string, xs:base64Binary or xs:hexBinary, to all connected clients. Invocations of this function are equivalent to <code>ws:send($message, ws:ids())</code>.
+
|Emits a <code>$message</code> to all connected clients. Invocations of this function are equivalent to <code>ws:send($message, ws:ids())</code>. See [[#ws:send|ws:send]] for more details on the message handling.
 +
|}
 +
 
 +
==ws:eval==
 +
 
 +
{{Mark|Introduced with 9.2:}}
 +
 
 +
{| width='100%'
 +
|-
 +
| width='120' | '''Signatures'''
 +
|{{Func|ws:eval|$query as xs:anyAtomicItem|xs:string}}<br />{{Func|ws:eval|$query as xs:anyAtomicItem, $bindings as map(*)?|xs:string}}<br />{{Func|ws:eval|$query as xs:anyAtomicItem, $bindings as map(*)?, $options as map(*)?|xs:string}}<br />
 +
|-
 +
| '''Summary'''
 +
|Schedules the evaluation of the supplied {{Code|$query}} and returns the result to the calling WebSocket client. The query can be a URI or a string, and variables and context items can be declared via {{Code|$bindings}} (see {{Function|XQuery|xquery:eval}} for more details). The following {{Code|$options}} can be supplied:
 +
* {{Code|base-uri}}: sets the [https://www.w3.org/TR/xquery-31/#dt-static-base-uri base-uri property] for the query. This URI will be used when resolving relative URIs, such as with {{Code|fn:doc}}.
 +
* {{Code|id}}: sets a custom job id. The id must not start with the standard <code>job</code> prefix, and it can only be assigned if no job with the same name exists.
 +
Query scheduling is recommendable if the immediate query execution might be too time consuming and lead to a timeout.
 +
|-
 +
| '''Errors'''
 +
|{{Error|overflow|#Errors}} Query execution is rejected, because too many jobs are queued or being executed. <br/>{{Error|id|#Errors}} The specified id is invalid or has already been assigned.
 +
|-
 +
| '''Examples'''
 +
|
 +
* Schedule a second query that will notify the client 10 seconds later that a message was processed:
 +
<pre class='brush:xquery'>
 +
declare
 +
  %ws:message('/tasks', '{$message}')
 +
function local:message($message) {
 +
  ws:eval('prof:sleep(10000), "Your message has been processed."')
 +
};
 +
</pre>
 
|}
 
|}
  
Line 103: Line 147:
 
| '''Summary'''
 
| '''Summary'''
 
|Returns the value of an attribute with the specified {{Code|$name}} from the WebSocket with the specified {{Code|$id}}. If the attribute is unknown, an empty sequence or the optionally specified {{Code|$default}} value will be returned instead.
 
|Returns the value of an attribute with the specified {{Code|$name}} from the WebSocket with the specified {{Code|$id}}. If the attribute is unknown, an empty sequence or the optionally specified {{Code|$default}} value will be returned instead.
 +
|-
 +
| '''Errors'''
 +
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists.
 
|}
 
|}
  
Line 116: Line 163:
 
|-
 
|-
 
| '''Errors'''
 
| '''Errors'''
|{{Error|set|#Errors}} The supplied value cannot be materialized.
+
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists.<br>{{Error|set|#Errors}} The supplied value cannot be materialized.
 
|}
 
|}
  
Line 128: Line 175:
 
| '''Summary'''
 
| '''Summary'''
 
|Deletes an attribute with the specified {{Code|$name}} from the WebSocket with the specified {{Mono|$id}}.
 
|Deletes an attribute with the specified {{Code|$name}} from the WebSocket with the specified {{Mono|$id}}.
 +
|-
 +
| '''Errors'''
 +
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists.
 
|}
 
|}
  
Line 135: Line 185:
  
 
<pre class="brush:xquery">
 
<pre class="brush:xquery">
import module namespace ws = "http://basex.org/modules/Websocket";
+
import module namespace ws = "http://basex.org/modules/ws";
  
 
declare
 
declare
 
   %ws:connect('/')
 
   %ws:connect('/')
function local:connect() as xs:string {
+
function local:connect() as empty-sequence() {
 
   let $id := ws:id()
 
   let $id := ws:id()
 
   let $message := json:serialize(map {
 
   let $message := json:serialize(map {
Line 158: Line 208:
  
 
<pre class="brush:xquery">
 
<pre class="brush:xquery">
import module namespace ws = "http://basex.org/modules/Websocket";
+
import module namespace ws = "http://basex.org/modules/ws";
  
 
declare
 
declare
Line 164: Line 214:
 
function local:message(
 
function local:message(
 
   $message as xs:string
 
   $message as xs:string
) as xs:string {
+
) as empty-sequence() {
 
   let $message := json:serialize(map { 'message': $message })
 
   let $message := json:serialize(map { 'message': $message })
 
   return ws:emit($message)
 
   return ws:emit($message)
Line 186: Line 236:
 
|-
 
|-
 
|{{Code|not-found}}
 
|{{Code|not-found}}
|The specified WebSocket was not found.
+
|No WebSocket with the specified id exists.
 
|}
 
|}
  
 
=Changelog=
 
=Changelog=
 +
 +
;Version 9.2
 +
 +
* Added: [[#ws:eval|ws:eval]]
  
 
This module was introduced with Version 9.1.
 
This module was introduced with Version 9.1.

Revision as of 16:01, 1 February 2019

This XQuery Module contains functions for accessing specific WebSocket functions. This module is mainly useful in the context of WebSockets.

Conventions

  • The module will be available if the basex-api library is found in the classpath. This is the case if you use one of the complete distributions of BaseX (zip, exe, war).
  • All functions and errors are assigned to the http://basex.org/modules/ws namespace, which is statically bound to the ws prefix. Prior to Version 9.2, the module needed to be imported in the query prolog:
import module namespace ws = "http://basex.org/modules/ws";
...
  • As sessions are side-effecting operations, all functions are flagged as non-deterministic. As a result, some query optimizations will be suppressed.

General Functions

ws:id

Signatures ws:id() as xs:string
Summary Returns the ID of the current WebSocket.
Errors not-found: No WebSocket with the specified id exists.

ws:ids

Signatures ws:ids() as xs:string*
Summary Returns the ids of all currently registered WebSocket.

ws:path

Signatures ws:path($id as xs:string) as xs:string
Summary Returns the path of the WebSocket with the specified $id.
Errors not-found: No WebSocket with the specified id exists.

ws:close

Signatures ws:close($id as xs:string) as empty-sequence()
Summary Closes the connection of the WebSocket with the specified $id.
Errors not-found: No WebSocket with the specified id exists.

Sending Data

ws:send

Signatures ws:send($message as item(), $ids as xs:string*) as empty-sequence()
Summary Sends a $message to the clients with the specified $ids. Ids that cannot be assigned to clients will be ignored. The message will be handled as follows:
  • Items of type xs:base64Binary and xs:hexBinary will be transmitted as binary messages.
  • Function items (maps, arrays) will be serialized as JSON and transmitted as string messages.
  • All other items will be serialized with the default serialization options and transmitted as string messages.

ws:broadcast

Signatures ws:broadcast($message as xs:anyAtomicType) as empty-sequence()
Summary Broadcasts a $message to all connected clients except to the caller. Invocations of this convenience function are equivalent to ws:send($message, ws:ids()[. != ws:id()]). See ws:send for more details on the message handling.

ws:emit

Signatures ws:emit($message as xs:anyAtomicType) as empty-sequence()
Summary Emits a $message to all connected clients. Invocations of this function are equivalent to ws:send($message, ws:ids()). See ws:send for more details on the message handling.

ws:eval

Template:Mark

Signatures ws:eval($query as xs:anyAtomicItem) as xs:string
ws:eval($query as xs:anyAtomicItem, $bindings as map(*)?) as xs:string
ws:eval($query as xs:anyAtomicItem, $bindings as map(*)?, $options as map(*)?) as xs:string
Summary Schedules the evaluation of the supplied $query and returns the result to the calling WebSocket client. The query can be a URI or a string, and variables and context items can be declared via $bindings (see xquery:eval for more details). The following $options can be supplied:
  • base-uri: sets the base-uri property for the query. This URI will be used when resolving relative URIs, such as with fn:doc.
  • id: sets a custom job id. The id must not start with the standard job prefix, and it can only be assigned if no job with the same name exists.

Query scheduling is recommendable if the immediate query execution might be too time consuming and lead to a timeout.

Errors overflow: Query execution is rejected, because too many jobs are queued or being executed.
id: The specified id is invalid or has already been assigned.
Examples
  • Schedule a second query that will notify the client 10 seconds later that a message was processed:
declare
  %ws:message('/tasks', '{$message}')
function local:message($message) {
  ws:eval('prof:sleep(10000), "Your message has been processed."')
}; 

WebSocket Attributes

ws:get

Signatures ws:get($id as xs:string, $name as xs:string) as item()*
ws:get($id as xs:string, $name as xs:string, $default as item()*) as item()*
Summary Returns the value of an attribute with the specified $name from the WebSocket with the specified $id. If the attribute is unknown, an empty sequence or the optionally specified $default value will be returned instead.
Errors not-found: No WebSocket with the specified id exists.

ws:set

Signatures ws:set($id as xs:string, $name as xs:string, $value as item()*) as empty-sequence()
Summary Returns the specified value of the attribute with the specified $name from the WebSocket with the specified $id.
Errors not-found: No WebSocket with the specified id exists.
set: The supplied value cannot be materialized.

ws:delete

Signatures ws:delete($id as xs:string, $name as xs:string) as empty-sequence()
Summary Deletes an attribute with the specified $name from the WebSocket with the specified $id.
Errors not-found: No WebSocket with the specified id exists.

Examples

Example 1

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

declare
  %ws:connect('/')
function local:connect() as empty-sequence() {
  let $id := ws:id()
  let $message := json:serialize(map {
    'type': 'Connect',
    'id': $id
  })
  return ws:broadcast($message)
};

Explanation:

  • The function has a %ws:connect annotation. It gets called if a client successfully creates a WebSocket connection to the path / (check out WebSockets for further information).
  • A JSON response is generated, which contains the new client id and a Connect string.
  • This response will be sent to all other connected clients.

Example 2

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

declare
  %ws:message('/', '{$message}')
function local:message(
  $message as xs:string
) as empty-sequence() {
  let $message := json:serialize(map { 'message': $message })
  return ws:emit($message)
};

Explanation:

  • The function has a %ws:message annotation. It gets called if a client sends a new message.
  • A JSON response is generated, which contains the message string.
  • This response will be sent to all connected clients (including the calling client).

Errors

Code Description
set The supplied value cannot be materialized.
not-found No WebSocket with the specified id exists.

Changelog

Version 9.2

This module was introduced with Version 9.1.