This is very basic example code demonstarting web sockets using SWI-Prolog. There are three files, sever.pl, index.html and time.js. While the code could be further refactored it is left in its present form as it is typical of standard use cases.
File: server.pl
:- module(server,[]).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/websocket)).
:- initialization
http_server(http_dispatch, [port(8000)]).
:- http_handler(root(.), http_reply_file('index.html', []), []).
:- http_handler(root('time.js'), http_reply_file('time.js', []), []).
:- http_handler(root(time),
http_upgrade_to_websocket(time_handler, []),
[spawn([])]).
time_handler(WebSocket) :-
ws_receive(WebSocket, Message, [format(json)]), % This waits until a message is received.
(
Message.opcode == close
->
true
;
time_response(Response_dict),
ws_send(WebSocket, json(Response_dict)),
time_handler(WebSocket)
).
time_response(Response_dict) :-
get_time(Time),
format_time(string(Message), '%c', Time),
dict_create(Data, _, [message-Message]),
dict_create(Response_dict, _, [data-Data,format-json,opcode-text]).
File: index.html
<!DOCTYPE html>
<html>
<head>
<title>Web Socket Example</title>
<script charset="utf-8" src="time.js"></script>
</head>
<body>
<h2>Current Time</h2>
<p id="time"> </p>
<button id="message-submit" type="button">Get current time</button>
</body>
</html>
File: time.js
// Called when page loads
document.addEventListener('DOMContentLoaded', (e) => {
const input_button = document.getElementById("message-submit")
const connection = openWebSocket()
input_button.addEventListener("click", (event) => {
connection.send(JSON.stringify(""))
})
})
// Called by addEventListener to get the connection when page loads
function openWebSocket() {
connection = new WebSocket("ws://" + window.location.host + "/time")
connection.onerror = (error) => {
console.log(error)
}
connection.onmessage = wsMessageHandler
return connection
}
// Called when Web Socket message arrives.
function wsMessageHandler(event) {
const payload = JSON.parse(event.data)
const message = payload.data.message
document.getElementById("time").innerHTML = message
}
Example run
Using SWI-Prolog
Welcome to SWI-Prolog (threaded, 64 bits, version 9.1.6)
...
?- working_directory(_,'C:/Users/Groot)').
true.
?- [server].
% Started server at http://localhost:8000/
true.
?-
then using an Internet browser
The page will load looking like this
click Get current time
will update the time and look like this
Prompt
Explain code to a programmer new to Prolog, HTML and JavaScript.
Note: All of the code above was included in the prompt
ChatGPT Completion
This code sets up a simple web socket server that responds to requests for the current time.
The
server.pl
module sets up the server using thehttp_server
predicate from thehttp/thread_httpd
library. It also registers several handlers for different URLs.The handler for the root URL (
/
) responds with theindex.html
file, which contains a button and a placeholder for the current time.The handler for the
/time
URL upgrades the connection to a web socket and passes it to thetime_handler
predicate. This predicate waits for a message from the web socket and then responds with the current time in a JSON format. It then waits for another message and repeats the process.The
index.html
file contains a script (time.js
) that sets up an event listener on the button. When the button is clicked, it sends an empty JSON message to the web socket connection.The script also defines two functions (
openWebSocket
andwsMessageHandler
) that handle the web socket connection.openWebSocket
sets up the connection and registers a message handler.wsMessageHandler
extracts the time from the JSON payload and updates the placeholder in the HTML file.Overall, this code demonstrates a simple example of a web socket server and client that communicate using JSON messages.
For more basic examples of working code see
If you know web sockets you will notice that this is not demonstrating an automatic push of data to the page. That can be easily be done but that makes the very basic example a bit more complicated and picks a specific use case so was not done.
Note: You may find it difficult to get ChatGPT to generate such an example as it struggles with certain parts of SWI-Prolog. The lack of examples for certain modules and predicates means that ChatGPT often hallucinates to get a completion which can be incorrect. However, if you are a skilled Prolog programmer, you can work out the kinks. The prompt can became so detailed in instructions that it was not worth using ChatGPT.
Enjoy