I’m trying to put together a simple test-case for library(hub)
, but I can’t seem to have messages be sent back-and-forth as expected.
My code looks as follows:
:- http_handler(root(ws),
http_upgrade_to_websocket(handle_websocket, []),
[spawn([])]).
handle_websocket(WebSocket) :-
debug(server(websocket), "Connection incoming ~w", [WebSocket]),
hub_add(hotwire_hub, WebSocket, Id),
debug(server(websocket), "Added ~w", [Id]).
get_or_create_socket_hub(Hub) :-
current_hub(hotwire_hub, Hub)
-> true
; hub_create(hotwire_hub, Hub, []).
:- dynamic socket_hub_thread/1.
start_socket_hub :-
get_or_create_socket_hub(Hub),
debug(server(websocket), "Creating hub ~w", [Hub]),
( socket_hub_thread(_) -> stop_socket_hub ; true ),
thread_create(socket_hub_listener(Hub), SocketListenerId, []),
assertz(socket_hub_thread(SocketListenerId)).
stop_socket_hub :-
socket_hub_thread(ThreadId),
thread_send_message(ThreadId, done),
thread_join(ThreadId),
retractall(socket_hub_thread(ThreadId)).
socket_hub_listener(_Hub) :-
thread_self(Self),
thread_get_message(Self, done, [timeout(0)]),
debug(server(websocket), "Stopping socket hub", []),
!. % done
socket_hub_listener(Hub) :-
( thread_get_message(Hub.queues.event, Msg, [timeout(0.1)])
-> handle_hub_event(Msg) ; true ),
socket_hub_listener(Hub).
handle_hub_event(Msg) :-
hub{error: Error} :< Msg,
debug(server(websocket), "Hub error: ~w", [Error]).
handle_hub_event(Msg) :-
hub{joined: Id} :< Msg,
debug(server(websocket), "Hub new connection: ~w", [Id]),
hub_send(Id, text("Hello!")),
debug(server(websocket), "Sent message to new", []).
handle_hub_event(Msg) :-
debug(server(websocket), "Got Message ~k", [Msg]).
After starting the webserver and the socket listening thread, I open a page that includes the following javascript:
const createSocket = () => {
const proto = window.location.protocol === "https:" ? "wss" : "ws";
const socket = new WebSocket(`${proto}://${window.location.host}/ws`);
window.test_socket = socket;
socket.addEventListener('open', (event) => {
console.log("Socket open");
});
socket.addEventListener('message', (event) => {
console.log("Socket Message: ${event.data}");
});
socket.addEventListener('error', (event) => {
console.log("Socket error", event);
});
window.addEventListener('beforeunload', () => {
console.log("page unloading");
socket.close();
});
};
createSocket();
On the client side, I see it log the “socket open” message. On the server side, I see the following:
% [Thread 15] 2023-02-19 21:34:24 Connection incoming <stream>(0x6000037ccc00,0x6000037ccd00)
% [Thread 15] 2023-02-19 21:34:24 Added 16fd0bd8-b0c7-11ed-9cc2-7b5f40bf6966
% [Thread 12] 2023-02-19 21:34:24 Hub new connection: 16fd0bd8-b0c7-11ed-9cc2-7b5f40bf6966
% [Thread 12] 2023-02-19 21:34:24 Sent message to new
% [Thread hub_out_q_4] 2023-02-19 21:34:24 To: <stream>(0x6000037ccc00,0x6000037ccd00) messages: text("Hello!")
% [Thread 12] 2023-02-19 21:34:24 Hub error: error(existence_error(stream,<stream>(0x6000037ccc00,0x6000037ccd00)),context(websocket:ws_start_message/3,_2700))
No matter what I’ve tried (hub_broadcast/2, hub_send/2), attempting to send from the server to the client gives this error (existence_error
for the client stream) and sending from the client to the server gives nothing.
Is there some step I’m missing in the handler to keep the streams open or some such?