Interfacing with Angular

Agree. Websockets have benefits especially when server push is required or to reduce latency. They also come at a price. It is an open connection that easily breaks on some network issue and requires support in proxy servers. That is more readily available these days, but still not always guaranteed :frowning:

A good use case is probably using a browser as GUI for an application on the same host or in a LAN, so connection issues are irrelevant and latency really goes down to the sub-millisec range.

I’m a bit lost here. Do I simply add this library to the list as in

and then simply shorten the command to start the server to

swipl server.pl --port=6455 --pidfile=http.pid

or do I need to add anything else to the Prolog script?

That is just fine. The http_server.pl library loads a reasonable part of the server architecture that just about any server needs. This avoid having to remember all the basic server libraries. Add what is missing (in this case websockets and the Unix daemon infrastructure) and you’re ready to go.

1 Like

After several hours of trying to get wss:// and nginx to play nicely, I’ve conceded defeat and got JavaScript in the browser and SWI Prolog server to communicate via JSON like so:

:- use_module(library(http/http_server)).
:- use_module(library(http/http_files)).
:- use_module(library(http/http_unix_daemon)).

:- initialization http_daemon.

:- http_handler(root(.), http_reply_from_files('.', [indexes(['./index.html'])]), [prefix]).
:- http_handler(root(prolog), prolog_handler, []).

prolog_handler(Request) :-
  http_read_json_dict(Request, DictIn),
  request_handler(DictIn.request, DictIn, DictOut),
  reply_json_dict(DictOut).

request_handler("ping", _Dict, json{reply: pong}).

Browser code:

function prologServer(Request) {
  return fetch("prolog",
  { method: "POST"
  , headers: { "Content-Type": "application/json"}
  , body: JSON.stringify(Request)
  }
);
}

prologServer({"request": "ping"})
.then(response => response.json())
.then(data => document.querySelector("#message").innerText = data.reply);

The next interesting question is how to format the Json values so that Prolog and Javascript can use it as a lingua franca.

Using the introductory example from Bratko as an example by initial thought is if the Prolog looks like:

parent(pam, bob).
parent(tom, bob).
parent(tom, liz).
parent(bob, pat).
parent(pat, jim).

Then the Json should be

[ ["parent", "pam", "bob"],
  ["parent", "tom",  "bob"],
  ["parent", "tom", "liz"],
  ["parent", "bob", "pat"],
  ["parent", "pat", "jim"]
]

which the Prolog script could then iteratively translate with term_string (?Term, ?String) and then Term =.. List to translate, and then do the reverse in the reply to the browser.

Though not difficult, I wondered if there’s already a convention and libraries to do this?

Not sure if it covers all your need, but check out this library:

https://www.swi-prolog.org/pldoc/man?section=termtojson

1 Like

Thanks @torbjorn.lager

I managed to get what I wanted:

?- json_prolog([["parent", "pam", "bob"],["parent", "tom", "bob"],["parent", "tom", "liz"], ["parent", "bob", "pat"],["parent", "pat", "jim"]], Terms).
Terms = [parent(pam, bob), parent(tom, bob), parent(tom, liz), parent(bob, pat), parent(pat, jim)].

?- json_prolog(L, [parent(pam, bob), parent(tom, bob), parent(tom, liz), parent(bob, pat), parent(pat, jim)]).
L = [["parent", "pam", "bob"], ["parent", "tom", "bob"], ["parent", "tom", "liz"], ["parent", "bob", "pat"], ["parent", "pat", "jim"]].

With the little module below. Making this bidirectional was a bit of a hack, but it works. I might need to make it more elaborate to handle nested lists/compounds, but this is all I need for now:

:- module(json_prolog, [json_prolog/2]).

unquote_quote(Unquoted, Quoted) :-
  maplist(term_string, Unquoted, Quoted).

json_prolog(QLists, PrologList) :-
  nonvar(QLists), var(PrologList), !,
  maplist(unquote_quote, UQLists, QLists),
  maplist(=.., PrologList, UQLists).

json_prolog(QLists, PrologList) :-
  var(QLists), nonvar(PrologList), !,
  maplist(=.., PrologList, UQLists),
  maplist(unquote_quote, UQLists, QLists).
1 Like

I have some code that uses “bare” JavaScript (using WindowOrWorkerGlobalScope.fetch()) and a simple Prolog server using http_handler and http_read_json_dict. If anyone is interested, I can excerpt a simple code example (it’ll take me a few hours; but the code needs some refactoring anyway).

It would be nice to have a simple self-contained example code for that.

If you find the time to do it, I would be interested to look at a minimum viable example with comments to explain what does what and where to put our own business code. Thanks for offering !

Was the problem wss and ws would have worked?

Well I just ask my question…

As I understand it, SWI cant yet “serve” secure websockets. (at least not without a webproxy)
But I am trying to talk to a external server using SWI-Prolog… That external server requires wss… Can someone confirm that we can talk to secure websockets just fine?

It can. There is nothing special about it. Just do the usual https server and use the same websocket code as you use for http. SWISH does it :slight_smile:

You meant what we do to serve wss from SWISH over Nginx? (Swish serving http and ws… while Nginx converts to https and wss?)

Btw, I remember some people having trouble getting apache2 to proxy the WebSocket for SWISH (yet Nginx works fine) … … the other day I got apache2 to work… The trick was moving jus the chat part of SWISH to a subdomain and then proxy only the websocket on its own subdomain ( this only applies to the chat portion of swish… everything else works fine)

Actually what i am up to is I trying to connect SWI-Prolog to wss://gateway.discord.gg/ … though I think what you saying is set up the ngynx proxy to proxy for gateway.discord.gg . I’ll give that try

Not only. SWISH happily runs using https/wss natively. Yes, the central server uses http/ws and an nginx proxy as that is all the server can support. The server has a central nginx server which proxies requests to LXC containers based on virtual host identifiers.

Isn’t that the client side of wss? I suppose that should work too. Not sure I ever used it.

​Aha, good! I was almost sure reading that SWISH has native SSL support but not configured my servers to try it yet. (out of habit​, ​I still run SWISH on a daily basis behind a https/wss proxy)

Correct, my use case right now has only to do with the client side. I been trying to troubleshoot why my ​client ​code could understand the socket servers messages just fine but ​yet ​the server is ​not ​understanding my clients ​side’s websocket messages … A few hours into troubleshooting I thought “it be funny if the trouble ​all along was SWI’s secretly ​only ​using ws:// client (not wss:// client​)”… So I needed a sanity check that ​ ​​w​ss​ was ​work​ing​ and should continue troubleshooting my code.

(ps. I asked about the server because if there was a difference in the time between when SWI’s Non-SSL worked versus when its natively was supporting Server SSL was different . thus indicate a multipart timeline of development for when to expect websockets client and/or server being able to do SSL)

Is the problem connecting using wss? I’ve had trouble with that as well in the past. Some servers (and clients) are pretty picky about the headers exchanged during the connect phase. Sometimes they ask more than what is required by the standard. Try to find a working client/server couple, sniff into the communication and compare this with the failing attempt …

@logicmoo @jan

Should we move the replies related to ws and wss to a new topic?