[mod] connects

This commit is contained in:
Andy Bunce 2025-07-11 22:51:59 +01:00
parent 1c758567d4
commit 3c60660f16
5 changed files with 46 additions and 173 deletions

View file

@ -14,7 +14,7 @@ declare variable $chat-util:id := 'id';
: Sends a users list (all, active) to all registered clients.
:)
declare function chat-util:users() as empty-sequence() {
ws:emit({
ws:emit(map{
'type': 'users',
'users': array { sort(user:list()) },
'active': array { distinct-values(
@ -34,7 +34,7 @@ declare function chat-util:message(
$to as xs:string?
) as empty-sequence() {
let $ws-ids := ws:ids()[not($to) or ws:get(., $chat-util:id) = $to]
return ws:send({
return ws:send(map{
'type': 'message',
'text': serialize($text),
'from': ws:get(ws:id(), $chat-util:id),

View file

@ -5,15 +5,15 @@
module namespace chat-ws = 'chat-ws';
import module namespace chat-util = 'chat/util' at 'lsp-util.xqm';
import module namespace request = "http://exquery.org/ns/request";
(:~
: Creates a WebSocket connection. Registers the user and notifies all clients.
:)
declare
%ws:connect('/chat')
%ws:connect('/lsp')
function chat-ws:connect() as empty-sequence() {
ws:set(ws:id(), $chat-util:id, session:get($chat-util:id)),
ws:set(ws:id()=>trace("CONNECT: "), $chat-util:id, session:get($chat-util:id)),
chat-util:users()
};
@ -22,7 +22,7 @@ function chat-ws:connect() as empty-sequence() {
: @param $message message
:)
declare
%ws:message('/chat', '{$message}')
%ws:message('/lsp', '{$message}')
function chat-ws:message(
$message as xs:string
) as empty-sequence() {
@ -39,7 +39,7 @@ function chat-ws:message(
: Closes a WebSocket connection. Unregisters the user and notifies all clients.
:)
declare
%ws:close('/chat')
%ws:close('/lsp')
function chat-ws:close() as empty-sequence() {
ws:delete(ws:id(), $chat-util:id),
chat-util:users()

View file

@ -1,144 +0,0 @@
(:~
: Simple WebSocket chat. RESTXQ functions.
: @author BaseX Team, BSD License
:)
module namespace chat = 'chat';
import module namespace chat-util = 'chat/util' at 'lsp-util.xqm';
(:~
: Login or main page.
: @return HTML page
:)
declare
%rest:path('/lsp')
%output:method('html')
function chat:chat() as element() {
if(session:get($chat-util:id)) then (
chat:main()
) else (
chat:login()
)
};
(:~
: Checks the user input, registers the user and reloads the chat.
: @param $name username
: @param $pass password
: @return redirection
:)
declare
%rest:POST
%rest:path('/lsp/login-check')
%rest:form-param('name', '{$name}')
%rest:form-param('pass', '{$pass}')
function chat:login-check(
$name as xs:string,
$pass as xs:string
) as element(rest:response) {
try {
user:check($name, $pass),
session:set($chat-util:id, $name)
} catch user:* {
(: login fails: no session info is set :)
},
web:redirect('/chat')
};
(:~
: Logs out the current user, notifies all WebSocket clients, and redirects to the login page.
: @return redirection
:)
declare
%rest:path('/lsp/logout')
function chat:logout() as element(rest:response) {
session:get($chat-util:id) ! chat-util:close(.),
session:delete($chat-util:id),
web:redirect('/chat')
};
(:~
: Returns the HTML login page.
: @return HTML page
:)
declare %private function chat:login() as element(html) {
chat:wrap((
<div class='warning'>Please enter your credentials:</div>,
<form action='/chat/login-check' method='post'>
<div class='small'/>
<table>
<tr>
<td><b>Name:</b></td>
<td>
<input size='30' name='name' id='user' autofocus=''/>
</td>
</tr>
<tr>
<td><b>Password:</b></td>
<td>{
<input size='30' type='password' name='pass'/>,
<button type='submit'>Login</button>
}</td>
</tr>
</table>
</form>
), ())
};
(:~
: Returns the HTML main page.
: @return HTML page
:)
declare %private function chat:main() as element(html) {
chat:wrap((
<p>
<input type='text' size='60' autofocus='true' placeholder='Message to all users…'
id='input' onkeydown='keyDown(event)' autocomplete='off'/>
</p>,
<table width='100%'>
<tr>
<td width='100'>
<div class='note'>USERS (<b>online</b>)</div>
<div id='users'/>
</td>
<td class='vertical'/>
<td>
<div class='note'>CHAT MESSAGES</div>
<div id='messages'/>
</td>
</tr>
</table>
), <script type='text/javascript' src='/static/chat.js'/>)
};
(:~
: Returns an HTML page.
: @param $contents page contents
: @param $login login page
: @return HTML page
:)
declare %private function chat:wrap(
$contents as item()*,
$headers as element()*
) as element(html) {
<html>
<head>
<meta charset='utf-8'/>
<title>BaseX WebSocket Chat</title>
<meta name='author' content='BaseX Team, BSD License'/>
<link rel='stylesheet' type='text/css' href='/static/style.css'/>
{ $headers }
</head>
<body>
<span class='right'>
{
for $id in session:get($chat-util:id)
return <span><b>{ $id }</b> (<a href='/chat/logout'>logout</a>)</span>
}
&#xa0; <a href='/'><img src='static/basex.svg' class='img'/></a>
</span>
<h1>BaseX WebSocket Chat</h1>
{ $contents }
</body>
</html>
};