Difference between revisions of "WebSocket Module"
Jump to navigation
Jump to search
(25 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
=Conventions= | =Conventions= | ||
− | * The {{Code|basex-api}} | + | * 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 | + | * 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. |
− | + | * 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 16: | Line 12: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:id() as xs:string</pre> |
− | |- | + | |- valign="top" |
| '''Summary''' | | '''Summary''' | ||
|Returns the ID of the current WebSocket. | |Returns the ID of the current WebSocket. | ||
− | |- | + | |- valign="top" |
| '''Errors''' | | '''Errors''' | ||
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | ||
Line 30: | Line 26: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:ids() as xs:string*</pre> |
− | |- | + | |- valign="top" |
| '''Summary''' | | '''Summary''' | ||
− | |Returns the ids of all currently registered | + | |Returns the ids of all currently registered WebSockets. |
|} | |} | ||
Line 41: | Line 37: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:path( |
− | |- | + | $id as xs:string |
+ | ) as xs:string</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
|Returns the path of the WebSocket with the specified {{Code|$id}}. | |Returns the path of the WebSocket with the specified {{Code|$id}}. | ||
− | |- | + | |- valign="top" |
| '''Errors''' | | '''Errors''' | ||
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | ||
Line 55: | Line 53: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:close( |
− | |- | + | $id as xs:string |
+ | ) as empty-sequence()</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
|Closes the connection of the WebSocket with the specified {{Code|$id}}. | |Closes the connection of the WebSocket with the specified {{Code|$id}}. | ||
− | |- | + | |- valign="top" |
| '''Errors''' | | '''Errors''' | ||
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | ||
Line 71: | Line 71: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:send( |
− | |- | + | $message as item(), |
+ | $ids as xs:string* | ||
+ | ) as empty-sequence()</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Sends a <code>$message</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 82: | Line 88: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:broadcast( |
− | |- | + | $message as xs:anyAtomicType |
+ | ) as empty-sequence()</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Broadcasts a <code>$message</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 {{Function||ws:send}} for more details on the message handling. |
|} | |} | ||
Line 93: | Line 101: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:emit( |
− | |- | + | $message as xs:anyAtomicType |
+ | ) as empty-sequence()</pre> | ||
+ | |- valign="top" | ||
+ | | '''Summary''' | ||
+ | |Emits a <code>$message</code> to all connected clients. Invocations of this function are equivalent to <code>ws:send($message, ws:ids())</code>. See {{Function||ws:send}} for more details on the message handling. | ||
+ | |} | ||
+ | |||
+ | ==ws:eval== | ||
+ | |||
+ | {| width='100%' | ||
+ | |- valign="top" | ||
+ | | width='120' | '''Signature''' | ||
+ | |<pre>ws:eval( | ||
+ | $query as xs:anyAtomicType, | ||
+ | $bindings as map(*)? := (), | ||
+ | $options as map(*)? := map { } | ||
+ | ) as xs:string</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''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. | ||
+ | |- valign="top" | ||
+ | | '''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. | ||
+ | |- valign="top" | ||
+ | | '''Examples''' | ||
+ | | | ||
+ | * Schedule a second query that will notify the client 10 seconds later that a message was processed: | ||
+ | <syntaxhighlight lang="xquery"> | ||
+ | declare | ||
+ | %ws:message('/tasks', '{$message}') | ||
+ | function local:message($message) { | ||
+ | ws:eval('prof:sleep(10000), "Your message has been processed."') | ||
+ | }; | ||
+ | </syntaxhighlight> | ||
|} | |} | ||
Line 106: | Line 148: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:get( |
− | |- | + | $id as xs:string, |
+ | $name as xs:string, | ||
+ | $default as item()* := () | ||
+ | ) as item()*</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Returns the value of an attribute with the specified {{Code|$name}} | + | |Returns the value of an attribute with the specified {{Code|$name}} for 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. |
− | |- | + | |- valign="top" |
| '''Errors''' | | '''Errors''' | ||
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | ||
Line 120: | Line 166: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:set( |
− | |- | + | $id as xs:string, |
+ | $name as xs:string, | ||
+ | $value as item()* | ||
+ | ) as empty-sequence()</pre> | ||
+ | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | | | + | |Assigns the specified {{Code|$value}} to the attribute with the specified {{Code|$name}} for the WebSocket with the specified {{Mono|$id}}. |
− | |- | + | |- valign="top" |
| '''Errors''' | | '''Errors''' | ||
− | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists | + | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists. |
|} | |} | ||
Line 134: | Line 184: | ||
{| width='100%' | {| width='100%' | ||
− | |- | + | |- valign="top" |
− | | width='120' | ''' | + | | width='120' | '''Signature''' |
− | | | + | |<pre>ws:delete( |
− | |- | + | $id as xs:string, |
+ | $name as xs:string | ||
+ | ) as empty-sequence()</pre> | ||
+ | |- valign="top" | ||
| '''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}}. | ||
− | |- | + | |- valign="top" |
| '''Errors''' | | '''Errors''' | ||
|{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | |{{Error|not-found|#Errors}} No WebSocket with the specified id exists. | ||
Line 149: | Line 202: | ||
==Example 1== | ==Example 1== | ||
− | < | + | <syntaxhighlight lang="xquery"> |
− | import module namespace ws = "http://basex.org/modules/ | + | import module namespace ws = "http://basex.org/modules/ws"; |
declare | declare | ||
%ws:connect('/') | %ws:connect('/') | ||
− | function local:connect() as | + | 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 162: | Line 215: | ||
return ws:broadcast($message) | return ws:broadcast($message) | ||
}; | }; | ||
− | </ | + | </syntaxhighlight> |
'''Explanation:''' | '''Explanation:''' | ||
Line 172: | Line 225: | ||
==Example 2== | ==Example 2== | ||
− | < | + | <syntaxhighlight lang="xquery"> |
− | import module namespace ws = "http://basex.org/modules/ | + | import module namespace ws = "http://basex.org/modules/ws"; |
declare | declare | ||
Line 179: | Line 232: | ||
function local:message( | function local:message( | ||
$message as xs:string | $message as xs:string | ||
− | ) as | + | ) 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) | ||
}; | }; | ||
− | </ | + | </syntaxhighlight> |
'''Explanation:''' | '''Explanation:''' | ||
Line 196: | Line 249: | ||
! width="110"|Code | ! width="110"|Code | ||
|Description | |Description | ||
− | |- | + | |- valign="top" |
− | |||
− | |||
− | |||
|{{Code|not-found}} | |{{Code|not-found}} | ||
|No WebSocket with the specified id exists. | |No WebSocket with the specified id exists. | ||
Line 205: | Line 255: | ||
=Changelog= | =Changelog= | ||
+ | |||
+ | ;Version 9.2 | ||
+ | |||
+ | * Added: {{Function||ws:eval}} | ||
This module was introduced with Version 9.1. | This module was introduced with Version 9.1. |
Latest revision as of 11:39, 28 June 2023
This XQuery Module contains functions for accessing specific WebSocket functions. This module is mainly useful in the context of WebSockets.
Contents
Conventions[edit]
- 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 thews
prefix. - As sessions are side-effecting operations, all functions are flagged as non-deterministic. As a result, some query optimizations will be suppressed.
General Functions[edit]
ws:id[edit]
Signature | 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[edit]
Signature | ws:ids() as xs:string* |
Summary | Returns the ids of all currently registered WebSockets. |
ws:path[edit]
Signature | 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[edit]
Signature | 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[edit]
ws:send[edit]
Signature | 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:
|
ws:broadcast[edit]
Signature | 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[edit]
Signature | 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[edit]
Signature | ws:eval( $query as xs:anyAtomicType, $bindings as map(*)? := (), $options as map(*)? := 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:
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 |
declare
%ws:message('/tasks', '{$message}')
function local:message($message) {
ws:eval('prof:sleep(10000), "Your message has been processed."')
};
|
WebSocket Attributes[edit]
ws:get[edit]
Signature | 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 for 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[edit]
Signature | ws:set( $id as xs:string, $name as xs:string, $value as item()* ) as empty-sequence() |
Summary | Assigns the specified $value to the attribute with the specified $name for the WebSocket with the specified $id .
|
Errors | not-found : No WebSocket with the specified id exists.
|
ws:delete[edit]
Signature | 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[edit]
Example 1[edit]
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[edit]
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[edit]
Code | Description |
---|---|
not-found
|
No WebSocket with the specified id exists. |
Changelog[edit]
- Version 9.2
- Added:
ws:eval
This module was introduced with Version 9.1.